2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "utils/BitstreamStats.h"
22 #include "PlayerCoreFactory.h"
23 #include "threads/SingleLock.h"
24 #include "cores/AudioEngine/Utils/AEUtil.h"
25 #include "cores/dvdplayer/DVDPlayer.h"
26 #include "cores/paplayer/PAPlayer.h"
27 #include "cores/paplayer/DVDPlayerCodec.h"
28 #include "dialogs/GUIDialogContextMenu.h"
29 #include "utils/HttpHeader.h"
30 #include "settings/Settings.h"
33 #include "profiles/ProfilesManager.h"
34 #include "settings/AdvancedSettings.h"
35 #include "utils/AutoPtrHandle.h"
36 #include "cores/ExternalPlayer/ExternalPlayer.h"
37 #include "PlayerCoreConfig.h"
38 #include "PlayerSelectionRule.h"
39 #include "guilib/LocalizeStrings.h"
41 #define PLAYERCOREFACTORY_XML "playercorefactory.xml"
43 using namespace AUTOPTR;
45 CPlayerCoreFactory::CPlayerCoreFactory()
48 CPlayerCoreFactory::~CPlayerCoreFactory()
50 for(std::vector<CPlayerCoreConfig *>::iterator it = m_vecCoreConfigs.begin(); it != m_vecCoreConfigs.end(); ++it)
52 for(std::vector<CPlayerSelectionRule *>::iterator it = m_vecCoreSelectionRules.begin(); it != m_vecCoreSelectionRules.end(); ++it)
56 CPlayerCoreFactory& CPlayerCoreFactory::Get()
58 static CPlayerCoreFactory sPlayerCoreFactory;
59 return sPlayerCoreFactory;
62 void CPlayerCoreFactory::OnSettingsLoaded()
64 LoadConfiguration("special://xbmc/system/" PLAYERCOREFACTORY_XML, true);
65 LoadConfiguration(CProfilesManager::Get().GetUserDataItem(PLAYERCOREFACTORY_XML), false);
68 /* generic function to make a vector unique, removes later duplicates */
69 template<typename T> void unique (T &con)
71 typename T::iterator cur, end;
76 typename T::value_type i = *cur;
77 end = remove (++cur, end, i);
79 con.erase (end, con.end());
82 IPlayer* CPlayerCoreFactory::CreatePlayer(const CStdString& strCore, IPlayerCallback& callback) const
84 return CreatePlayer(GetPlayerCore(strCore), callback );
87 IPlayer* CPlayerCoreFactory::CreatePlayer(const PLAYERCOREID eCore, IPlayerCallback& callback) const
89 CSingleLock lock(m_section);
90 if (m_vecCoreConfigs.empty() || eCore-1 > m_vecCoreConfigs.size()-1)
93 return m_vecCoreConfigs[eCore-1]->CreatePlayer(callback);
96 PLAYERCOREID CPlayerCoreFactory::GetPlayerCore(const CStdString& strCoreName) const
98 CSingleLock lock(m_section);
99 if (!strCoreName.empty())
101 // Dereference "*default*player" aliases
102 CStdString strRealCoreName;
103 if (strCoreName.Equals("audiodefaultplayer", false)) strRealCoreName = g_advancedSettings.m_audioDefaultPlayer;
104 else if (strCoreName.Equals("videodefaultplayer", false)) strRealCoreName = g_advancedSettings.m_videoDefaultPlayer;
105 else if (strCoreName.Equals("videodefaultdvdplayer", false)) strRealCoreName = g_advancedSettings.m_videoDefaultDVDPlayer;
106 else strRealCoreName = strCoreName;
108 for(PLAYERCOREID i = 0; i < m_vecCoreConfigs.size(); i++)
110 if (m_vecCoreConfigs[i]->GetName().Equals(strRealCoreName, false))
113 CLog::Log(LOGWARNING, "CPlayerCoreFactory::GetPlayerCore(%s): no such core: %s", strCoreName.c_str(), strRealCoreName.c_str());
118 CStdString CPlayerCoreFactory::GetPlayerName(const PLAYERCOREID eCore) const
120 CSingleLock lock(m_section);
121 return m_vecCoreConfigs[eCore-1]->GetName();
124 CPlayerCoreConfig* CPlayerCoreFactory::GetPlayerConfig(const CStdString& strCoreName) const
126 CSingleLock lock(m_section);
127 PLAYERCOREID id = GetPlayerCore(strCoreName);
128 if (id != EPC_NONE) return m_vecCoreConfigs[id-1];
132 void CPlayerCoreFactory::GetPlayers( VECPLAYERCORES &vecCores ) const
134 CSingleLock lock(m_section);
135 for(unsigned int i = 0; i < m_vecCoreConfigs.size(); i++)
137 if(m_vecCoreConfigs[i]->m_eCore == EPC_NONE)
139 if (m_vecCoreConfigs[i]->m_bPlaysAudio || m_vecCoreConfigs[i]->m_bPlaysVideo)
140 vecCores.push_back(i+1);
144 void CPlayerCoreFactory::GetPlayers( VECPLAYERCORES &vecCores, const bool audio, const bool video ) const
146 CSingleLock lock(m_section);
147 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: for video=%d, audio=%d", video, audio);
149 for(unsigned int i = 0; i < m_vecCoreConfigs.size(); i++)
151 if(m_vecCoreConfigs[i]->m_eCore == EPC_NONE)
153 if (audio == m_vecCoreConfigs[i]->m_bPlaysAudio && video == m_vecCoreConfigs[i]->m_bPlaysVideo)
155 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding player: %s (%d)", m_vecCoreConfigs[i]->m_name.c_str(), i+1);
156 vecCores.push_back(i+1);
161 void CPlayerCoreFactory::GetPlayers( const CFileItem& item, VECPLAYERCORES &vecCores) const
163 CURL url(item.GetPath());
165 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers(%s)", item.GetPath().c_str());
168 for(unsigned int i = 0; i < m_vecCoreSelectionRules.size(); i++)
169 m_vecCoreSelectionRules[i]->GetPlayers(item, vecCores);
171 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: matched %"PRIuS" rules with players", vecCores.size());
173 if( PAPlayer::HandlesType(url.GetFileType()) )
175 // We no longer force PAPlayer as our default audio player (used to be true):
177 if (url.GetProtocol().Equals("mms"))
181 else if (item.IsType(".wma"))
184 // DVDPlayerCodec codec;
185 // if (!codec.Init(item.GetPath(),2048))
192 if( CSettings::Get().GetInt("audiooutput.mode") == AUDIO_ANALOG )
194 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding PAPlayer (%d)", EPC_PAPLAYER);
195 vecCores.push_back(EPC_PAPLAYER);
197 else if (url.GetFileType().Equals("ac3")
198 || url.GetFileType().Equals("dts"))
200 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding DVDPlayer (%d)", EPC_DVDPLAYER);
201 vecCores.push_back(EPC_DVDPLAYER);
205 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding PAPlayer (%d)", EPC_PAPLAYER);
206 vecCores.push_back(EPC_PAPLAYER);
213 // Set video default player. Check whether it's video first (overrule audio check)
214 // Also push these players in case it is NOT audio either
215 if (item.IsVideo() || !item.IsAudio())
217 PLAYERCOREID eVideoDefault = GetPlayerCore("videodefaultplayer");
218 if (eVideoDefault != EPC_NONE)
220 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding videodefaultplayer (%d)", eVideoDefault);
221 vecCores.push_back(eVideoDefault);
223 GetPlayers(vecCores, false, true); // Video-only players
224 GetPlayers(vecCores, true, true); // Audio & video players
227 // Set audio default player
228 // Pushback all audio players in case we don't know the type
231 PLAYERCOREID eAudioDefault = GetPlayerCore("audiodefaultplayer");
232 if (eAudioDefault != EPC_NONE)
234 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding audiodefaultplayer (%d)", eAudioDefault);
235 vecCores.push_back(eAudioDefault);
237 GetPlayers(vecCores, true, false); // Audio-only players
238 GetPlayers(vecCores, true, true); // Audio & video players
241 /* make our list unique, preserving first added players */
244 CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: added %"PRIuS" players", vecCores.size());
247 void CPlayerCoreFactory::GetRemotePlayers( VECPLAYERCORES &vecCores ) const
249 CSingleLock lock(m_section);
250 for(unsigned int i = 0; i < m_vecCoreConfigs.size(); i++)
252 if(m_vecCoreConfigs[i]->m_eCore != EPC_UPNPPLAYER)
254 vecCores.push_back(i+1);
258 PLAYERCOREID CPlayerCoreFactory::GetDefaultPlayer( const CFileItem& item ) const
260 VECPLAYERCORES vecCores;
261 GetPlayers(item, vecCores);
263 //If we have any players return the first one
264 if( !vecCores.empty() ) return vecCores.at(0);
269 PLAYERCOREID CPlayerCoreFactory::SelectPlayerDialog(VECPLAYERCORES &vecCores, float posX, float posY) const
271 CContextButtons choices;
275 CStdString strCaption = CPlayerCoreFactory::GetPlayerName(vecCores[0]);
277 strCaption += g_localizeStrings.Get(13278);
279 choices.Add(0, strCaption);
281 //Add all other players
282 for( unsigned int i = 1; i < vecCores.size(); i++ )
283 choices.Add(i, CPlayerCoreFactory::GetPlayerName(vecCores[i]));
285 int choice = CGUIDialogContextMenu::ShowAndGetChoice(choices);
287 return vecCores[choice];
292 PLAYERCOREID CPlayerCoreFactory::SelectPlayerDialog(float posX, float posY) const
294 VECPLAYERCORES vecCores;
295 GetPlayers(vecCores);
296 return SelectPlayerDialog(vecCores, posX, posY);
299 bool CPlayerCoreFactory::LoadConfiguration(const std::string &file, bool clear)
301 CSingleLock lock(m_section);
303 CLog::Log(LOGNOTICE, "Loading player core factory settings from %s.", file.c_str());
304 if (!XFILE::CFile::Exists(file))
305 { // tell the user it doesn't exist
306 CLog::Log(LOGNOTICE, "%s does not exist. Skipping.", file.c_str());
310 CXBMCTinyXML playerCoreFactoryXML;
311 if (!playerCoreFactoryXML.LoadFile(file))
313 CLog::Log(LOGERROR, "Error loading %s, Line %d (%s)", file.c_str(), playerCoreFactoryXML.ErrorRow(), playerCoreFactoryXML.ErrorDesc());
317 TiXmlElement *pConfig = playerCoreFactoryXML.RootElement();
320 CLog::Log(LOGERROR, "Error loading %s, Bad structure", file.c_str());
326 for(std::vector<CPlayerCoreConfig *>::iterator it = m_vecCoreConfigs.begin(); it != m_vecCoreConfigs.end(); ++it)
328 m_vecCoreConfigs.clear();
329 // Builtin players; hard-coded because re-ordering them would break scripts
330 CPlayerCoreConfig* dvdplayer = new CPlayerCoreConfig("DVDPlayer", EPC_DVDPLAYER, NULL);
331 dvdplayer->m_bPlaysAudio = dvdplayer->m_bPlaysVideo = true;
332 m_vecCoreConfigs.push_back(dvdplayer);
334 // Don't remove this, its a placeholder for the old MPlayer core, it would break scripts
335 CPlayerCoreConfig* mplayer = new CPlayerCoreConfig("oldmplayercore", EPC_DVDPLAYER, NULL);
336 m_vecCoreConfigs.push_back(mplayer);
338 CPlayerCoreConfig* paplayer = new CPlayerCoreConfig("PAPlayer", EPC_PAPLAYER, NULL);
339 paplayer->m_bPlaysAudio = true;
340 m_vecCoreConfigs.push_back(paplayer);
342 #if defined(HAS_AMLPLAYER)
343 CPlayerCoreConfig* amlplayer = new CPlayerCoreConfig("AMLPlayer", EPC_AMLPLAYER, NULL);
344 amlplayer->m_bPlaysAudio = true;
345 amlplayer->m_bPlaysVideo = true;
346 m_vecCoreConfigs.push_back(amlplayer);
349 #if defined(HAS_OMXPLAYER)
350 CPlayerCoreConfig* omxplayer = new CPlayerCoreConfig("OMXPlayer", EPC_OMXPLAYER, NULL);
351 omxplayer->m_bPlaysAudio = true;
352 omxplayer->m_bPlaysVideo = true;
353 m_vecCoreConfigs.push_back(omxplayer);
356 for(std::vector<CPlayerSelectionRule *>::iterator it = m_vecCoreSelectionRules.begin(); it != m_vecCoreSelectionRules.end(); ++it)
358 m_vecCoreSelectionRules.clear();
361 if (!pConfig || strcmpi(pConfig->Value(),"playercorefactory") != 0)
363 CLog::Log(LOGERROR, "Error loading configuration, no <playercorefactory> node");
367 TiXmlElement *pPlayers = pConfig->FirstChildElement("players");
370 TiXmlElement* pPlayer = pPlayers->FirstChildElement("player");
373 CStdString name = pPlayer->Attribute("name");
374 CStdString type = pPlayer->Attribute("type");
375 if (type.length() == 0) type = name;
378 EPLAYERCORES eCore = EPC_NONE;
379 if (type == "dvdplayer" || type == "mplayer") eCore = EPC_DVDPLAYER;
380 if (type == "paplayer" ) eCore = EPC_PAPLAYER;
381 if (type == "externalplayer" ) eCore = EPC_EXTPLAYER;
383 if (eCore != EPC_NONE)
385 m_vecCoreConfigs.push_back(new CPlayerCoreConfig(name, eCore, pPlayer));
388 pPlayer = pPlayer->NextSiblingElement("player");
392 TiXmlElement *pRule = pConfig->FirstChildElement("rules");
395 const char* szAction = pRule->Attribute("action");
398 if (stricmp(szAction, "append") == 0)
400 m_vecCoreSelectionRules.push_back(new CPlayerSelectionRule(pRule));
402 else if (stricmp(szAction, "prepend") == 0)
404 m_vecCoreSelectionRules.insert(m_vecCoreSelectionRules.begin(), 1, new CPlayerSelectionRule(pRule));
408 m_vecCoreSelectionRules.clear();
409 m_vecCoreSelectionRules.push_back(new CPlayerSelectionRule(pRule));
414 m_vecCoreSelectionRules.push_back(new CPlayerSelectionRule(pRule));
417 pRule = pRule->NextSiblingElement("rules");
420 // succeeded - tell the user it worked
421 CLog::Log(LOGNOTICE, "Loaded playercorefactory configuration");
426 void CPlayerCoreFactory::OnPlayerDiscovered(const CStdString& id, const CStdString& name, EPLAYERCORES core)
428 CSingleLock lock(m_section);
429 std::vector<CPlayerCoreConfig *>::iterator it;
430 for(it = m_vecCoreConfigs.begin();
431 it != m_vecCoreConfigs.end();
434 if ((*it)->GetId() == id)
436 (*it)->m_name = name;
437 (*it)->m_eCore = core;
442 CPlayerCoreConfig* player = new CPlayerCoreConfig(name, core, NULL, id);
443 player->m_bPlaysAudio = true;
444 player->m_bPlaysVideo = true;
445 m_vecCoreConfigs.push_back(player);
448 void CPlayerCoreFactory::OnPlayerRemoved(const CStdString& id)
450 CSingleLock lock(m_section);
451 std::vector<CPlayerCoreConfig *>::iterator it;
452 for(it = m_vecCoreConfigs.begin();
453 it != m_vecCoreConfigs.end();
456 if ((*it)->GetId() == id)
457 (*it)->m_eCore = EPC_NONE;