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/>.
26 #include "Application.h"
27 #include "GUIPassword.h"
28 #include "GUIUserMessages.h"
29 #include "PlayListPlayer.h"
30 #include "filesystem/StackDirectory.h"
31 #include "filesystem/Directory.h"
32 #include "filesystem/DirectoryFactory.h"
33 #include "filesystem/File.h"
34 #include "profiles/ProfilesManager.h"
35 #include "settings/Settings.h"
36 #include "playlists/PlayList.h"
37 #include "guilib/GUIWindowManager.h"
38 #include "guilib/LocalizeStrings.h"
39 #include "storage/MediaManager.h"
40 #include "video/VideoDatabase.h"
41 #include "dialogs/GUIDialogYesNo.h"
42 #include "utils/URIUtils.h"
43 #include "utils/log.h"
44 #ifdef HAS_CDDA_RIPPER
45 #include "cdrip/CDDARipper.h"
49 using namespace XFILE;
50 using namespace PLAYLIST;
51 using namespace MEDIA_DETECT;
61 void CAutorun::ExecuteAutorun(const CStdString& path, bool bypassSettings, bool ignoreplaying, bool startFromBeginning )
63 if ((!ignoreplaying && (g_application.m_pPlayer->IsPlayingAudio() || g_application.m_pPlayer->IsPlayingVideo() || g_windowManager.HasModalDialog())) || g_windowManager.GetActiveWindow() == WINDOW_LOGIN_SCREEN)
66 CCdInfo* pInfo = g_mediaManager.GetCdInfo(path);
71 g_application.ResetScreenSaver();
72 g_application.WakeUpScreenSaverAndDPMS(); // turn off the screensaver if it's active
73 #ifdef HAS_CDDA_RIPPER
74 if (CSettings::Get().GetInt("audiocds.autoaction") == AUTOCD_RIP &&
75 pInfo->IsAudio(1) && !CProfilesManager::Get().GetCurrentProfile().musicLocked())
77 CCDDARipper::GetInstance().RipCD();
81 PlayDisc(path, bypassSettings, startFromBeginning);
84 bool CAutorun::PlayDisc(const CStdString& path, bool bypassSettings, bool startFromBeginning)
86 if ( !bypassSettings && CSettings::Get().GetInt("audiocds.autoaction") != AUTOCD_PLAY && !CSettings::Get().GetBool("dvds.autorun"))
89 int nSize = g_playlistPlayer.GetPlaylist( PLAYLIST_MUSIC ).size();
90 int nAddedToPlaylist = 0;
94 CCdInfo* pInfo = g_mediaManager.GetCdInfo(path);
98 if (mediaPath.empty() && pInfo->IsAudio(1))
99 mediaPath = "cdda://local/";
101 if (mediaPath.empty() && (pInfo->IsISOUDF(1) || pInfo->IsISOHFS(1) || pInfo->IsIso9660(1) || pInfo->IsIso9660Interactive(1)))
102 mediaPath = "iso9660://";
104 if (mediaPath.empty())
107 #ifdef TARGET_WINDOWS
108 if (mediaPath.empty() || mediaPath == "iso9660://")
109 mediaPath = g_mediaManager.TranslateDevicePath("");
112 auto_ptr<IDirectory> pDir ( CDirectoryFactory::Create( mediaPath ));
113 bool bPlaying = RunDisc(pDir.get(), mediaPath, nAddedToPlaylist, true, bypassSettings, startFromBeginning);
115 if ( !bPlaying && nAddedToPlaylist > 0 )
117 CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
118 g_windowManager.SendMessage( msg );
119 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_MUSIC);
120 // Start playing the items we inserted
121 return g_playlistPlayer.Play(nSize);
128 * This method tries to determine what type of disc is located in the given drive and starts to play the content appropriately.
130 bool CAutorun::RunDisc(IDirectory* pDir, const CStdString& strDrive, int& nAddedToPlaylist, bool bRoot, bool bypassSettings /* = false */, bool startFromBeginning /* = false */)
132 bool bPlaying(false);
133 CFileItemList vecItems;
135 if ( !pDir->GetDirectory( strDrive, vecItems ) )
140 // Sorting necessary for easier HDDVD handling
141 vecItems.Sort(SortByLabel, SortOrderAscending);
143 bool bAllowVideo = true;
144 // bool bAllowPictures = true;
145 bool bAllowMusic = true;
146 if (!g_passwordManager.IsMasterLockUnlocked(false))
148 bAllowVideo = !CProfilesManager::Get().GetCurrentProfile().videoLocked();
149 // bAllowPictures = !CProfilesManager::Get().GetCurrentProfile().picturesLocked();
150 bAllowMusic = !CProfilesManager::Get().GetCurrentProfile().musicLocked();
153 // is this a root folder we have to check the content to determine a disc type
156 CStdString hddvdname = "";
157 CFileItemPtr phddvdItem;
159 // check root folders next, for normal structured dvd's
160 for (int i = 0; i < vecItems.Size(); i++)
162 CFileItemPtr pItem = vecItems[i];
164 // is the current item a (non system) folder?
165 if (pItem->m_bIsFolder && pItem->GetPath() != "." && pItem->GetPath() != "..")
167 CStdString name = pItem->GetPath();
168 URIUtils::RemoveSlashAtEnd(name);
169 name = URIUtils::GetFileName(name);
171 // Check if the current foldername indicates a DVD structure (name is "VIDEO_TS")
172 if (name.Equals("VIDEO_TS") && bAllowVideo
173 && (bypassSettings || CSettings::Get().GetBool("dvds.autorun")))
175 CStdString path = URIUtils::AddFileToFolder(pItem->GetPath(), "VIDEO_TS.IFO");
176 if(!CFile::Exists(path))
177 path = URIUtils::AddFileToFolder(pItem->GetPath(), "video_ts.ifo");
178 CFileItemPtr item(new CFileItem(path, false));
179 item->SetLabel(g_mediaManager.GetDiskLabel(strDrive));
180 item->GetVideoInfoTag()->m_strFileNameAndPath = g_mediaManager.GetDiskUniqueId(strDrive);
182 if (!startFromBeginning && !item->GetVideoInfoTag()->m_strFileNameAndPath.empty())
183 item->m_lStartOffset = STARTOFFSET_RESUME;
185 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
186 g_playlistPlayer.SetShuffle (PLAYLIST_VIDEO, false);
187 g_playlistPlayer.Add(PLAYLIST_VIDEO, item);
188 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
189 g_playlistPlayer.Play(0);
193 // Check if the current foldername indicates a Blu-Ray structure (default is "BDMV").
194 // A BR should also include an "AACS" folder for encryption, Sony-BRs can also include update folders for PS3 (PS3_UPDATE / PS3_VPRM).
195 // ToDo: for the time beeing, the DVD autorun settings are used to determine if the BR should be started automatically.
196 if (name.Equals("BDMV") && bAllowVideo
197 && (bypassSettings || CSettings::Get().GetBool("dvds.autorun")))
199 CFileItemPtr item(new CFileItem(URIUtils::AddFileToFolder(pItem->GetPath(), "index.bdmv"), false));
200 item->SetLabel(g_mediaManager.GetDiskLabel(strDrive));
201 item->GetVideoInfoTag()->m_strFileNameAndPath = g_mediaManager.GetDiskUniqueId(strDrive);
203 if (!startFromBeginning && !item->GetVideoInfoTag()->m_strFileNameAndPath.empty())
204 item->m_lStartOffset = STARTOFFSET_RESUME;
206 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
207 g_playlistPlayer.SetShuffle (PLAYLIST_VIDEO, false);
208 g_playlistPlayer.Add(PLAYLIST_VIDEO, item);
209 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
210 g_playlistPlayer.Play(0);
214 // Check if the current foldername indicates a HD DVD structure (default is "HVDVD_TS").
215 // Most HD DVD will also include an "ADV_OBJ" folder for advanced content. This folder should be handled first.
216 // ToDo: for the time beeing, the DVD autorun settings are used to determine if the HD DVD should be started automatically.
217 CFileItemList items, sitems;
219 // Advanced Content HD DVD (most discs?)
220 if (name.Equals("ADV_OBJ"))
222 CLog::Log(LOGINFO,"HD DVD: Checking for playlist.");
223 // find playlist file
224 CDirectory::GetDirectory(pItem->GetPath(), items, "*.xpl");
227 // HD DVD Standard says the highest numbered playlist has to be handled first.
228 CLog::Log(LOGINFO,"HD DVD: Playlist found. Set filetypes to *.xpl for external player.");
229 items.Sort(SortByLabel, SortOrderDescending);
231 hddvdname = URIUtils::GetFileName(items[0]->GetPath());
232 CLog::Log(LOGINFO,"HD DVD: %s", items[0]->GetPath().c_str());
236 // Standard Content HD DVD (few discs?)
237 if (name.Equals("HVDVD_TS") && bAllowVideo
238 && (bypassSettings || CSettings::Get().GetBool("dvds.autorun")))
242 CLog::Log(LOGINFO,"HD DVD: Checking for ifo.");
243 // find Video Manager or Title Set Information
244 CDirectory::GetDirectory(pItem->GetPath(), items, "HV*.ifo");
247 // HD DVD Standard says the lowest numbered ifo has to be handled first.
248 CLog::Log(LOGINFO,"HD DVD: IFO found. Set filename to HV* and filetypes to *.ifo for external player.");
249 items.Sort(SortByLabel, SortOrderAscending);
251 hddvdname = URIUtils::GetFileName(items[0]->GetPath());
252 CLog::Log(LOGINFO,"HD DVD: %s",items[0]->GetPath().c_str());
255 // Find and sort *.evo files for internal playback.
256 // While this algorithm works for all of my HD DVDs, it may fail on other discs. If there are very large extras which are
257 // alphabetically before the main movie they will be sorted to the top of the playlist and get played first.
258 CDirectory::GetDirectory(pItem->GetPath(), items, "*.evo");
261 // Sort *.evo files in alphabetical order.
262 items.Sort(SortByLabel, SortOrderAscending);
265 // calculate average size of elements above 1gb
266 for (int j = 0; j < items.Size(); j++)
267 if (items[j]->m_dwSize > 1000000000)
270 asize = asize + items[j]->m_dwSize;
272 asize = asize / ecount;
273 // Put largest files in alphabetical order to top of new list.
274 for (int j = 0; j < items.Size(); j++)
275 if (items[j]->m_dwSize >= asize)
276 sitems.Add (items[j]);
277 // Sort *.evo files by size.
278 items.Sort(SortBySize, SortOrderDescending);
279 // Add other files with descending size to bottom of new list.
280 for (int j = 0; j < items.Size(); j++)
281 if (items[j]->m_dwSize < asize)
282 sitems.Add (items[j]);
283 // Replace list with optimized list.
290 CFileItem item(URIUtils::AddFileToFolder(phddvdItem->GetPath(), hddvdname), false);
291 item.SetLabel(g_mediaManager.GetDiskLabel(strDrive));
292 item.GetVideoInfoTag()->m_strFileNameAndPath = g_mediaManager.GetDiskUniqueId(strDrive);
294 if (!startFromBeginning && !item.GetVideoInfoTag()->m_strFileNameAndPath.empty())
295 item.m_lStartOffset = STARTOFFSET_RESUME;
298 CStdString hddvdplayer = CPlayerCoreFactory::Get().GetPlayerName(CPlayerCoreFactory::Get().GetDefaultPlayer(item));
300 // Single *.xpl or *.ifo files require an external player to handle playback.
301 // If no matching rule was found, DVDPlayer will be default player.
302 if (hddvdplayer != "DVDPlayer")
304 CLog::Log(LOGINFO,"HD DVD: External singlefile playback initiated: %s",hddvdname.c_str());
305 g_application.PlayFile(item, false);
308 CLog::Log(LOGINFO,"HD DVD: No external player found. Fallback to internal one.");
311 // internal *.evo playback.
312 CLog::Log(LOGINFO,"HD DVD: Internal multifile playback initiated.");
313 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
314 g_playlistPlayer.SetShuffle (PLAYLIST_VIDEO, false);
315 g_playlistPlayer.Add(PLAYLIST_VIDEO, items);
316 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
317 g_playlistPlayer.Play(0);
321 // Video CDs can have multiple file formats. First we need to determine which one is used on the CD
323 if (name.Equals("MPEGAV"))
325 if (name.Equals("MPEG2"))
328 // If a file format was extracted we are sure this is a VCD. Autoplay if settings indicate we should.
329 if (!strExt.empty() && bAllowVideo
330 && (bypassSettings || CSettings::Get().GetBool("dvds.autorun")))
333 CDirectory::GetDirectory(pItem->GetPath(), items, strExt);
336 items.Sort(SortByLabel, SortOrderAscending);
337 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
338 g_playlistPlayer.Add(PLAYLIST_VIDEO, items);
339 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
340 g_playlistPlayer.Play(0);
344 /* Probably want this if/when we add some automedia action dialog...
345 else if (pItem->GetPath().Find("PICTURES") != -1 && bAllowPictures
349 CStdString strExec = StringUtils::Format("XBMC.RecursiveSlideShow(%s)", pItem->GetPath().c_str());
350 CBuiltins::Execute(strExec);
359 if (!nAddedToPlaylist && !bPlaying && (bypassSettings || CSettings::Get().GetBool("dvds.autorun")))
362 CFileItemList tempItems;
363 tempItems.Append(vecItems);
364 if (CSettings::Get().GetBool("myvideos.stackvideos"))
366 CFileItemList itemlist;
368 for (int i = 0; i < tempItems.Size(); i++)
370 CFileItemPtr pItem = tempItems[i];
371 if (!pItem->m_bIsFolder && pItem->IsVideo())
374 if (pItem->IsStack())
376 // TODO: remove this once the app/player is capable of handling stacks immediately
379 dir.GetDirectory(pItem->GetPath(), items);
380 itemlist.Append(items);
393 if (g_windowManager.GetActiveWindow() != WINDOW_VIDEO_FILES)
394 if (!g_passwordManager.IsMasterLockUnlocked(true))
397 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
398 g_playlistPlayer.Add(PLAYLIST_VIDEO, itemlist);
399 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
400 g_playlistPlayer.Play(0);
404 if (!bPlaying && (bypassSettings || CSettings::Get().GetInt("audiocds.autoaction") == AUTOCD_PLAY) && bAllowMusic)
406 for (int i = 0; i < vecItems.Size(); i++)
408 CFileItemPtr pItem = vecItems[i];
409 if (!pItem->m_bIsFolder && pItem->IsAudio())
412 g_playlistPlayer.Add(PLAYLIST_MUSIC, pItem);
416 /* Probably want this if/when we add some automedia action dialog...
417 // and finally pictures
418 if (!nAddedToPlaylist && !bPlaying && bypassSettings && bAllowPictures)
420 for (int i = 0; i < vecItems.Size(); i++)
422 CFileItemPtr pItem = vecItems[i];
423 if (!pItem->m_bIsFolder && pItem->IsPicture())
426 CStdString strExec = StringUtils::Format("XBMC.RecursiveSlideShow(%s)", strDrive.c_str());
427 CBuiltins::Execute(strExec);
434 // check subdirs if we are not playing yet
437 for (int i = 0; i < vecItems.Size(); i++)
439 CFileItemPtr pItem = vecItems[i];
440 if (pItem->m_bIsFolder)
442 if (pItem->GetPath() != "." && pItem->GetPath() != ".." )
444 if (RunDisc(pDir, pItem->GetPath(), nAddedToPlaylist, false, bypassSettings, startFromBeginning))
450 } // if (non system) folder
451 } // for all items in directory
457 void CAutorun::HandleAutorun()
459 #ifndef TARGET_WINDOWS
462 CDetectDVDMedia::m_evAutorun.Reset();
466 if (CDetectDVDMedia::m_evAutorun.WaitMSec(0))
469 CDetectDVDMedia::m_evAutorun.Reset();
474 void CAutorun::Enable()
479 void CAutorun::Disable()
484 bool CAutorun::IsEnabled() const
489 bool CAutorun::PlayDiscAskResume(const CStdString& path)
491 return PlayDisc(path, true, !CanResumePlayDVD(path) || CGUIDialogYesNo::ShowAndGetInput(341, -1, -1, -1, 13404, 12021));
494 bool CAutorun::CanResumePlayDVD(const CStdString& path)
496 CStdString strUniqueId = g_mediaManager.GetDiskUniqueId(path);
497 if (!strUniqueId.empty())
502 if (dbs.GetResumeBookMark(strUniqueId, bookmark))
508 void CAutorun::SettingOptionAudioCdActionsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t)
510 list.push_back(make_pair(g_localizeStrings.Get(16018), AUTOCD_NONE));
511 list.push_back(make_pair(g_localizeStrings.Get(14098), AUTOCD_PLAY));
512 #ifdef HAS_CDDA_RIPPER
513 list.push_back(make_pair(g_localizeStrings.Get(14096), AUTOCD_RIP));
517 void CAutorun::SettingOptionAudioCdEncodersFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t)
519 #ifdef HAVE_LIBMP3LAME
520 list.push_back(make_pair(g_localizeStrings.Get(34000), CDDARIP_ENCODER_LAME));
522 #ifdef HAVE_LIBVORBISENC
523 list.push_back(make_pair(g_localizeStrings.Get(34001), CDDARIP_ENCODER_VORBIS));
525 list.push_back(make_pair(g_localizeStrings.Get(34002), CDDARIP_ENCODER_WAV));
526 list.push_back(make_pair(g_localizeStrings.Get(34005), CDDARIP_ENCODER_FLAC));
527 list.push_back(make_pair(g_localizeStrings.Get(34006), CDDARIP_ENCODER_FFMPEG_M4A));
528 list.push_back(make_pair(g_localizeStrings.Get(34007), CDDARIP_ENCODER_FFMPEG_WMA));