2 * Copyright (C) 2005-2012 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 "settings/GUISettings.h"
35 #include "settings/Settings.h"
36 #include "playlists/PlayList.h"
37 #include "guilib/GUIWindowManager.h"
38 #include "storage/MediaManager.h"
39 #include "video/VideoDatabase.h"
40 #include "dialogs/GUIDialogYesNo.h"
41 #include "utils/URIUtils.h"
42 #include "utils/log.h"
43 #ifdef HAS_CDDA_RIPPER
44 #include "cdrip/CDDARipper.h"
48 using namespace XFILE;
49 using namespace PLAYLIST;
50 using namespace MEDIA_DETECT;
60 void CAutorun::ExecuteAutorun(const CStdString& path, bool bypassSettings, bool ignoreplaying, bool startFromBeginning )
62 if ((!ignoreplaying && (g_application.IsPlayingAudio() || g_application.IsPlayingVideo() || g_windowManager.HasModalDialog())) || g_windowManager.GetActiveWindow() == WINDOW_LOGIN_SCREEN)
65 CCdInfo* pInfo = g_mediaManager.GetCdInfo(path);
70 g_application.ResetScreenSaver();
71 g_application.WakeUpScreenSaverAndDPMS(); // turn off the screensaver if it's active
72 #ifdef HAS_CDDA_RIPPER
73 if (g_guiSettings.GetInt("audiocds.autoaction") == AUTOCD_RIP &&
74 pInfo->IsAudio(1) && !g_settings.GetCurrentProfile().musicLocked())
76 CCDDARipper::GetInstance().RipCD();
80 PlayDisc(path, bypassSettings, startFromBeginning);
83 bool CAutorun::PlayDisc(const CStdString& path, bool bypassSettings, bool startFromBeginning)
85 if ( !bypassSettings && !g_guiSettings.GetInt("audiocds.autoaction") == AUTOCD_PLAY && !g_guiSettings.GetBool("dvds.autorun"))
88 int nSize = g_playlistPlayer.GetPlaylist( PLAYLIST_MUSIC ).size();
89 int nAddedToPlaylist = 0;
93 CCdInfo* pInfo = g_mediaManager.GetCdInfo(path);
97 if (mediaPath.IsEmpty() && pInfo->IsAudio(1))
98 mediaPath = "cdda://local/";
100 if (mediaPath.IsEmpty() && (pInfo->IsISOUDF(1) || pInfo->IsISOHFS(1) || pInfo->IsIso9660(1) || pInfo->IsIso9660Interactive(1)))
101 mediaPath = "iso9660://";
103 if (mediaPath.IsEmpty())
107 if (mediaPath.IsEmpty() || mediaPath.CompareNoCase("iso9660://") == 0)
108 mediaPath = g_mediaManager.TranslateDevicePath("");
111 auto_ptr<IDirectory> pDir ( CDirectoryFactory::Create( mediaPath ));
112 bool bPlaying = RunDisc(pDir.get(), mediaPath, nAddedToPlaylist, true, bypassSettings, startFromBeginning);
114 if ( !bPlaying && nAddedToPlaylist > 0 )
116 CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
117 g_windowManager.SendMessage( msg );
118 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_MUSIC);
119 // Start playing the items we inserted
120 return g_playlistPlayer.Play(nSize);
127 * This method tries to determine what type of disc is located in the given drive and starts to play the content appropriately.
129 bool CAutorun::RunDisc(IDirectory* pDir, const CStdString& strDrive, int& nAddedToPlaylist, bool bRoot, bool bypassSettings /* = false */, bool startFromBeginning /* = false */)
131 bool bPlaying(false);
132 CFileItemList vecItems;
134 if ( !pDir->GetDirectory( strDrive, vecItems ) )
139 // Sorting necessary for easier HDDVD handling
140 vecItems.Sort(SORT_METHOD_LABEL, SortOrderAscending);
142 bool bAllowVideo = true;
143 // bool bAllowPictures = true;
144 bool bAllowMusic = true;
145 if (!g_passwordManager.IsMasterLockUnlocked(false))
147 bAllowVideo = !g_settings.GetCurrentProfile().videoLocked();
148 // bAllowPictures = !g_settings.GetCurrentProfile().picturesLocked();
149 bAllowMusic = !g_settings.GetCurrentProfile().musicLocked();
152 // is this a root folder we have to check the content to determine a disc type
155 CStdString hddvdname = "";
156 CFileItemPtr phddvdItem;
158 // check root folders next, for normal structured dvd's
159 for (int i = 0; i < vecItems.Size(); i++)
161 CFileItemPtr pItem = vecItems[i];
163 // is the current item a (non system) folder?
164 if (pItem->m_bIsFolder && pItem->GetPath() != "." && pItem->GetPath() != "..")
166 CStdString name = pItem->GetPath();
167 URIUtils::RemoveSlashAtEnd(name);
168 name = URIUtils::GetFileName(name);
170 // Check if the current foldername indicates a DVD structure (name is "VIDEO_TS")
171 if (name.Equals("VIDEO_TS") && bAllowVideo
172 && (bypassSettings || g_guiSettings.GetBool("dvds.autorun")))
174 CStdString path = URIUtils::AddFileToFolder(pItem->GetPath(), "VIDEO_TS.IFO");
175 if(!CFile::Exists(path))
176 path = URIUtils::AddFileToFolder(pItem->GetPath(), "video_ts.ifo");
177 CFileItem item(path, false);
178 item.SetLabel(g_mediaManager.GetDiskLabel(strDrive));
179 item.GetVideoInfoTag()->m_strFileNameAndPath = g_mediaManager.GetDiskUniqueId(strDrive);
181 if (!startFromBeginning && !item.GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
182 item.m_lStartOffset = STARTOFFSET_RESUME;
184 g_application.PlayFile(item, false);
189 // Check if the current foldername indicates a Blu-Ray structure (default is "BDMV").
190 // A BR should also include an "AACS" folder for encryption, Sony-BRs can also include update folders for PS3 (PS3_UPDATE / PS3_VPRM).
191 // ToDo: for the time beeing, the DVD autorun settings are used to determine if the BR should be started automatically.
192 if (name.Equals("BDMV") && bAllowVideo
193 && (bypassSettings || g_guiSettings.GetBool("dvds.autorun")))
195 CFileItem item(URIUtils::AddFileToFolder(pItem->GetPath(), "index.bdmv"), false);
196 item.SetLabel(g_mediaManager.GetDiskLabel(strDrive));
197 item.GetVideoInfoTag()->m_strFileNameAndPath = g_mediaManager.GetDiskUniqueId(strDrive);
199 if (!startFromBeginning && !item.GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
200 item.m_lStartOffset = STARTOFFSET_RESUME;
202 g_application.PlayFile(item, false);
207 // Check if the current foldername indicates a HD DVD structure (default is "HVDVD_TS").
208 // Most HD DVD will also include an "ADV_OBJ" folder for advanced content. This folder should be handled first.
209 // ToDo: for the time beeing, the DVD autorun settings are used to determine if the HD DVD should be started automatically.
210 CFileItemList items, sitems;
212 // Advanced Content HD DVD (most discs?)
213 if (name.Equals("ADV_OBJ"))
215 CLog::Log(LOGINFO,"HD DVD: Checking for playlist.");
216 // find playlist file
217 CDirectory::GetDirectory(pItem->GetPath(), items, "*.xpl");
220 // HD DVD Standard says the highest numbered playlist has to be handled first.
221 CLog::Log(LOGINFO,"HD DVD: Playlist found. Set filetypes to *.xpl for external player.");
222 items.Sort(SORT_METHOD_LABEL, SortOrderDescending);
224 hddvdname = URIUtils::GetFileName(items[0]->GetPath());
225 CLog::Log(LOGINFO,"HD DVD: %s", items[0]->GetPath().c_str());
229 // Standard Content HD DVD (few discs?)
230 if (name.Equals("HVDVD_TS") && bAllowVideo
231 && (bypassSettings || g_guiSettings.GetBool("dvds.autorun")))
235 CLog::Log(LOGINFO,"HD DVD: Checking for ifo.");
236 // find Video Manager or Title Set Information
237 CDirectory::GetDirectory(pItem->GetPath(), items, "HV*.ifo");
240 // HD DVD Standard says the lowest numbered ifo has to be handled first.
241 CLog::Log(LOGINFO,"HD DVD: IFO found. Set filename to HV* and filetypes to *.ifo for external player.");
242 items.Sort(SORT_METHOD_LABEL, SortOrderAscending);
244 hddvdname = URIUtils::GetFileName(items[0]->GetPath());
245 CLog::Log(LOGINFO,"HD DVD: %s",items[0]->GetPath().c_str());
248 // Find and sort *.evo files for internal playback.
249 // While this algorithm works for all of my HD DVDs, it may fail on other discs. If there are very large extras which are
250 // alphabetically before the main movie they will be sorted to the top of the playlist and get played first.
251 CDirectory::GetDirectory(pItem->GetPath(), items, "*.evo");
254 // Sort *.evo files in alphabetical order.
255 items.Sort(SORT_METHOD_LABEL, SortOrderAscending);
258 // calculate average size of elements above 1gb
259 for (int j = 0; j < items.Size(); j++)
260 if (items[j]->m_dwSize > 1000000000)
263 asize = asize + items[j]->m_dwSize;
265 asize = asize / ecount;
266 // Put largest files in alphabetical order to top of new list.
267 for (int j = 0; j < items.Size(); j++)
268 if (items[j]->m_dwSize >= asize)
269 sitems.Add (items[j]);
270 // Sort *.evo files by size.
271 items.Sort(SORT_METHOD_SIZE, SortOrderDescending);
272 // Add other files with descending size to bottom of new list.
273 for (int j = 0; j < items.Size(); j++)
274 if (items[j]->m_dwSize < asize)
275 sitems.Add (items[j]);
276 // Replace list with optimized list.
283 CFileItem item(URIUtils::AddFileToFolder(phddvdItem->GetPath(), hddvdname), false);
284 item.SetLabel(g_mediaManager.GetDiskLabel(strDrive));
285 item.GetVideoInfoTag()->m_strFileNameAndPath = g_mediaManager.GetDiskUniqueId(strDrive);
287 if (!startFromBeginning && !item.GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
288 item.m_lStartOffset = STARTOFFSET_RESUME;
291 CStdString hddvdplayer = CPlayerCoreFactory::GetPlayerName(CPlayerCoreFactory::GetDefaultPlayer(item));
293 // Single *.xpl or *.ifo files require an external player to handle playback.
294 // If no matching rule was found, DVDPlayer will be default player.
295 if (hddvdplayer != "DVDPlayer")
297 CLog::Log(LOGINFO,"HD DVD: External singlefile playback initiated: %s",hddvdname.c_str());
298 g_application.PlayFile(item, false);
302 CLog::Log(LOGINFO,"HD DVD: No external player found. Fallback to internal one.");
305 // internal *.evo playback.
306 CLog::Log(LOGINFO,"HD DVD: Internal multifile playback initiated.");
307 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
308 g_playlistPlayer.SetShuffle (PLAYLIST_VIDEO, false);
309 g_playlistPlayer.Add(PLAYLIST_VIDEO, items);
310 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
311 g_playlistPlayer.Play(0);
316 // Video CDs can have multiple file formats. First we need to determine which one is used on the CD
318 if (name.Equals("MPEGAV"))
320 if (name.Equals("MPEG2"))
323 // If a file format was extracted we are sure this is a VCD. Autoplay if settings indicate we should.
324 if (!strExt.IsEmpty() && bAllowVideo
325 && (bypassSettings || g_guiSettings.GetBool("dvds.autorun")))
328 CDirectory::GetDirectory(pItem->GetPath(), items, strExt);
331 items.Sort(SORT_METHOD_LABEL, SortOrderAscending);
332 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
333 g_playlistPlayer.Add(PLAYLIST_VIDEO, items);
334 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
335 g_playlistPlayer.Play(0);
340 /* Probably want this if/when we add some automedia action dialog...
341 else if (pItem->GetPath().Find("PICTURES") != -1 && bAllowPictures
346 strExec.Format("XBMC.RecursiveSlideShow(%s)", pItem->GetPath().c_str());
347 CBuiltins::Execute(strExec);
356 if (!nAddedToPlaylist && !bPlaying && (bypassSettings || g_guiSettings.GetBool("dvds.autorun")))
359 CFileItemList tempItems;
360 tempItems.Append(vecItems);
361 if (g_settings.m_videoStacking)
363 CFileItemList itemlist;
365 for (int i = 0; i < tempItems.Size(); i++)
367 CFileItemPtr pItem = tempItems[i];
368 if (!pItem->m_bIsFolder && pItem->IsVideo())
371 if (pItem->IsStack())
373 // TODO: remove this once the app/player is capable of handling stacks immediately
376 dir.GetDirectory(pItem->GetPath(), items);
377 itemlist.Append(items);
390 if (g_windowManager.GetActiveWindow() != WINDOW_VIDEO_FILES)
391 if (!g_passwordManager.IsMasterLockUnlocked(true))
394 g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
395 g_playlistPlayer.Add(PLAYLIST_VIDEO, itemlist);
396 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
397 g_playlistPlayer.Play(0);
401 if (!bPlaying && (bypassSettings || g_guiSettings.GetInt("audiocds.autoaction") == AUTOCD_PLAY) && bAllowMusic)
403 for (int i = 0; i < vecItems.Size(); i++)
405 CFileItemPtr pItem = vecItems[i];
406 if (!pItem->m_bIsFolder && pItem->IsAudio())
409 g_playlistPlayer.Add(PLAYLIST_MUSIC, pItem);
413 /* Probably want this if/when we add some automedia action dialog...
414 // and finally pictures
415 if (!nAddedToPlaylist && !bPlaying && bypassSettings && bAllowPictures)
417 for (int i = 0; i < vecItems.Size(); i++)
419 CFileItemPtr pItem = vecItems[i];
420 if (!pItem->m_bIsFolder && pItem->IsPicture())
424 strExec.Format("XBMC.RecursiveSlideShow(%s)", strDrive.c_str());
425 CBuiltins::Execute(strExec);
432 // check subdirs if we are not playing yet
435 for (int i = 0; i < vecItems.Size(); i++)
437 CFileItemPtr pItem = vecItems[i];
438 if (pItem->m_bIsFolder)
440 if (pItem->GetPath() != "." && pItem->GetPath() != ".." )
442 if (RunDisc(pDir, pItem->GetPath(), nAddedToPlaylist, false, bypassSettings, startFromBeginning))
448 } // if (non system) folder
449 } // for all items in directory
455 void CAutorun::HandleAutorun()
460 CDetectDVDMedia::m_evAutorun.Reset();
464 if (CDetectDVDMedia::m_evAutorun.WaitMSec(0))
467 CDetectDVDMedia::m_evAutorun.Reset();
472 void CAutorun::Enable()
477 void CAutorun::Disable()
482 bool CAutorun::IsEnabled() const
487 bool CAutorun::PlayDiscAskResume(const CStdString& path)
489 return PlayDisc(path, true, !CanResumePlayDVD(path) || CGUIDialogYesNo::ShowAndGetInput(341, -1, -1, -1, 13404, 12021));
492 bool CAutorun::CanResumePlayDVD(const CStdString& path)
494 CStdString strUniqueId = g_mediaManager.GetDiskUniqueId(path);
495 if (!strUniqueId.IsEmpty())
500 if (dbs.GetResumeBookMark(strUniqueId, bookmark))