2 * Copyright (C) 2011-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/>.
23 #if defined (HAS_OMXPLAYER)
28 #include "OMXPlayerAudio.h"
29 #include "OMXPlayerVideo.h"
30 #include "OMXPlayer.h"
31 #include "Application.h"
32 #include "ApplicationMessenger.h"
33 #include "GUIInfoManager.h"
34 #include "cores/VideoRenderers/RenderManager.h"
35 #include "cores/VideoRenderers/RenderFlags.h"
37 #include "filesystem/File.h"
38 #include "filesystem/SpecialProtocol.h"
39 #include "guilib/GUIWindowManager.h"
40 #include "settings/AdvancedSettings.h"
41 #include "settings/MediaSettings.h"
42 #include "settings/Settings.h"
43 #include "threads/SingleLock.h"
44 #include "windowing/WindowingFactory.h"
46 #include "utils/log.h"
47 #include "utils/TimeUtils.h"
48 #include "utils/URIUtils.h"
49 #include "utils/Variant.h"
50 #include "utils/StreamDetails.h"
51 #include "xbmc/playlists/PlayListM3U.h"
53 #include "utils/LangCodeExpander.h"
54 #include "guilib/LocalizeStrings.h"
55 #include "guilib/Key.h"
57 #include "storage/MediaManager.h"
58 #include "GUIUserMessages.h"
59 #include "utils/StreamUtils.h"
61 #include "DVDInputStreams/DVDFactoryInputStream.h"
62 #include "DVDInputStreams/DVDInputStreamNavigator.h"
63 #include "DVDInputStreams/DVDInputStreamTV.h"
64 #include "DVDInputStreams/DVDInputStreamPVRManager.h"
66 #include "DVDDemuxers/DVDDemux.h"
67 #include "DVDDemuxers/DVDDemuxUtils.h"
68 #include "DVDDemuxers/DVDDemuxVobsub.h"
69 #include "DVDDemuxers/DVDFactoryDemuxer.h"
70 #include "DVDDemuxers/DVDDemuxFFmpeg.h"
72 #include "DVDCodecs/DVDCodecs.h"
73 #include "DVDCodecs/DVDFactoryCodec.h"
75 #include "DVDFileInfo.h"
77 #include "utils/LangCodeExpander.h"
78 #include "guilib/Key.h"
79 #include "guilib/LocalizeStrings.h"
81 #include "utils/URIUtils.h"
82 #include "GUIInfoManager.h"
83 #include "guilib/GUIWindowManager.h"
84 #include "guilib/StereoscopicsManager.h"
85 #include "Application.h"
86 #include "ApplicationMessenger.h"
87 #include "filesystem/File.h"
88 #include "pictures/Picture.h"
89 #include "DllSwScale.h"
90 #ifdef HAS_VIDEO_PLAYBACK
91 #include "cores/VideoRenderers/RenderManager.h"
93 #ifdef HAS_PERFORMANCE_SAMPLE
94 #include "xbmc/utils/PerformanceSample.h"
96 #define MEASURE_FUNCTION
98 #include "settings/AdvancedSettings.h"
100 #include "GUIUserMessages.h"
101 #include "settings/Settings.h"
102 #include "settings/MediaSettings.h"
103 #include "utils/log.h"
104 #include "utils/TimeUtils.h"
105 #include "utils/StreamDetails.h"
106 #include "pvr/PVRManager.h"
107 #include "pvr/channels/PVRChannel.h"
108 #include "pvr/windows/GUIWindowPVR.h"
109 #include "pvr/addons/PVRClients.h"
110 #include "filesystem/PVRFile.h"
111 #include "video/dialogs/GUIDialogFullScreenInfo.h"
112 #include "utils/StreamUtils.h"
113 #include "utils/Variant.h"
114 #include "storage/MediaManager.h"
115 #include "dialogs/GUIDialogBusy.h"
116 #include "dialogs/GUIDialogKaiToast.h"
117 #include "xbmc/playlists/PlayListM3U.h"
118 #include "utils/StringUtils.h"
120 #include "LangInfo.h"
122 #include "utils/LangCodeExpander.h"
124 // video not playing from clock, but stepped
125 #define TP(speed) ((speed) < 0 || (speed) > 4*DVD_PLAYSPEED_NORMAL)
127 #define TPA(speed) ((speed) != DVD_PLAYSPEED_PAUSE && (speed) != DVD_PLAYSPEED_NORMAL)
132 void COMXSelectionStreams::Clear(StreamType type, StreamSource source)
134 CSingleLock lock(m_section);
135 for(int i=m_Streams.size()-1;i>=0;i--)
137 if(type && m_Streams[i].type != type)
140 if(source && m_Streams[i].source != source)
143 m_Streams.erase(m_Streams.begin() + i);
147 OMXSelectionStream& COMXSelectionStreams::Get(StreamType type, int index)
149 CSingleLock lock(m_section);
151 for(int i=0;i<(int)m_Streams.size();i++)
153 if(m_Streams[i].type != type)
159 CLog::Log(LOGERROR, "%s - failed to get stream", __FUNCTION__);
163 std::vector<OMXSelectionStream> COMXSelectionStreams::Get(StreamType type)
165 std::vector<OMXSelectionStream> streams;
166 int count = Count(type);
167 for(int index = 0; index < count; ++index){
168 streams.push_back(Get(type, index));
173 #define PREDICATE_RETURN(lh, rh) \
176 return (lh) > (rh); \
179 class PredicateSubtitleFilter
182 std::string audiolang;
186 /** \brief The class' operator() decides if the given (subtitle) SelectionStream is relevant wrt.
187 * preferred subtitle language and audio language. If the subtitle is relevant <B>false</B> false is returned.
189 * A subtitle is relevant if
190 * - it was previously selected, or
191 * - it's an external sub and "prefer external subs was selected", or
192 * - it's a forced sub and "original stream's language" was selected, or
193 * - it's a forced sub and its language matches the audio's language, or
194 * - it's a default sub, or
195 * - its language matches the preferred subtitle's language (unequal to "original stream's language")
197 PredicateSubtitleFilter(std::string& lang)
199 original(StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.subtitlelanguage"), "original")),
200 preferexternal(CSettings::Get().GetBool("subtitles.preferexternal"))
204 bool operator()(const OMXSelectionStream& ss) const
206 if (ss.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream)
211 if(ss.source == STREAM_SOURCE_DEMUX_SUB || ss.source == STREAM_SOURCE_TEXT)
215 if ((ss.flags & CDemuxStream::FLAG_FORCED) && (original || g_LangCodeExpander.CompareLangCodes(ss.language, audiolang)))
218 if ((ss.flags & CDemuxStream::FLAG_DEFAULT))
223 std::string subtitle_language = g_langInfo.GetSubtitleLanguage();
224 if (g_LangCodeExpander.CompareLangCodes(subtitle_language, ss.language))
232 static bool PredicateAudioPriority(const OMXSelectionStream& lh, const OMXSelectionStream& rh)
234 PREDICATE_RETURN(lh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream
235 , rh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream);
237 if(!StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.audiolanguage"), "original"))
239 CStdString audio_language = g_langInfo.GetAudioLanguage();
240 PREDICATE_RETURN(g_LangCodeExpander.CompareLangCodes(audio_language, lh.language)
241 , g_LangCodeExpander.CompareLangCodes(audio_language, rh.language));
244 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT
245 , rh.flags & CDemuxStream::FLAG_DEFAULT);
247 PREDICATE_RETURN(lh.channels
250 PREDICATE_RETURN(StreamUtils::GetCodecPriority(lh.codec)
251 , StreamUtils::GetCodecPriority(rh.codec));
255 /** \brief The class' operator() decides if the given (subtitle) SelectionStream lh is 'better than' the given (subtitle) SelectionStream rh.
256 * If lh is 'better than' rh the return value is true, false otherwise.
258 * A subtitle lh is 'better than' a subtitle rh (in evaluation order) if
259 * - lh was previously selected, or
260 * - lh is an external sub and "prefer external subs was selected" and rh not, or
261 * - lh is a forced sub and ("original stream's language" was selected or subtitles are off) and rh not, or
262 * - lh is an external sub and its language matches the preferred subtitle's language (unequal to "original stream's language") and rh not, or
263 * - lh is an external sub and rh not, or
264 * - lh is language matches the preferred subtitle's language (unequal to "original stream's language") and rh not, or
265 * - lh is a default sub and rh not
267 class PredicateSubtitlePriority
270 std::string audiolang;
275 PredicateSubtitlePriority(std::string& lang)
277 original(StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.subtitlelanguage"), "original")),
278 preferextsubs(CSettings::Get().GetBool("subtitles.preferexternal")),
279 subson(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn)
283 bool operator()(const OMXSelectionStream& lh, const OMXSelectionStream& rh) const
285 PREDICATE_RETURN(lh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream
286 , rh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream);
290 PREDICATE_RETURN(lh.source == STREAM_SOURCE_DEMUX_SUB
291 , rh.source == STREAM_SOURCE_DEMUX_SUB);
293 PREDICATE_RETURN(lh.source == STREAM_SOURCE_TEXT
294 , rh.source == STREAM_SOURCE_TEXT);
297 if(!subson || original)
299 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_FORCED && g_LangCodeExpander.CompareLangCodes(lh.language, audiolang)
300 , rh.flags & CDemuxStream::FLAG_FORCED && g_LangCodeExpander.CompareLangCodes(rh.language, audiolang));
302 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_FORCED
303 , rh.flags & CDemuxStream::FLAG_FORCED);
306 CStdString subtitle_language = g_langInfo.GetSubtitleLanguage();
309 PREDICATE_RETURN((lh.source == STREAM_SOURCE_DEMUX_SUB || lh.source == STREAM_SOURCE_TEXT) && g_LangCodeExpander.CompareLangCodes(subtitle_language, lh.language)
310 , (rh.source == STREAM_SOURCE_DEMUX_SUB || rh.source == STREAM_SOURCE_TEXT) && g_LangCodeExpander.CompareLangCodes(subtitle_language, rh.language));
313 PREDICATE_RETURN(lh.source == STREAM_SOURCE_DEMUX_SUB
314 , rh.source == STREAM_SOURCE_DEMUX_SUB);
316 PREDICATE_RETURN(lh.source == STREAM_SOURCE_TEXT
317 , rh.source == STREAM_SOURCE_TEXT);
321 PREDICATE_RETURN(g_LangCodeExpander.CompareLangCodes(subtitle_language, lh.language)
322 , g_LangCodeExpander.CompareLangCodes(subtitle_language, rh.language));
325 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT
326 , rh.flags & CDemuxStream::FLAG_DEFAULT);
332 static bool PredicateVideoPriority(const OMXSelectionStream& lh, const OMXSelectionStream& rh)
334 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT
335 , rh.flags & CDemuxStream::FLAG_DEFAULT);
339 bool COMXSelectionStreams::Get(StreamType type, CDemuxStream::EFlags flag, OMXSelectionStream& out)
341 CSingleLock lock(m_section);
342 for(int i=0;i<(int)m_Streams.size();i++)
344 if(m_Streams[i].type != type)
346 if((m_Streams[i].flags & flag) != flag)
354 int COMXSelectionStreams::IndexOf(StreamType type, int source, int id) const
356 CSingleLock lock(m_section);
358 for(int i=0;i<(int)m_Streams.size();i++)
360 if(type && m_Streams[i].type != type)
363 if(source && m_Streams[i].source != source)
367 if(m_Streams[i].id == id)
376 int COMXSelectionStreams::IndexOf(StreamType type, COMXPlayer& p) const
378 if (p.m_pInputStream && p.m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
381 if(type == STREAM_AUDIO)
382 id = ((CDVDInputStreamNavigator*)p.m_pInputStream)->GetActiveAudioStream();
383 else if(type == STREAM_VIDEO)
384 id = p.m_CurrentVideo.id;
385 else if(type == STREAM_SUBTITLE)
386 id = ((CDVDInputStreamNavigator*)p.m_pInputStream)->GetActiveSubtitleStream();
388 return IndexOf(type, STREAM_SOURCE_NAV, id);
391 if(type == STREAM_AUDIO)
392 return IndexOf(type, p.m_CurrentAudio.source, p.m_CurrentAudio.id);
393 else if(type == STREAM_VIDEO)
394 return IndexOf(type, p.m_CurrentVideo.source, p.m_CurrentVideo.id);
395 else if(type == STREAM_SUBTITLE)
396 return IndexOf(type, p.m_CurrentSubtitle.source, p.m_CurrentSubtitle.id);
397 else if(type == STREAM_TELETEXT)
398 return IndexOf(type, p.m_CurrentTeletext.source, p.m_CurrentTeletext.id);
403 int COMXSelectionStreams::Source(StreamSource source, std::string filename)
405 CSingleLock lock(m_section);
406 int index = source - 1;
407 for(int i=0;i<(int)m_Streams.size();i++)
409 OMXSelectionStream &s = m_Streams[i];
410 if(STREAM_SOURCE_MASK(s.source) != source)
412 // if it already exists, return same
413 if(s.filename == filename)
422 void COMXSelectionStreams::Update(OMXSelectionStream& s)
424 CSingleLock lock(m_section);
425 int index = IndexOf(s.type, s.source, s.id);
428 OMXSelectionStream& o = Get(s.type, index);
429 s.type_index = o.type_index;
434 s.type_index = Count(s.type);
435 m_Streams.push_back(s);
439 void COMXSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer)
441 if(input && input->IsStreamType(DVDSTREAM_TYPE_DVD))
443 CDVDInputStreamNavigator* nav = (CDVDInputStreamNavigator*)input;
444 string filename = nav->GetFileName();
445 int source = Source(STREAM_SOURCE_NAV, filename);
448 count = nav->GetAudioStreamCount();
449 for(int i=0;i<count;i++)
451 OMXSelectionStream s;
453 s.type = STREAM_AUDIO;
455 s.flags = CDemuxStream::FLAG_NONE;
456 s.filename = filename;
458 DVDNavStreamInfo info;
459 nav->GetAudioStreamInfo(i, info);
461 s.language = g_LangCodeExpander.ConvertToISO6392T(info.language);
462 s.channels = info.channels;
466 count = nav->GetSubTitleStreamCount();
467 for(int i=0;i<count;i++)
469 OMXSelectionStream s;
471 s.type = STREAM_SUBTITLE;
473 s.flags = CDemuxStream::FLAG_NONE;
474 s.filename = filename;
477 DVDNavStreamInfo info;
478 nav->GetSubtitleStreamInfo(i, info);
480 s.language = g_LangCodeExpander.ConvertToISO6392T(info.language);
486 string filename = demuxer->GetFileName();
487 int count = demuxer->GetNrOfStreams();
489 if(input) /* hack to know this is sub decoder */
490 source = Source(STREAM_SOURCE_DEMUX, filename);
492 source = Source(STREAM_SOURCE_DEMUX_SUB, filename);
495 for(int i=0;i<count;i++)
497 CDemuxStream* stream = demuxer->GetStream(i);
498 /* make sure stream is marked with right source */
499 stream->source = source;
501 OMXSelectionStream s;
503 s.type = stream->type;
505 s.language = g_LangCodeExpander.ConvertToISO6392T(stream->language);
506 s.flags = stream->flags;
507 s.filename = demuxer->GetFileName();
508 stream->GetStreamName(s.name);
510 demuxer->GetStreamCodecName(stream->iId, codec);
512 s.channels = 0; // Default to 0. Overwrite if STREAM_AUDIO below.
513 if(stream->type == STREAM_AUDIO)
516 ((CDemuxStreamAudio*)stream)->GetStreamType(type);
517 if(type.length() > 0)
519 if(s.name.length() > 0)
523 s.channels = ((CDemuxStreamAudio*)stream)->iChannels;
530 COMXPlayer::COMXPlayer(IPlayerCallback &callback)
532 CThread("OMXPlayer"),
533 m_CurrentAudio(STREAM_AUDIO, DVDPLAYER_AUDIO),
534 m_CurrentVideo(STREAM_VIDEO, DVDPLAYER_VIDEO),
535 m_CurrentSubtitle(STREAM_SUBTITLE, DVDPLAYER_SUBTITLE),
536 m_CurrentTeletext(STREAM_TELETEXT, DVDPLAYER_TELETEXT),
537 m_messenger("player"),
538 m_omxPlayerVideo(&m_av_clock, &m_overlayContainer, m_messenger),
539 m_omxPlayerAudio(&m_av_clock, m_messenger),
540 m_dvdPlayerSubtitle(&m_overlayContainer),
541 m_dvdPlayerTeletext(),
545 m_pSubtitleDemuxer = NULL;
546 m_pInputStream = NULL;
550 m_EdlAutoSkipMarkers.Clear();
551 m_UpdateApplication = 0;
553 m_bAbortRequest = false;
556 m_playSpeed = DVD_PLAYSPEED_NORMAL;
557 m_caching = CACHESTATE_DONE;
563 m_last_check_time = 0.0;
566 memset(&m_SpeedState, 0, sizeof(m_SpeedState));
568 #ifdef DVDDEBUG_MESSAGE_TRACKER
569 g_dvdMessageTracker.Init();
573 COMXPlayer::~COMXPlayer()
577 #ifdef DVDDEBUG_MESSAGE_TRACKER
578 g_dvdMessageTracker.DeInit();
582 bool COMXPlayer::OpenFile(const CFileItem &file, const CPlayerOptions &options)
586 CLog::Log(LOGNOTICE, "COMXPlayer: Opening: %s", CURL::GetRedacted(file.GetPath()).c_str());
588 // if playing a file close it first
589 // this has to be changed so we won't have to close it.
593 m_bAbortRequest = false;
595 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
598 m_UpdateApplication = 0;
601 m_PlayerOptions = options;
603 m_mimetype = file.GetMimeType();
604 m_filename = file.GetPath();
608 #if defined(HAS_VIDEO_PLAYBACK)
609 g_renderManager.PreInit();
613 if(!m_ready.WaitMSec(g_advancedSettings.m_videoBusyDialogDelay_ms))
615 CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY);
619 while(!m_ready.WaitMSec(1))
620 g_windowManager.ProcessRenderLoop(false);
625 // Playback might have been stopped due to some error
626 if (m_bStop || m_bAbortRequest)
633 CLog::Log(LOGERROR, "%s - Exception thrown on open", __FUNCTION__);
638 bool COMXPlayer::CloseFile()
640 CLog::Log(LOGDEBUG, "COMXPlayer::CloseFile");
642 // set the abort request so that other threads can finish up
643 m_bAbortRequest = true;
645 // tell demuxer to abort
649 if(m_pSubtitleDemuxer)
650 m_pSubtitleDemuxer->Abort();
653 m_pInputStream->Abort();
655 CLog::Log(LOGDEBUG, "COMXPlayer: waiting for threads to exit");
657 // wait for the main thread to finish up
658 // since this main thread cleans up all other resources and threads
659 // we are done after the StopThread call
663 m_EdlAutoSkipMarkers.Clear();
668 CLog::Log(LOGNOTICE, "DVDPlayer: finished waiting");
669 #if defined(HAS_VIDEO_PLAYBACK)
670 g_renderManager.UnInit();
675 bool COMXPlayer::IsPlaying() const
680 void COMXPlayer::OnStartup()
682 m_CurrentVideo.Clear();
683 m_CurrentAudio.Clear();
684 m_CurrentSubtitle.Clear();
685 m_CurrentTeletext.Clear();
689 CUtil::ClearTempFonts();
692 bool COMXPlayer::OpenInputStream()
695 SAFE_DELETE(m_pInputStream);
697 CLog::Log(LOGNOTICE, "Creating InputStream");
699 // correct the filename if needed
700 CStdString filename(m_filename);
701 if (filename.Find("dvd://") == 0
702 || filename.CompareNoCase("iso9660://video_ts/video_ts.ifo") == 0)
704 m_filename = g_mediaManager.TranslateDevicePath("");
707 // before creating the input stream, if this is an HLS playlist then get the
708 // most appropriate bitrate based on our network settings
709 // ensure to strip off the url options by using a temp CURL object
710 if (filename.Left(7) == "http://" && CURL(filename).GetFileName().Right(5) == ".m3u8")
712 // get the available bandwidth (as per user settings)
713 int maxrate = CSettings::Get().GetInt("network.bandwidth");
717 // determine the most appropriate stream
718 m_filename = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(m_filename, (size_t)maxrate);
720 m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_filename, m_mimetype);
721 if(m_pInputStream == NULL)
723 CLog::Log(LOGERROR, "COMXPlayer::OpenInputStream - unable to create input stream for [%s]", m_filename.c_str());
727 m_pInputStream->SetFileItem(m_item);
729 if (!m_pInputStream->Open(m_filename.c_str(), m_mimetype))
731 CLog::Log(LOGERROR, "COMXPlayer::OpenInputStream - error opening [%s]", m_filename.c_str());
735 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
736 || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY))
738 CLog::Log(LOGINFO, "COMXPlayer::OpenInputStream - DVD/BD not supported - Will try...");
741 // find any available external subtitles for non dvd files
742 if (!m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
743 && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)
744 && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV)
745 && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP))
747 // find any available external subtitles
748 std::vector<CStdString> filenames;
749 CUtil::ScanForExternalSubtitles( m_filename, filenames );
751 // find any upnp subtitles
752 CStdString key("upnp:subtitle:1");
753 for(unsigned s = 1; m_item.HasProperty(key); key = StringUtils::Format("upnp:subtitle:%u", ++s))
754 filenames.push_back(m_item.GetProperty(key).asString());
756 for(unsigned int i=0;i<filenames.size();i++)
758 // if vobsub subtitle:
759 if (URIUtils::HasExtension(filenames[i], ".idx"))
761 CStdString strSubFile;
762 if ( CUtil::FindVobSubPair( filenames, filenames[i], strSubFile ) )
763 AddSubtitleFile(filenames[i], strSubFile);
767 if ( !CUtil::IsVobSub(filenames, filenames[i] ) )
769 AddSubtitleFile(filenames[i]);
772 } // end loop over all subtitle files
774 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true;
777 SetAVDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay);
778 SetSubTitleDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay);
782 m_ChannelEntryTimeOut.SetInfinite();
787 bool COMXPlayer::OpenDemuxStream()
790 SAFE_DELETE(m_pDemuxer);
792 CLog::Log(LOGNOTICE, "Creating Demuxer");
797 while(!m_bStop && attempts-- > 0)
799 m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
800 if(!m_pDemuxer && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
804 else if(!m_pDemuxer && m_pInputStream->NextStream() != CDVDInputStream::NEXTSTREAM_NONE)
806 CLog::Log(LOGDEBUG, "%s - New stream available from input, retry open", __FUNCTION__);
814 CLog::Log(LOGERROR, "%s - Error creating demuxer", __FUNCTION__);
821 CLog::Log(LOGERROR, "%s - Exception thrown when opening demuxer", __FUNCTION__);
825 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
826 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV);
827 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
829 int64_t len = m_pInputStream->GetLength();
830 int64_t tim = m_pDemuxer->GetStreamLength();
831 if(len > 0 && tim > 0)
832 m_pInputStream->SetReadRate(g_advancedSettings.m_readBufferFactor * len * 1000 / tim);
837 void COMXPlayer::OpenDefaultStreams(bool reset)
839 // if input stream dictate, we will open later
840 if(m_dvd.iSelectedAudioStream >= 0
841 || m_dvd.iSelectedSPUStream >= 0)
844 OMXSelectionStreams streams;
848 streams = m_SelectionStreams.Get(STREAM_VIDEO, PredicateVideoPriority);
850 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
852 if(OpenVideoStream(it->id, it->source, reset))
856 CloseVideoStream(true);
859 if(m_PlayerOptions.video_only)
862 streams = m_SelectionStreams.Get(STREAM_AUDIO, PredicateAudioPriority);
865 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
867 if(OpenAudioStream(it->id, it->source, reset))
871 CloseAudioStream(true);
874 m_omxPlayerVideo.EnableSubtitle(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn);
876 // open subtitle stream
877 OMXSelectionStream as = m_SelectionStreams.Get(STREAM_AUDIO, GetAudioStream());
878 PredicateSubtitleFilter psf(as.language);
879 streams = m_SelectionStreams.RemoveIf(STREAM_SUBTITLE, psf);
880 PredicateSubtitlePriority psp(as.language);
881 std::stable_sort(streams.begin(), streams.end(), psp);
883 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
885 if(OpenSubtitleStream(it->id, it->source))
888 if(it->flags & CDemuxStream::FLAG_FORCED)
889 m_omxPlayerVideo.EnableSubtitle(true);
894 CloseSubtitleStream(true);
895 SetSubtitleVisible(false);
898 // open teletext stream
899 streams = m_SelectionStreams.Get(STREAM_TELETEXT);
901 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
903 if(OpenTeletextStream(it->id, it->source))
907 CloseTeletextStream(true);
910 bool COMXPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
913 // check if we should read from subtitle demuxer
914 if( m_pSubtitleDemuxer && m_dvdPlayerSubtitle.AcceptsData() )
916 packet = m_pSubtitleDemuxer->Read();
920 UpdateCorrection(packet, m_offset_pts);
921 if(packet->iStreamId < 0)
924 stream = m_pSubtitleDemuxer->GetStream(packet->iStreamId);
927 CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__);
930 if(stream->source == STREAM_SOURCE_NONE)
932 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX_SUB);
933 m_SelectionStreams.Update(NULL, m_pSubtitleDemuxer);
939 // read a data frame from stream.
941 packet = m_pDemuxer->Read();
945 // stream changed, update and open defaults
946 if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE)
948 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
949 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
950 OpenDefaultStreams(false);
952 // reevaluate HasVideo/Audio, we may have switched from/to a radio channel
953 if(m_CurrentVideo.id < 0)
955 if(m_CurrentAudio.id < 0)
961 UpdateCorrection(packet, m_offset_pts);
963 if(packet->iStreamId < 0)
968 stream = m_pDemuxer->GetStream(packet->iStreamId);
971 CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__);
974 if(stream->source == STREAM_SOURCE_NONE)
976 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
977 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
985 bool COMXPlayer::IsValidStream(COMXCurrentStream& stream)
988 return true; // we consider non selected as valid
990 int source = STREAM_SOURCE_MASK(stream.source);
991 if(source == STREAM_SOURCE_TEXT)
993 if(source == STREAM_SOURCE_DEMUX_SUB)
995 CDemuxStream* st = m_pSubtitleDemuxer->GetStream(stream.id);
996 if(st == NULL || st->disabled)
998 if(st->type != stream.type)
1002 if(source == STREAM_SOURCE_DEMUX)
1004 CDemuxStream* st = m_pDemuxer->GetStream(stream.id);
1005 if(st == NULL || st->disabled)
1007 if(st->type != stream.type)
1010 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
1012 if(stream.type == STREAM_AUDIO && st->iPhysicalId != m_dvd.iSelectedAudioStream)
1014 if(stream.type == STREAM_SUBTITLE && st->iPhysicalId != m_dvd.iSelectedSPUStream)
1024 bool COMXPlayer::IsBetterStream(COMXCurrentStream& current, CDemuxStream* stream)
1026 // Do not reopen non-video streams if we're in video-only mode
1027 if(m_PlayerOptions.video_only && current.type != STREAM_VIDEO)
1030 if(stream->disabled)
1033 if (m_pInputStream && ( m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
1034 || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY) ) )
1038 source_type = STREAM_SOURCE_MASK(current.source);
1039 if(source_type != STREAM_SOURCE_DEMUX
1040 && source_type != STREAM_SOURCE_NONE)
1043 source_type = STREAM_SOURCE_MASK(stream->source);
1044 if(source_type != STREAM_SOURCE_DEMUX
1045 || stream->type != current.type
1046 || stream->iId == current.id)
1049 if(current.type == STREAM_AUDIO && stream->iPhysicalId == m_dvd.iSelectedAudioStream)
1051 if(current.type == STREAM_SUBTITLE && stream->iPhysicalId == m_dvd.iSelectedSPUStream)
1053 if(current.type == STREAM_VIDEO && current.id < 0)
1058 if(stream->source == current.source
1059 && stream->iId == current.id)
1062 if(stream->type != current.type)
1065 if(current.type == STREAM_SUBTITLE)
1074 void COMXPlayer::Process()
1076 bool bOmxWaitVideo = false;
1077 bool bOmxWaitAudio = false;
1078 bool bOmxSentEOFs = false;
1079 float m_threshold = 0.2f;
1081 if (!OpenInputStream())
1083 m_bAbortRequest = true;
1087 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
1089 CLog::Log(LOGNOTICE, "OMXPlayer: playing a file with menu's");
1090 m_PlayerOptions.starttime = 0;
1092 if(m_PlayerOptions.state.size() > 0)
1093 ptr->SetState(m_PlayerOptions.state);
1094 else if(CDVDInputStreamNavigator* nav = dynamic_cast<CDVDInputStreamNavigator*>(m_pInputStream))
1095 nav->EnableSubtitleStream(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn);
1097 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true;
1100 if(!OpenDemuxStream())
1102 m_bAbortRequest = true;
1106 // allow renderer to switch to fullscreen if requested
1107 m_omxPlayerVideo.EnableFullscreen(m_PlayerOptions.fullscreen);
1109 if(!m_av_clock.OMXInitialize(&m_clock))
1111 m_bAbortRequest = true;
1114 if(CSettings::Get().GetBool("videoplayer.adjustrefreshrate"))
1115 m_av_clock.HDMIClockSync();
1116 m_av_clock.OMXStateIdle();
1117 m_av_clock.OMXStop();
1118 m_av_clock.OMXPause();
1120 OpenDefaultStreams();
1122 // look for any EDL files
1124 m_EdlAutoSkipMarkers.Clear();
1125 if (m_CurrentVideo.id >= 0 && m_CurrentVideo.hint.fpsrate > 0 && m_CurrentVideo.hint.fpsscale > 0)
1127 float fFramesPerSecond = (float)m_CurrentVideo.hint.fpsrate / (float)m_CurrentVideo.hint.fpsscale;
1128 m_Edl.ReadEditDecisionLists(m_filename, fFramesPerSecond, m_CurrentVideo.hint.height);
1132 * Check to see if the demuxer should start at something other than time 0. This will be the case
1133 * if there was a start time specified as part of the "Start from where last stopped" (aka
1134 * auto-resume) feature or if there is an EDL cut or commercial break that starts at time 0.
1138 if(m_PlayerOptions.starttime > 0 || m_PlayerOptions.startpercent > 0)
1140 if (m_PlayerOptions.startpercent > 0 && m_pDemuxer)
1142 int64_t playerStartTime = (int64_t) ( ( (float) m_pDemuxer->GetStreamLength() ) * ( m_PlayerOptions.startpercent/(float)100 ) );
1143 starttime = m_Edl.RestoreCutTime(playerStartTime);
1147 starttime = m_Edl.RestoreCutTime((int64_t)m_PlayerOptions.starttime * 1000); // s to ms
1149 CLog::Log(LOGDEBUG, "%s - Start position set to last stopped position: %d", __FUNCTION__, starttime);
1151 else if(m_Edl.InCut(0, &cut)
1152 && (cut.action == CEdl::CUT || cut.action == CEdl::COMM_BREAK))
1154 starttime = cut.end;
1155 CLog::Log(LOGDEBUG, "%s - Start position set to end of first cut or commercial break: %d", __FUNCTION__, starttime);
1156 if(cut.action == CEdl::COMM_BREAK)
1159 * Setup auto skip markers as if the commercial break had been skipped using standard
1162 m_EdlAutoSkipMarkers.commbreak_start = cut.start;
1163 m_EdlAutoSkipMarkers.commbreak_end = cut.end;
1164 m_EdlAutoSkipMarkers.seek_to_start = true;
1169 double startpts = DVD_NOPTS_VALUE;
1172 if (m_pDemuxer->SeekTime(starttime, false, &startpts))
1173 CLog::Log(LOGDEBUG, "%s - starting demuxer from: %d", __FUNCTION__, starttime);
1175 CLog::Log(LOGDEBUG, "%s - failed to start demuxing from: %d", __FUNCTION__, starttime);
1178 if(m_pSubtitleDemuxer)
1180 if(m_pSubtitleDemuxer->SeekTime(starttime, false, &startpts))
1181 CLog::Log(LOGDEBUG, "%s - starting subtitle demuxer from: %d", __FUNCTION__, starttime);
1183 CLog::Log(LOGDEBUG, "%s - failed to start subtitle demuxing from: %d", __FUNCTION__, starttime);
1187 // make sure all selected stream have data on startup
1188 if (CachePVRStream())
1189 SetCaching(CACHESTATE_PVR);
1191 // make sure application know our info
1192 UpdateApplication(0);
1195 if(m_PlayerOptions.identify == false)
1196 m_callback.OnPlayBackStarted();
1198 // we are done initializing now, set the readyevent
1201 if (!CachePVRStream())
1202 SetCaching(CACHESTATE_FLUSH);
1204 EDEINTERLACEMODE current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1206 while (!m_bAbortRequest)
1208 double now = m_clock.GetAbsoluteClock();
1209 if (m_last_check_time == 0.0 || m_last_check_time + DVD_MSEC_TO_TIME(20) <= now)
1211 m_last_check_time = now;
1212 m_stamp = m_av_clock.OMXMediaTime();
1213 const bool m_Pause = m_playSpeed == DVD_PLAYSPEED_PAUSE;
1214 const bool not_accepts_data = (!m_omxPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) ||
1215 (!m_omxPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0);
1216 /* when the video/audio fifos are low, we pause clock, when high we resume */
1217 double audio_pts = floor(m_omxPlayerAudio.GetCurrentPts());
1218 double video_pts = floor(m_omxPlayerVideo.GetCurrentPts());
1220 float audio_fifo = audio_pts / DVD_TIME_BASE - m_stamp * 1e-6;
1221 float video_fifo = video_pts / DVD_TIME_BASE - m_stamp * 1e-6;
1222 float threshold = 0.1f;
1223 bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;
1225 // if deinterlace setting has changed, we should close and open video
1226 if (current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode)
1228 int iStream = m_CurrentVideo.id, source = m_CurrentVideo.source;
1229 CloseVideoStream(false);
1230 OpenVideoStream(iStream, source);
1231 if (m_State.canseek)
1232 m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true));
1233 current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1236 m_video_fifo = (int)(100.0*(m_omxPlayerVideo.GetDecoderBufferSize()-m_omxPlayerVideo.GetDecoderFreeSpace())/m_omxPlayerVideo.GetDecoderBufferSize());
1237 m_audio_fifo = (int)(100.0*audio_fifo/m_omxPlayerAudio.GetCacheTotal());
1240 static unsigned count;
1241 if ((count++ & 7) == 0)
1244 if (m_omxPlayerVideo.GetDecoderBufferSize() && m_omxPlayerAudio.GetCacheTotal())
1245 vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
1247 (int)(100.0*video_fifo/m_omxPlayerAudio.GetCacheTotal()),
1249 if (m_omxPlayerAudio.GetCacheTotal())
1250 vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
1252 (int)(100.0*m_omxPlayerAudio.GetDelay()/m_omxPlayerAudio.GetCacheTotal()),
1254 vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d",
1255 m_omxPlayerVideo.GetLevel(), 0, 0, 100);
1256 vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d",
1257 m_omxPlayerAudio.GetLevel(), 0, 0, 100);
1260 if (audio_pts != DVD_NOPTS_VALUE)
1262 audio_fifo_low = m_HasAudio && audio_fifo < threshold;
1263 audio_fifo_high = audio_pts != DVD_NOPTS_VALUE && audio_fifo >= m_threshold;
1265 if (video_pts != DVD_NOPTS_VALUE)
1267 video_fifo_low = m_HasVideo && video_fifo < threshold;
1268 video_fifo_high = video_pts != DVD_NOPTS_VALUE && video_fifo >= m_threshold;
1270 if (!m_HasAudio && m_HasVideo)
1271 audio_fifo_high = true;
1272 if (!m_HasVideo && m_HasAudio)
1273 video_fifo_high = true;
1276 CLog::Log(LOGDEBUG, "%s - M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", __FUNCTION__,
1277 m_stamp*1e-6, m_av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6, m_av_clock.OMXIsPaused(), bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL),
1278 audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_threshold,
1279 audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high,
1280 m_omxPlayerAudio.GetLevel(), m_omxPlayerVideo.GetLevel(), m_omxPlayerAudio.GetDelay(), (float)m_omxPlayerAudio.GetCacheTotal());
1283 if (TP(m_playSpeed))
1285 if (m_CurrentVideo.started)
1287 if (m_stamp == 0.0 && (!m_stepped || m_playSpeed > 0))
1289 /* trickplay modes progress by stepping */
1290 CLog::Log(LOGDEBUG, "COMXPlayer::Process - Seeking step speed:%.2f last:%.2f v:%.2f", (double)m_playSpeed / DVD_PLAYSPEED_NORMAL, m_SpeedState.lastpts*1e-6, video_pts*1e-6);
1291 m_av_clock.OMXStep();
1295 m_av_clock.OMXMediaTime(0.0);
1296 m_last_check_time = 0.0;
1301 else if(!m_Pause && (bOmxSentEOFs || not_accepts_data || (audio_fifo_high && video_fifo_high)))
1303 if (m_av_clock.OMXIsPaused())
1305 CLog::Log(LOGDEBUG, "Resume %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f\n", audio_fifo, video_fifo,
1306 audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, bOmxSentEOFs, not_accepts_data, m_threshold);
1307 m_av_clock.OMXStateExecute();
1308 m_av_clock.OMXResume();
1311 else if (m_Pause || audio_fifo_low || video_fifo_low)
1313 if (!m_av_clock.OMXIsPaused() && !TPA(m_playSpeed))
1316 m_threshold = std::min(2.0f*m_threshold, 16.0f);
1317 CLog::Log(LOGDEBUG, "Pause %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f\n", audio_fifo, video_fifo,
1318 audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, bOmxSentEOFs, not_accepts_data, m_threshold);
1319 m_av_clock.OMXPause();
1328 // should we open a new input stream?
1331 if (OpenInputStream() == false)
1333 CLog::Log(LOGERROR, "%s - Closing stream due to OpenInputStream()", __FUNCTION__);
1334 m_bAbortRequest = true;
1339 // should we open a new demuxer?
1342 if (m_pInputStream->NextStream() == CDVDInputStream::NEXTSTREAM_NONE)
1345 if (m_pInputStream->IsEOF())
1348 if (OpenDemuxStream() == false)
1350 CLog::Log(LOGERROR, "%s - Closing stream due to OpenDemuxStream()", __FUNCTION__);
1351 m_bAbortRequest = true;
1355 OpenDefaultStreams();
1357 // never allow first frames after open to be skipped
1358 if( m_omxPlayerVideo.IsInited() )
1359 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP));
1361 if (CachePVRStream())
1362 SetCaching(CACHESTATE_PVR);
1364 UpdateApplication(0);
1368 // handle eventual seeks due to playspeed
1371 // update player state
1372 UpdatePlayState(200);
1374 // update application with our state
1375 UpdateApplication(1000);
1377 // make sure we run subtitle process here
1378 m_dvdPlayerSubtitle.Process(m_clock.GetClock() - m_omxPlayerVideo.GetSubtitleDelay());
1380 // OMX emergency exit
1381 if(HasAudio() && m_omxPlayerAudio.BadState())
1383 CLog::Log(LOGERROR, "%s - Closing stream due to m_omxPlayerAudio.BadState()", __FUNCTION__);
1384 m_bAbortRequest = true;
1388 if (CheckDelayedChannelEntry())
1391 // if the queues are full, no need to read more
1392 if ((!m_omxPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) ||
1393 (!m_omxPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0))
1399 // always yield to players if they have data levels > 50 percent
1400 if((m_omxPlayerAudio.GetLevel() > 50 || m_CurrentAudio.id < 0)
1401 && (m_omxPlayerVideo.GetLevel() > 50 || m_CurrentVideo.id < 0))
1404 DemuxPacket* pPacket = NULL;
1405 CDemuxStream *pStream = NULL;
1406 ReadPacket(pPacket, pStream);
1407 if (pPacket && !pStream)
1409 /* probably a empty packet, just free it and move on */
1410 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
1415 // reset eos state when we get a packet (e.g. for case of seek after eos)
1416 bOmxWaitVideo = false;
1417 bOmxWaitAudio = false;
1418 bOmxSentEOFs = false;
1422 // when paused, demuxer could be be returning empty
1423 if (m_playSpeed == DVD_PLAYSPEED_PAUSE)
1426 // check for a still frame state
1427 if (CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
1429 // stills will be skipped
1430 if(m_dvd.state == DVDSTATE_STILL)
1432 if (m_dvd.iDVDStillTime > 0)
1434 if ((XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime) >= m_dvd.iDVDStillTime)
1436 m_dvd.iDVDStillTime = 0;
1437 m_dvd.iDVDStillStartTime = 0;
1438 m_dvd.state = DVDSTATE_NORMAL;
1439 pStream->SkipStill();
1446 // if there is another stream available, reopen demuxer
1447 CDVDInputStream::ENextStream next = m_pInputStream->NextStream();
1448 if(next == CDVDInputStream::NEXTSTREAM_OPEN)
1450 SAFE_DELETE(m_pDemuxer);
1451 m_CurrentAudio.stream = NULL;
1452 m_CurrentVideo.stream = NULL;
1453 m_CurrentSubtitle.stream = NULL;
1457 // input stream asked us to just retry
1458 if(next == CDVDInputStream::NEXTSTREAM_RETRY)
1464 // make sure we tell all players to finish it's data
1467 if(m_CurrentAudio.inited)
1469 m_omxPlayerAudio.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF));
1470 bOmxWaitAudio = true;
1472 if(m_CurrentVideo.inited)
1474 m_omxPlayerVideo.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF));
1475 bOmxWaitVideo = true;
1477 if(m_CurrentSubtitle.inited)
1478 m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF));
1479 if(m_CurrentTeletext.inited)
1480 m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF));
1481 m_CurrentAudio.inited = false;
1482 m_CurrentVideo.inited = false;
1483 m_CurrentSubtitle.inited = false;
1484 m_CurrentTeletext.inited = false;
1485 bOmxSentEOFs = true;
1488 // if we are caching, start playing it again
1489 SetCaching(CACHESTATE_DONE);
1491 // while players are still playing, keep going to allow seekbacks
1492 if(m_omxPlayerVideo.HasData()
1493 || m_omxPlayerAudio.HasData())
1499 // wait for omx components to finish
1500 if(bOmxWaitVideo && !m_omxPlayerVideo.IsEOS())
1505 if(bOmxWaitAudio && !m_omxPlayerAudio.IsEOS())
1511 if (!m_pInputStream->IsEOF())
1512 CLog::Log(LOGINFO, "%s - eof reading from demuxer", __FUNCTION__);
1514 m_CurrentAudio.started = false;
1515 m_CurrentVideo.started = false;
1516 m_CurrentSubtitle.started = false;
1517 m_CurrentTeletext.started = false;
1522 // it's a valid data packet, reset error counter
1525 // check so that none of our streams has become invalid
1526 if (!IsValidStream(m_CurrentAudio) && m_omxPlayerAudio.IsStalled()) CloseAudioStream(true);
1527 if (!IsValidStream(m_CurrentVideo) && m_omxPlayerVideo.IsStalled()) CloseVideoStream(true);
1528 if (!IsValidStream(m_CurrentSubtitle) && m_dvdPlayerSubtitle.IsStalled()) CloseSubtitleStream(true);
1529 if (!IsValidStream(m_CurrentTeletext)) CloseTeletextStream(true);
1531 // see if we can find something better to play
1532 if (IsBetterStream(m_CurrentAudio, pStream)) OpenAudioStream (pStream->iId, pStream->source);
1533 if (IsBetterStream(m_CurrentVideo, pStream)) OpenVideoStream (pStream->iId, pStream->source);
1534 if (IsBetterStream(m_CurrentSubtitle, pStream)) OpenSubtitleStream(pStream->iId, pStream->source);
1535 if (IsBetterStream(m_CurrentTeletext, pStream)) OpenTeletextStream(pStream->iId, pStream->source);
1537 // process the packet
1538 ProcessPacket(pStream, pPacket);
1540 // check if in a cut or commercial break that should be automatically skipped
1541 CheckAutoSceneSkip();
1545 bool COMXPlayer::CheckDelayedChannelEntry(void)
1547 bool bReturn(false);
1549 if (m_ChannelEntryTimeOut.IsTimePast())
1551 CFileItem currentFile(g_application.CurrentFileItem());
1552 CPVRChannel *currentChannel = currentFile.GetPVRChannelInfoTag();
1553 SwitchChannel(*currentChannel);
1556 m_ChannelEntryTimeOut.SetInfinite();
1562 void COMXPlayer::ProcessPacket(CDemuxStream* pStream, DemuxPacket* pPacket)
1564 /* process packet if it belongs to selected stream. for dvd's don't allow automatic opening of streams*/
1565 OMXStreamLock lock(this);
1569 if (pPacket->iStreamId == m_CurrentAudio.id && pStream->source == m_CurrentAudio.source && pStream->type == STREAM_AUDIO)
1570 ProcessAudioData(pStream, pPacket);
1571 else if (pPacket->iStreamId == m_CurrentVideo.id && pStream->source == m_CurrentVideo.source && pStream->type == STREAM_VIDEO)
1572 ProcessVideoData(pStream, pPacket);
1573 else if (pPacket->iStreamId == m_CurrentSubtitle.id && pStream->source == m_CurrentSubtitle.source && pStream->type == STREAM_SUBTITLE)
1574 ProcessSubData(pStream, pPacket);
1575 else if (pPacket->iStreamId == m_CurrentTeletext.id && pStream->source == m_CurrentTeletext.source && pStream->type == STREAM_TELETEXT)
1576 ProcessTeletextData(pStream, pPacket);
1579 pStream->SetDiscard(AVDISCARD_ALL);
1580 CDVDDemuxUtils::FreeDemuxPacket(pPacket); // free it since we won't do anything with it
1585 CLog::Log(LOGERROR, "%s - Exception thrown when processing demux packet", __FUNCTION__);
1590 void COMXPlayer::ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket)
1592 if (m_CurrentAudio.stream != (void*)pStream
1593 || m_CurrentAudio.changes != pStream->changes)
1595 /* check so that dmuxer hints or extra data hasn't changed */
1596 /* if they have, reopen stream */
1598 if (m_CurrentAudio.hint != CDVDStreamInfo(*pStream, true))
1599 OpenAudioStream( pPacket->iStreamId, pStream->source );
1601 m_CurrentAudio.stream = (void*)pStream;
1602 m_CurrentAudio.changes = pStream->changes;
1605 // check if we are too slow and need to recache
1606 CheckStartCaching(m_CurrentAudio);
1608 CheckContinuity(m_CurrentAudio, pPacket);
1609 UpdateTimestamps(m_CurrentAudio, pPacket);
1612 if (CheckPlayerInit(m_CurrentAudio, DVDPLAYER_AUDIO))
1616 * If CheckSceneSkip() returns true then demux point is inside an EDL cut and the packets are dropped.
1617 * If not inside a hard cut, but the demux point has reached an EDL mute section then trigger the
1618 * AUDIO_SILENCE state. The AUDIO_SILENCE state is reverted as soon as the demux point is outside
1619 * of any EDL section while EDL mute is still active.
1622 if (CheckSceneSkip(m_CurrentAudio))
1624 else if (m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) && cut.action == CEdl::MUTE // Inside EDL mute
1625 && !m_EdlAutoSkipMarkers.mute) // Mute not already triggered
1627 m_omxPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, true));
1628 m_EdlAutoSkipMarkers.mute = true;
1630 else if (!m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) // Outside of any EDL
1631 && m_EdlAutoSkipMarkers.mute) // But the mute hasn't been removed yet
1633 m_omxPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, false));
1634 m_EdlAutoSkipMarkers.mute = false;
1637 m_omxPlayerAudio.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1640 void COMXPlayer::ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket)
1642 if (m_CurrentVideo.stream != (void*)pStream
1643 || m_CurrentVideo.changes != pStream->changes)
1645 /* check so that dmuxer hints or extra data hasn't changed */
1646 /* if they have reopen stream */
1648 if (m_CurrentVideo.hint != CDVDStreamInfo(*pStream, true))
1649 OpenVideoStream(pPacket->iStreamId, pStream->source);
1651 m_CurrentVideo.stream = (void*)pStream;
1652 m_CurrentVideo.changes = pStream->changes;
1655 // check if we are too slow and need to recache
1656 CheckStartCaching(m_CurrentVideo);
1658 if( pPacket->iSize != 4) //don't check the EOF_SEQUENCE of stillframes
1660 CheckContinuity(m_CurrentVideo, pPacket);
1661 UpdateTimestamps(m_CurrentVideo, pPacket);
1665 if (CheckPlayerInit(m_CurrentVideo, DVDPLAYER_VIDEO))
1668 if (CheckSceneSkip(m_CurrentVideo))
1671 m_omxPlayerVideo.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1674 void COMXPlayer::ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket)
1676 if (m_CurrentSubtitle.stream != (void*)pStream
1677 || m_CurrentSubtitle.changes != pStream->changes)
1679 /* check so that dmuxer hints or extra data hasn't changed */
1680 /* if they have reopen stream */
1682 if (m_CurrentSubtitle.hint != CDVDStreamInfo(*pStream, true))
1683 OpenSubtitleStream(pPacket->iStreamId, pStream->source);
1685 m_CurrentSubtitle.stream = (void*)pStream;
1686 m_CurrentSubtitle.changes = pStream->changes;
1689 UpdateTimestamps(m_CurrentSubtitle, pPacket);
1692 if (CheckPlayerInit(m_CurrentSubtitle, DVDPLAYER_SUBTITLE))
1695 if (CheckSceneSkip(m_CurrentSubtitle))
1698 m_dvdPlayerSubtitle.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1700 if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
1701 m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL);
1704 void COMXPlayer::ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket)
1706 if (m_CurrentTeletext.stream != (void*)pStream
1707 || m_CurrentTeletext.changes != pStream->changes)
1709 /* check so that dmuxer hints or extra data hasn't changed */
1710 /* if they have, reopen stream */
1711 if (m_CurrentTeletext.hint != CDVDStreamInfo(*pStream, true))
1712 OpenTeletextStream( pPacket->iStreamId, pStream->source );
1714 m_CurrentTeletext.stream = (void*)pStream;
1715 m_CurrentTeletext.changes = pStream->changes;
1717 UpdateTimestamps(m_CurrentTeletext, pPacket);
1720 if (CheckPlayerInit(m_CurrentTeletext, DVDPLAYER_TELETEXT))
1723 if (CheckSceneSkip(m_CurrentTeletext))
1726 m_dvdPlayerTeletext.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1729 bool COMXPlayer::GetCachingTimes(double& level, double& delay, double& offset)
1731 if(!m_pInputStream || !m_pDemuxer)
1734 XFILE::SCacheStatus status;
1735 if (!m_pInputStream->GetCacheStatus(&status))
1738 int64_t cached = status.forward;
1739 unsigned currate = status.currate;
1740 unsigned maxrate = status.maxrate;
1741 bool full = status.full;
1743 int64_t length = m_pInputStream->GetLength();
1744 int64_t remain = length - m_pInputStream->Seek(0, SEEK_CUR);
1746 if(cached < 0 || length <= 0 || remain < 0)
1749 double play_sbp = DVD_MSEC_TO_TIME(m_pDemuxer->GetStreamLength()) / length;
1750 double queued = 1000.0 * GetQueueTime() / play_sbp;
1754 offset = (double)(cached + queued) / length;
1759 double cache_sbp = 1.1 * (double)DVD_TIME_BASE / currate; /* underestimate by 10 % */
1760 double play_left = play_sbp * (remain + queued); /* time to play out all remaining bytes */
1761 double cache_left = cache_sbp * (remain - cached); /* time to cache the remaining bytes */
1762 double cache_need = std::max(0.0, remain - play_left / cache_sbp); /* bytes needed until play_left == cache_left */
1764 delay = cache_left - play_left;
1766 if (full && (currate < maxrate) )
1767 level = -1.0; /* buffer is full & our read rate is too low */
1769 level = (cached + queued) / (cache_need + queued);
1774 void COMXPlayer::HandlePlaySpeed()
1776 ECacheState caching = m_caching;
1778 if(IsInMenu() && caching != CACHESTATE_DONE)
1779 caching = CACHESTATE_DONE;
1781 if(caching == CACHESTATE_FULL)
1783 double level, delay, offset;
1784 if(GetCachingTimes(level, delay, offset))
1788 CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(21454), g_localizeStrings.Get(21455));
1789 caching = CACHESTATE_INIT;
1792 caching = CACHESTATE_INIT;
1796 if ((!m_omxPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0)
1797 || (!m_omxPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0))
1798 caching = CACHESTATE_INIT;
1802 if(caching == CACHESTATE_INIT)
1804 // if all enabled streams have been inited we are done
1805 if((m_CurrentVideo.id < 0 || m_CurrentVideo.started)
1806 && (m_CurrentAudio.id < 0 || m_CurrentAudio.started))
1807 caching = CACHESTATE_PLAY;
1809 // handle situation that we get no data on one stream
1810 if(m_CurrentAudio.id >= 0 && m_CurrentVideo.id >= 0)
1812 if ((!m_omxPlayerAudio.AcceptsData() && !m_CurrentVideo.started)
1813 || (!m_omxPlayerVideo.AcceptsData() && !m_CurrentAudio.started))
1815 caching = CACHESTATE_DONE;
1820 if (caching == CACHESTATE_PVR)
1822 bool bGotAudio(m_pDemuxer->GetNrOfAudioStreams() > 0);
1823 bool bGotVideo(m_pDemuxer->GetNrOfVideoStreams() > 0);
1824 bool bAudioLevelOk(m_omxPlayerAudio.GetLevel() > g_advancedSettings.m_iPVRMinAudioCacheLevel);
1825 bool bVideoLevelOk(m_omxPlayerVideo.GetLevel() > g_advancedSettings.m_iPVRMinVideoCacheLevel);
1826 bool bAudioFull(!m_omxPlayerAudio.AcceptsData());
1827 bool bVideoFull(!m_omxPlayerVideo.AcceptsData());
1829 if (/* if all streams got at least g_advancedSettings.m_iPVRMinCacheLevel in their buffers, we're done */
1830 ((bGotVideo || bGotAudio) && (!bGotAudio || bAudioLevelOk) && (!bGotVideo || bVideoLevelOk)) ||
1831 /* or if one of the buffers is full */
1832 (bAudioFull || bVideoFull))
1834 CLog::Log(LOGDEBUG, "set caching from pvr to done. audio (%d) = %d. video (%d) = %d",
1835 bGotAudio, m_omxPlayerAudio.GetLevel(),
1836 bGotVideo, m_omxPlayerVideo.GetLevel());
1838 CFileItem currentItem(g_application.CurrentFileItem());
1839 if (currentItem.HasPVRChannelInfoTag())
1840 g_PVRManager.LoadCurrentChannelSettings();
1842 caching = CACHESTATE_DONE;
1846 /* ensure that automatically started players are stopped while caching */
1847 if (m_CurrentAudio.started)
1848 m_omxPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE);
1849 if (m_CurrentVideo.started)
1850 m_omxPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE);
1854 if(caching == CACHESTATE_PLAY)
1856 // if all enabled streams have started playing we are done
1857 if((m_CurrentVideo.id < 0 || !m_omxPlayerVideo.IsStalled())
1858 && (m_CurrentAudio.id < 0 || !m_omxPlayerAudio.IsStalled()))
1859 caching = CACHESTATE_DONE;
1862 if(m_caching != caching)
1863 SetCaching(caching);
1866 if(GetPlaySpeed() != DVD_PLAYSPEED_NORMAL && GetPlaySpeed() != DVD_PLAYSPEED_PAUSE)
1870 // this can't be done in menu
1871 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
1874 else if (m_CurrentVideo.id >= 0
1875 && m_CurrentVideo.inited == true
1876 && m_SpeedState.lastpts != m_omxPlayerVideo.GetCurrentPts()
1877 && m_SpeedState.lasttime != GetTime()
1880 m_SpeedState.lastpts = m_omxPlayerVideo.GetCurrentPts();
1881 m_SpeedState.lasttime = GetTime();
1882 // check how much off clock video is when ff/rw:ing
1883 // a problem here is that seeking isn't very accurate
1884 // and since the clock will be resynced after seek
1885 // we might actually not really be playing at the wanted
1886 // speed. we'd need to have some way to not resync the clock
1887 // after a seek to remember timing. still need to handle
1888 // discontinuities somehow
1890 // when seeking, give the player a headstart to make sure
1891 // the time it takes to seek doesn't make a difference.
1893 error = m_clock.GetClock() - m_SpeedState.lastpts;
1894 error *= m_playSpeed / abs(m_playSpeed);
1896 if(error > DVD_MSEC_TO_TIME(1000))
1898 CLog::Log(LOGDEBUG, "COMXPlayer::Process - Seeking to catch up");
1899 int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL);
1900 m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true));
1906 bool COMXPlayer::CheckStartCaching(COMXCurrentStream& current)
1908 if(m_caching != CACHESTATE_DONE
1909 || m_playSpeed != DVD_PLAYSPEED_NORMAL)
1915 if((current.type == STREAM_AUDIO && m_omxPlayerAudio.IsStalled())
1916 || (current.type == STREAM_VIDEO && m_omxPlayerVideo.IsStalled()))
1918 if (CachePVRStream())
1920 if ((current.type == STREAM_AUDIO && current.started && m_omxPlayerAudio.GetLevel() == 0) ||
1921 (current.type == STREAM_VIDEO && current.started && m_omxPlayerVideo.GetLevel() == 0))
1923 CLog::Log(LOGDEBUG, "%s stream stalled. start buffering", current.type == STREAM_AUDIO ? "audio" : "video");
1924 SetCaching(CACHESTATE_PVR);
1929 // don't start caching if it's only a single stream that has run dry
1930 if(m_omxPlayerAudio.GetLevel() > 50
1931 || m_omxPlayerVideo.GetLevel() > 50)
1935 SetCaching(CACHESTATE_FULL);
1937 SetCaching(CACHESTATE_INIT);
1943 bool COMXPlayer::CheckPlayerInit(COMXCurrentStream& current, unsigned int source)
1948 if(current.startpts != DVD_NOPTS_VALUE)
1950 if(current.dts == DVD_NOPTS_VALUE)
1952 CLog::Log(LOGDEBUG, "%s - dropping packet type:%d dts:%f to get to start point at %f", __FUNCTION__, source, current.dts, current.startpts);
1956 if((current.startpts - current.dts) > DVD_SEC_TO_TIME(20))
1958 CLog::Log(LOGDEBUG, "%s - too far to decode before finishing seek", __FUNCTION__);
1959 if(m_CurrentAudio.startpts != DVD_NOPTS_VALUE)
1960 m_CurrentAudio.startpts = current.dts;
1961 if(m_CurrentVideo.startpts != DVD_NOPTS_VALUE)
1962 m_CurrentVideo.startpts = current.dts;
1963 if(m_CurrentSubtitle.startpts != DVD_NOPTS_VALUE)
1964 m_CurrentSubtitle.startpts = current.dts;
1965 if(m_CurrentTeletext.startpts != DVD_NOPTS_VALUE)
1966 m_CurrentTeletext.startpts = current.dts;
1969 if(current.dts < current.startpts)
1971 CLog::Log(LOGDEBUG, "%s - dropping packet type:%d dts:%f to get to start point at %f", __FUNCTION__, source, current.dts, current.startpts);
1976 //If this is the first packet after a discontinuity, send it as a resync
1977 if (current.dts != DVD_NOPTS_VALUE)
1979 current.inited = true;
1980 current.startpts = current.dts;
1982 bool setclock = false;
1983 if(m_playSpeed == DVD_PLAYSPEED_NORMAL)
1985 if( source == DVDPLAYER_AUDIO)
1986 setclock = !m_CurrentVideo.inited;
1987 else if(source == DVDPLAYER_VIDEO)
1988 setclock = !m_CurrentAudio.inited;
1992 if(source == DVDPLAYER_VIDEO)
1996 double starttime = current.startpts;
1997 if(m_CurrentAudio.inited
1998 && m_CurrentAudio.startpts != DVD_NOPTS_VALUE
1999 && m_CurrentAudio.startpts < starttime)
2000 starttime = m_CurrentAudio.startpts;
2001 if(m_CurrentVideo.inited
2002 && m_CurrentVideo.startpts != DVD_NOPTS_VALUE
2003 && m_CurrentVideo.startpts < starttime)
2004 starttime = m_CurrentVideo.startpts;
2006 starttime = current.startpts - starttime;
2007 if(starttime > 0 && setclock)
2009 if(starttime > DVD_SEC_TO_TIME(2))
2010 CLog::Log(LOGWARNING, "COMXPlayer::CheckPlayerInit(%d) - Ignoring too large delay of %f", source, starttime);
2012 SendPlayerMessage(new CDVDMsgDouble(CDVDMsg::GENERAL_DELAY, starttime), source);
2015 SendPlayerMessage(new CDVDMsgGeneralResync(current.dts, setclock), source);
2020 void COMXPlayer::UpdateCorrection(DemuxPacket* pkt, double correction)
2022 //CLog::Log(LOGINFO,"%s: %d dts:%.0f pts:%.0f s:%d c:%.0f (%d,%d)", __func__, (int)pkt->iStreamId, pkt->dts, pkt->pts, pkt->iSize, correction, pkt->dts==DVD_NOPTS_VALUE, pkt->pts==DVD_NOPTS_VALUE);
2023 if(pkt->dts != DVD_NOPTS_VALUE) pkt->dts -= correction;
2024 if(pkt->pts != DVD_NOPTS_VALUE) pkt->pts -= correction;
2027 void COMXPlayer::UpdateTimestamps(COMXCurrentStream& current, DemuxPacket* pPacket)
2029 double dts = current.dts;
2030 /* update stored values */
2031 if(pPacket->dts != DVD_NOPTS_VALUE)
2033 else if(pPacket->pts != DVD_NOPTS_VALUE)
2036 /* calculate some average duration */
2037 if(pPacket->duration != DVD_NOPTS_VALUE)
2038 current.dur = pPacket->duration;
2039 else if(dts != DVD_NOPTS_VALUE && current.dts != DVD_NOPTS_VALUE)
2040 current.dur = 0.1 * (current.dur * 9 + (dts - current.dts));
2044 /* send a playback state structure periodically */
2045 if(current.dts_state == DVD_NOPTS_VALUE
2046 || abs(current.dts - current.dts_state) > DVD_MSEC_TO_TIME(200))
2048 current.dts_state = current.dts;
2052 // make sure we send no outdated state to a/v players
2054 SendPlayerMessage(new CDVDMsgType<SPlayerState>(CDVDMsg::PLAYER_DISPLAYTIME, m_StateInput), current.player);
2058 CSingleLock lock(m_StateSection);
2059 m_State = m_StateInput;
2064 static void UpdateLimits(double& minimum, double& maximum, double dts)
2066 if(dts == DVD_NOPTS_VALUE)
2068 if(minimum == DVD_NOPTS_VALUE || minimum > dts) minimum = dts;
2069 if(maximum == DVD_NOPTS_VALUE || maximum < dts) maximum = dts;
2072 void COMXPlayer::CheckContinuity(COMXCurrentStream& current, DemuxPacket* pPacket)
2074 if (m_playSpeed < DVD_PLAYSPEED_PAUSE)
2077 if( pPacket->dts == DVD_NOPTS_VALUE || current.dts == DVD_NOPTS_VALUE)
2080 double mindts = DVD_NOPTS_VALUE, maxdts = DVD_NOPTS_VALUE;
2081 UpdateLimits(mindts, maxdts, m_CurrentAudio.dts);
2082 UpdateLimits(mindts, maxdts, m_CurrentVideo.dts);
2083 UpdateLimits(mindts, maxdts, m_CurrentAudio.dts_end());
2084 UpdateLimits(mindts, maxdts, m_CurrentVideo.dts_end());
2086 /* if we don't have max and min, we can't do anything more */
2087 if( mindts == DVD_NOPTS_VALUE || maxdts == DVD_NOPTS_VALUE )
2090 double correction = 0.0;
2091 if( pPacket->dts > maxdts + DVD_MSEC_TO_TIME(1000))
2093 CLog::Log(LOGDEBUG, "COMXPlayer::CheckContinuity - resync forward :%d, prev:%f, curr:%f, diff:%f"
2094 , current.type, current.dts, pPacket->dts, pPacket->dts - maxdts);
2095 correction = pPacket->dts - maxdts;
2098 /* if it's large scale jump, correct for it */
2099 if(pPacket->dts + DVD_MSEC_TO_TIME(100) < current.dts_end())
2101 CLog::Log(LOGDEBUG, "COMXPlayer::CheckContinuity - resync backward :%d, prev:%f, curr:%f, diff:%f"
2102 , current.type, current.dts, pPacket->dts, pPacket->dts - current.dts);
2103 correction = pPacket->dts - current.dts_end();
2105 else if(pPacket->dts < current.dts)
2107 CLog::Log(LOGDEBUG, "COMXPlayer::CheckContinuity - wrapback :%d, prev:%f, curr:%f, diff:%f"
2108 , current.type, current.dts, pPacket->dts, pPacket->dts - current.dts);
2111 if(correction != 0.0)
2113 /* disable detection on next packet on other stream to avoid ping pong-ing */
2114 if(m_CurrentAudio.player != current.player) m_CurrentAudio.dts = DVD_NOPTS_VALUE;
2115 if(m_CurrentVideo.player != current.player) m_CurrentVideo.dts = DVD_NOPTS_VALUE;
2117 m_offset_pts += correction;
2118 UpdateCorrection(pPacket, correction);
2122 bool COMXPlayer::CheckSceneSkip(COMXCurrentStream& current)
2127 if(current.dts == DVD_NOPTS_VALUE)
2130 if(current.inited == false)
2134 return m_Edl.InCut(DVD_TIME_TO_MSEC(current.dts + m_offset_pts), &cut) && cut.action == CEdl::CUT;
2137 void COMXPlayer::CheckAutoSceneSkip()
2143 * Check that there is an audio and video stream.
2145 if(m_CurrentAudio.id < 0
2146 || m_CurrentVideo.id < 0)
2150 * If there is a startpts defined for either the audio or video stream then dvdplayer is still
2151 * still decoding frames to get to the previously requested seek point.
2153 if(m_CurrentAudio.inited == false
2154 || m_CurrentVideo.inited == false)
2157 if(m_CurrentAudio.dts == DVD_NOPTS_VALUE
2158 || m_CurrentVideo.dts == DVD_NOPTS_VALUE)
2161 const int64_t clock = DVD_TIME_TO_MSEC(min(m_CurrentAudio.dts, m_CurrentVideo.dts) + m_offset_pts);
2164 if(!m_Edl.InCut(clock, &cut))
2167 if(cut.action == CEdl::CUT
2168 && !(cut.end == m_EdlAutoSkipMarkers.cut || cut.start == m_EdlAutoSkipMarkers.cut)) // To prevent looping if same cut again
2170 CLog::Log(LOGDEBUG, "%s - Clock in EDL cut [%s - %s]: %s. Automatically skipping over.",
2171 __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(),
2172 CEdl::MillisecondsToTimeString(cut.end).c_str(), CEdl::MillisecondsToTimeString(clock).c_str());
2174 * Seeking either goes to the start or the end of the cut depending on the play direction.
2176 int64_t seek = GetPlaySpeed() >= 0 ? cut.end : cut.start;
2178 * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
2180 m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, true, true, false, true));
2182 * Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping
2183 * if there was an error with seeking and it landed somewhere unexpected, perhaps back in the
2184 * cut. The cut automatic skip marker is reset every 500ms allowing another attempt at the seek.
2186 m_EdlAutoSkipMarkers.cut = GetPlaySpeed() >= 0 ? cut.end : cut.start;
2188 else if(cut.action == CEdl::COMM_BREAK
2189 && GetPlaySpeed() >= 0
2190 && cut.start > m_EdlAutoSkipMarkers.commbreak_end)
2192 CLog::Log(LOGDEBUG, "%s - Clock in commercial break [%s - %s]: %s. Automatically skipping to end of commercial break (only done once per break)",
2193 __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), CEdl::MillisecondsToTimeString(cut.end).c_str(),
2194 CEdl::MillisecondsToTimeString(clock).c_str());
2196 * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
2198 m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, true, true, false, true));
2200 * Each commercial break is only skipped once so poorly detected commercial breaks can be
2201 * manually re-entered. Start and end are recorded to prevent looping and to allow seeking back
2202 * to the start of the commercial break if incorrectly flagged.
2204 m_EdlAutoSkipMarkers.commbreak_start = cut.start;
2205 m_EdlAutoSkipMarkers.commbreak_end = cut.end;
2206 m_EdlAutoSkipMarkers.seek_to_start = true; // Allow backwards Seek() to go directly to the start
2210 void COMXPlayer::SynchronizeDemuxer(unsigned int timeout)
2212 if(IsCurrentThread())
2214 if(!m_messenger.IsInited())
2217 CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, 0);
2218 m_messenger.Put(message->Acquire());
2219 message->Wait(&m_bStop, 0);
2223 void COMXPlayer::SynchronizePlayers(unsigned int sources)
2225 /* we need a big timeout as audio queue is about 8seconds for 2ch ac3 */
2226 const int timeout = 10*1000; // in milliseconds
2228 CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, sources);
2229 if (m_CurrentAudio.id >= 0)
2230 m_omxPlayerAudio.SendMessage(message->Acquire());
2232 if (m_CurrentVideo.id >= 0)
2233 m_omxPlayerVideo.SendMessage(message->Acquire());
2234 /* TODO - we have to rewrite the sync class, to not require
2235 all other players waiting for subtitle, should only
2237 if (m_CurrentSubtitle.id >= 0)
2238 m_dvdPlayerSubtitle.SendMessage(message->Acquire());
2243 void COMXPlayer::SendPlayerMessage(CDVDMsg* pMsg, unsigned int target)
2245 if(target == DVDPLAYER_AUDIO)
2246 m_omxPlayerAudio.SendMessage(pMsg);
2247 if(target == DVDPLAYER_VIDEO)
2248 m_omxPlayerVideo.SendMessage(pMsg);
2249 if(target == DVDPLAYER_SUBTITLE)
2250 m_dvdPlayerSubtitle.SendMessage(pMsg);
2251 if(target == DVDPLAYER_TELETEXT)
2252 m_dvdPlayerTeletext.SendMessage(pMsg);
2255 void COMXPlayer::OnExit()
2259 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit()");
2261 m_av_clock.OMXStop();
2262 m_av_clock.OMXStateIdle();
2264 // set event to inform openfile something went wrong in case openfile is still waiting for this event
2265 SetCaching(CACHESTATE_DONE);
2267 // close each stream
2268 if (!m_bAbortRequest) CLog::Log(LOGNOTICE, "OMXPlayer: eof, waiting for queues to empty");
2269 if (m_CurrentAudio.id >= 0)
2271 CLog::Log(LOGNOTICE, "OMXPlayer: closing audio stream");
2272 CloseAudioStream(!m_bAbortRequest);
2274 if (m_CurrentVideo.id >= 0)
2276 CLog::Log(LOGNOTICE, "OMXPlayer: closing video stream");
2277 CloseVideoStream(!m_bAbortRequest);
2279 if (m_CurrentSubtitle.id >= 0)
2281 CLog::Log(LOGNOTICE, "OMXPlayer: closing subtitle stream");
2282 CloseSubtitleStream(!m_bAbortRequest);
2284 if (m_CurrentTeletext.id >= 0)
2286 CLog::Log(LOGNOTICE, "OMXPlayer: closing teletext stream");
2287 CloseTeletextStream(!m_bAbortRequest);
2289 // destroy the demuxer
2292 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit() deleting demuxer");
2297 if (m_pSubtitleDemuxer)
2299 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit() deleting subtitle demuxer");
2300 delete m_pSubtitleDemuxer;
2302 m_pSubtitleDemuxer = NULL;
2304 // destroy the inputstream
2307 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit() deleting input stream");
2308 delete m_pInputStream;
2310 m_pInputStream = NULL;
2312 // clean up all selection streams
2313 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NONE);
2317 m_av_clock.OMXDeinitialize();
2322 CLog::Log(LOGERROR, "%s - Exception thrown when trying to close down player, memory leak will follow", __FUNCTION__);
2323 m_pInputStream = NULL;
2328 // if we didn't stop playing, advance to the next item in xbmc's playlist
2329 if(m_PlayerOptions.identify == false)
2331 if (m_bAbortRequest)
2332 m_callback.OnPlayBackStopped();
2334 m_callback.OnPlayBackEnded();
2337 // set event to inform openfile something went wrong in case openfile is still waiting for this event
2341 void COMXPlayer::HandleMessages()
2344 OMXStreamLock lock(this);
2346 while (m_messenger.Get(&pMsg, 0) == MSGQ_OK)
2351 if (pMsg->IsType(CDVDMsg::PLAYER_SEEK) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK) == 0
2352 && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK_CHAPTER) == 0)
2354 CDVDMsgPlayerSeek &msg(*((CDVDMsgPlayerSeek*)pMsg));
2356 if (!m_State.canseek)
2362 if(!msg.GetTrickPlay())
2364 g_infoManager.SetDisplayAfterSeek(100000);
2367 SetCaching(CACHESTATE_FLUSH);
2369 double start = DVD_NOPTS_VALUE;
2371 int time = msg.GetRestore() ? (int)m_Edl.RestoreCutTime(msg.GetTime()) : msg.GetTime();
2373 // if input streams doesn't support seektime we must convert back to clock
2374 if(dynamic_cast<CDVDInputStream::ISeekTime*>(m_pInputStream) == NULL)
2375 time -= DVD_TIME_TO_MSEC(m_State.time_offset - m_offset_pts);
2377 CLog::Log(LOGDEBUG, "demuxer seek to: %d", time);
2378 if (m_pDemuxer && m_pDemuxer->SeekTime(time, msg.GetBackward(), &start))
2380 CLog::Log(LOGDEBUG, "demuxer seek to: %.0f, success", start);
2381 if(m_pSubtitleDemuxer)
2383 if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward()))
2384 CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time);
2386 // dts after successful seek
2387 if (m_StateInput.time_src == ETIMESOURCE_CLOCK && start == DVD_NOPTS_VALUE)
2388 m_StateInput.dts = DVD_MSEC_TO_TIME(time);
2390 m_StateInput.dts = start;
2392 FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate());
2393 // mark mediatime as invalid
2394 m_av_clock.OMXMediaTime(0.0);
2395 m_last_check_time = 0.0;
2398 CLog::Log(LOGWARNING, "error while seeking");
2400 // set flag to indicate we have finished a seeking request
2401 if(!msg.GetTrickPlay())
2402 g_infoManager.SetDisplayAfterSeek();
2404 // dvd's will issue a HOP_CHANNEL that we need to skip
2405 if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2406 m_dvd.state = DVDSTATE_SEEK;
2408 else if (pMsg->IsType(CDVDMsg::PLAYER_SEEK_CHAPTER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK) == 0
2409 && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK_CHAPTER) == 0)
2411 g_infoManager.SetDisplayAfterSeek(100000);
2412 SetCaching(CACHESTATE_FLUSH);
2414 CDVDMsgPlayerSeekChapter &msg(*((CDVDMsgPlayerSeekChapter*)pMsg));
2415 double start = DVD_NOPTS_VALUE;
2417 // This should always be the case.
2418 if(m_pDemuxer && m_pDemuxer->SeekChapter(msg.GetChapter(), &start))
2420 FlushBuffers(false, start, true);
2421 // mark mediatime as invalid
2422 m_av_clock.OMXMediaTime(0.0);
2424 m_callback.OnPlayBackSeekChapter(msg.GetChapter());
2427 g_infoManager.SetDisplayAfterSeek();
2429 else if (pMsg->IsType(CDVDMsg::DEMUXER_RESET))
2431 m_CurrentAudio.stream = NULL;
2432 m_CurrentVideo.stream = NULL;
2433 m_CurrentSubtitle.stream = NULL;
2435 // we need to reset the demuxer, probably because the streams have changed
2437 m_pDemuxer->Reset();
2438 if(m_pSubtitleDemuxer)
2439 m_pSubtitleDemuxer->Reset();
2441 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_AUDIOSTREAM))
2443 CDVDMsgPlayerSetAudioStream* pMsg2 = (CDVDMsgPlayerSetAudioStream*)pMsg;
2445 OMXSelectionStream& st = m_SelectionStreams.Get(STREAM_AUDIO, pMsg2->GetStreamId());
2446 if(st.source != STREAM_SOURCE_NONE)
2448 if(st.source == STREAM_SOURCE_NAV && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2450 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
2451 if(pStream->SetActiveAudioStream(st.id))
2453 m_dvd.iSelectedAudioStream = -1;
2454 CloseAudioStream(false);
2455 m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true));
2460 CloseAudioStream(false);
2461 OpenAudioStream(st.id, st.source);
2462 AdaptForcedSubtitles();
2463 m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true));
2467 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_SUBTITLESTREAM))
2469 CDVDMsgPlayerSetSubtitleStream* pMsg2 = (CDVDMsgPlayerSetSubtitleStream*)pMsg;
2471 OMXSelectionStream& st = m_SelectionStreams.Get(STREAM_SUBTITLE, pMsg2->GetStreamId());
2472 if(st.source != STREAM_SOURCE_NONE)
2474 if(st.source == STREAM_SOURCE_NAV && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2476 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
2477 if(pStream->SetActiveSubtitleStream(st.id))
2479 m_dvd.iSelectedSPUStream = -1;
2480 CloseSubtitleStream(false);
2485 CloseSubtitleStream(false);
2486 OpenSubtitleStream(st.id, st.source);
2490 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_SUBTITLESTREAM_VISIBLE))
2492 CDVDMsgBool* pValue = (CDVDMsgBool*)pMsg;
2494 m_omxPlayerVideo.EnableSubtitle(pValue->m_value);
2496 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2497 static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->EnableSubtitleStream(pValue->m_value);
2499 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_STATE))
2501 g_infoManager.SetDisplayAfterSeek(100000);
2502 SetCaching(CACHESTATE_FLUSH);
2504 CDVDMsgPlayerSetState* pMsgPlayerSetState = (CDVDMsgPlayerSetState*)pMsg;
2506 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
2508 if(ptr->SetState(pMsgPlayerSetState->GetState()))
2510 m_dvd.state = DVDSTATE_NORMAL;
2511 m_dvd.iDVDStillStartTime = 0;
2512 m_dvd.iDVDStillTime = 0;
2516 g_infoManager.SetDisplayAfterSeek();
2518 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_RECORD))
2520 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2522 input->Record(*(CDVDMsgBool*)pMsg);
2524 else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
2526 FlushBuffers(false);
2528 else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
2530 int speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
2532 // correct our current clock, as it would start going wrong otherwise
2533 if(m_State.timestamp > 0)
2536 offset = m_clock.GetAbsoluteClock() - m_State.timestamp;
2537 offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
2538 if(offset > 1000) offset = 1000;
2539 if(offset < -1000) offset = -1000;
2540 m_State.time += DVD_TIME_TO_MSEC(offset);
2541 m_State.timestamp = m_clock.GetAbsoluteClock();
2544 if (speed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_PAUSE && speed != m_playSpeed)
2545 m_callback.OnPlayBackSpeedChanged(speed / DVD_PLAYSPEED_NORMAL);
2547 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && speed != m_playSpeed)
2549 CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream);
2550 pvrinputstream->Pause( speed == 0 );
2553 // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
2554 // audioplayer, stops outputing audio to audiorender, but still tries to
2555 // sleep an correct amount for each packet
2556 // videoplayer just plays faster after the clock speed has been increased
2558 // 2. skip frames and adjust their pts or the clock
2560 // when switching from trickplay to normal, we may not have a full set of reference frames
2561 // in decoder and we may get corrupt frames out. Seeking to current time will avoid this.
2562 if ( TP(speed) || TP(m_playSpeed) ||
2563 ( (speed == DVD_PLAYSPEED_PAUSE || speed == DVD_PLAYSPEED_NORMAL) &&
2564 (m_playSpeed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_NORMAL) ) )
2565 m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), (speed < 0), true, false, false, true));
2567 m_playSpeed = speed;
2568 m_caching = CACHESTATE_DONE;
2569 m_clock.SetSpeed(speed);
2570 m_av_clock.OMXSetSpeed(speed);
2571 m_av_clock.OMXPause();
2572 m_omxPlayerAudio.SetSpeed(speed);
2573 m_omxPlayerVideo.SetSpeed(speed);
2575 // TODO - we really shouldn't pause demuxer
2576 // until our buffers are somewhat filled
2578 m_pDemuxer->SetSpeed(speed);
2580 CLog::Log(LOGDEBUG, "COMXPlayer - CDVDMsg::PLAYER_SETSPEED speed : %d", speed);
2582 else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) == 0)
2584 FlushBuffers(false);
2585 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2586 if(input && input->SelectChannelByNumber(static_cast<CDVDMsgInt*>(pMsg)->m_value))
2588 SAFE_DELETE(m_pDemuxer);
2591 CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__);
2592 CApplicationMessenger::Get().MediaStop(false);
2595 else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT) == 0)
2597 FlushBuffers(false);
2598 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2599 if(input && input->SelectChannel(static_cast<CDVDMsgType <CPVRChannel> *>(pMsg)->m_value))
2601 SAFE_DELETE(m_pDemuxer);
2604 CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__);
2605 CApplicationMessenger::Get().MediaStop(false);
2608 else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT) || pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_PREV))
2610 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2613 bool bSwitchSuccessful(false);
2614 bool bShowPreview(CSettings::Get().GetInt("pvrplayback.channelentrytimeout") > 0);
2618 g_infoManager.SetDisplayAfterSeek(100000);
2619 FlushBuffers(false);
2622 if(pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT))
2623 bSwitchSuccessful = input->NextChannel(bShowPreview);
2625 bSwitchSuccessful = input->PrevChannel(bShowPreview);
2627 if(bSwitchSuccessful)
2631 UpdateApplication(0);
2632 m_ChannelEntryTimeOut.Set(CSettings::Get().GetInt("pvrplayback.channelentrytimeout"));
2636 m_ChannelEntryTimeOut.SetInfinite();
2637 SAFE_DELETE(m_pDemuxer);
2639 g_infoManager.SetDisplayAfterSeek();
2644 CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__);
2645 CApplicationMessenger::Get().MediaStop(false);
2649 else if (pMsg->IsType(CDVDMsg::GENERAL_GUI_ACTION))
2650 OnAction(((CDVDMsgType<CAction>*)pMsg)->m_value);
2651 else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
2653 int player = ((CDVDMsgInt*)pMsg)->m_value;
2654 if(player == DVDPLAYER_AUDIO)
2655 m_CurrentAudio.started = true;
2656 if(player == DVDPLAYER_VIDEO)
2657 m_CurrentVideo.started = true;
2659 if ((player == DVDPLAYER_AUDIO || player == DVDPLAYER_VIDEO) &&
2660 (TPA(m_playSpeed) || !m_HasAudio || m_CurrentAudio.started) &&
2661 (!m_HasVideo || m_CurrentVideo.started))
2663 CLog::Log(LOGDEBUG, "COMXPlayer::HandleMessages - player started RESET");
2664 m_av_clock.OMXReset(m_HasVideo, m_playSpeed != DVD_PLAYSPEED_NORMAL && m_playSpeed != DVD_PLAYSPEED_PAUSE ? false:m_HasAudio);
2667 CLog::Log(LOGDEBUG, "COMXPlayer::HandleMessages - player started %d (tpa:%d,a:%d,v:%d)", player, TPA(m_playSpeed), m_CurrentAudio.started, m_CurrentVideo.started);
2669 else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME))
2671 COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value;
2673 CSingleLock lock(m_StateSection);
2674 /* prioritize data from video player, but only accept data *
2675 * after it has been started to avoid race conditions after seeks */
2676 if(m_CurrentVideo.started && !m_omxPlayerVideo.SubmittedEOS())
2678 if(state.player == DVDPLAYER_VIDEO)
2681 else if(m_CurrentAudio.started)
2683 if(state.player == DVDPLAYER_AUDIO)
2690 CLog::Log(LOGERROR, "%s - Exception thrown when handling message", __FUNCTION__);
2698 void COMXPlayer::SetCaching(ECacheState state)
2700 if(state == CACHESTATE_FLUSH)
2702 double level, delay, offset;
2703 if(GetCachingTimes(level, delay, offset))
2704 state = CACHESTATE_FULL;
2706 state = CACHESTATE_INIT;
2709 if(m_caching == state)
2712 CLog::Log(LOGDEBUG, "COMXPlayer::SetCaching - caching state %d", state);
2713 if(state == CACHESTATE_FULL
2714 || state == CACHESTATE_INIT
2715 || state == CACHESTATE_PVR)
2717 m_clock.SetSpeed(DVD_PLAYSPEED_PAUSE);
2718 m_av_clock.OMXPause();
2719 m_omxPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE);
2720 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
2721 m_omxPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE);
2722 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
2724 if (state == CACHESTATE_PVR)
2725 m_pInputStream->ResetScanTimeout((unsigned int) CSettings::Get().GetInt("pvrplayback.scantime") * 1000);
2728 if(state == CACHESTATE_PLAY
2729 ||(state == CACHESTATE_DONE && m_caching != CACHESTATE_PLAY))
2731 m_clock.SetSpeed(m_playSpeed);
2732 m_omxPlayerAudio.SetSpeed(m_playSpeed);
2733 m_omxPlayerVideo.SetSpeed(m_playSpeed);
2734 m_pInputStream->ResetScanTimeout(0);
2739 void COMXPlayer::SetPlaySpeed(int speed)
2741 m_messenger.Put(new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed));
2742 m_omxPlayerAudio.SetSpeed(speed);
2743 m_omxPlayerVideo.SetSpeed(speed);
2744 SynchronizeDemuxer(100);
2747 bool COMXPlayer::CanPause()
2749 CSingleLock lock(m_StateSection);
2750 return m_State.canpause;
2753 void COMXPlayer::Pause()
2755 CSingleLock lock(m_StateSection);
2756 if (!m_State.canpause)
2760 if(m_playSpeed != DVD_PLAYSPEED_PAUSE && (m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR))
2762 SetCaching(CACHESTATE_DONE);
2766 // return to normal speed if it was paused before, pause otherwise
2767 if (m_playSpeed == DVD_PLAYSPEED_PAUSE)
2769 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
2770 m_callback.OnPlayBackResumed();
2774 SetPlaySpeed(DVD_PLAYSPEED_PAUSE);
2775 m_callback.OnPlayBackPaused();
2779 bool COMXPlayer::IsPaused() const
2781 return m_playSpeed == DVD_PLAYSPEED_PAUSE || m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR;
2784 bool COMXPlayer::HasVideo() const
2789 bool COMXPlayer::HasAudio() const
2794 bool COMXPlayer::IsPassthrough() const
2796 return m_omxPlayerAudio.Passthrough();
2799 bool COMXPlayer::CanSeek()
2801 CSingleLock lock(m_StateSection);
2802 return m_State.canseek;
2805 void COMXPlayer::Seek(bool bPlus, bool bLargeStep, bool bChapterOverride)
2808 if( m_playSpeed == DVD_PLAYSPEED_PAUSE && bPlus && !bLargeStep)
2810 m_av_clock.OMXStep();
2814 if (!m_State.canseek)
2817 if (bLargeStep && bChapterOverride && GetChapter() > 0)
2821 SeekChapter(GetChapter() - 1);
2824 else if (GetChapter() < GetChapterCount())
2826 SeekChapter(GetChapter() + 1);
2832 if (g_advancedSettings.m_videoUseTimeSeeking && GetTotalTime() > 2000*g_advancedSettings.m_videoTimeSeekForwardBig)
2835 seek = bPlus ? g_advancedSettings.m_videoTimeSeekForwardBig : g_advancedSettings.m_videoTimeSeekBackwardBig;
2837 seek = bPlus ? g_advancedSettings.m_videoTimeSeekForward : g_advancedSettings.m_videoTimeSeekBackward;
2845 percent = bPlus ? g_advancedSettings.m_videoPercentSeekForwardBig : g_advancedSettings.m_videoPercentSeekBackwardBig;
2847 percent = bPlus ? g_advancedSettings.m_videoPercentSeekForward : g_advancedSettings.m_videoPercentSeekBackward;
2848 seek = (int64_t)(GetTotalTimeInMsec()*(GetPercentage()+percent)/100);
2851 bool restore = true;
2855 * Alter the standard seek position based on whether any commercial breaks have been
2856 * automatically skipped.
2858 const int clock = DVD_TIME_TO_MSEC(m_clock.GetClock());
2860 * If a large backwards seek occurs within 10 seconds of the end of the last automated
2861 * commercial skip, then seek back to the start of the commercial break under the assumption
2862 * it was flagged incorrectly. 10 seconds grace period is allowed in case the watcher has to
2863 * fumble around finding the remote. Only happens once per commercial break.
2865 * Small skip does not trigger this in case the start of the commercial break was in fact fine
2866 * but it skipped too far into the program. In that case small skip backwards behaves as normal.
2868 if (!bPlus && bLargeStep
2869 && m_EdlAutoSkipMarkers.seek_to_start
2870 && clock >= m_EdlAutoSkipMarkers.commbreak_end
2871 && clock <= m_EdlAutoSkipMarkers.commbreak_end + 10*1000) // Only if within 10 seconds of the end (in msec)
2873 CLog::Log(LOGDEBUG, "%s - Seeking back to start of commercial break [%s - %s] as large backwards skip activated within 10 seconds of the automatic commercial skip (only done once per break).",
2874 __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(),
2875 CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str());
2876 seek = m_EdlAutoSkipMarkers.commbreak_start;
2878 m_EdlAutoSkipMarkers.seek_to_start = false; // So this will only happen within the 10 second grace period once.
2881 * If big skip forward within the last "reverted" commercial break, seek to the end of the
2882 * commercial break under the assumption that the break was incorrectly flagged and playback has
2883 * now reached the actual start of the commercial break. Assume that the end is flagged more
2884 * correctly than the landing point for a standard big skip (ends seem to be flagged more
2885 * accurately than the start).
2887 else if (bPlus && bLargeStep
2888 && clock >= m_EdlAutoSkipMarkers.commbreak_start
2889 && clock <= m_EdlAutoSkipMarkers.commbreak_end)
2891 CLog::Log(LOGDEBUG, "%s - Seeking to end of previously skipped commercial break [%s - %s] as big forwards skip activated within the break.",
2892 __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(),
2893 CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str());
2894 seek = m_EdlAutoSkipMarkers.commbreak_end;
2899 int64_t time = GetTime();
2900 if(g_application.CurrentFileItem().IsStack()
2901 && (seek > GetTotalTimeInMsec() || seek < 0))
2903 g_application.SeekTime((seek - time) * 0.001 + g_application.GetTime());
2904 // warning, don't access any dvdplayer variables here as
2905 // the dvdplayer object may have been destroyed
2909 m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, !bPlus, true, false, restore));
2910 SynchronizeDemuxer(100);
2911 if (seek < 0) seek = 0;
2912 m_callback.OnPlayBackSeek((int)seek, (int)(seek - time));
2915 bool COMXPlayer::SeekScene(bool bPlus)
2917 if (!m_Edl.HasSceneMarker())
2921 * There is a 5 second grace period applied when seeking for scenes backwards. If there is no
2922 * grace period applied it is impossible to go backwards past a scene marker.
2924 int64_t clock = GetTime();
2925 if (!bPlus && clock > 5 * 1000) // 5 seconds
2928 int64_t iScenemarker;
2929 if (m_Edl.GetNextSceneMarker(bPlus, clock, &iScenemarker))
2932 * Seeking is flushed and inaccurate, just like Seek()
2934 m_messenger.Put(new CDVDMsgPlayerSeek((int)iScenemarker, !bPlus, true, false, false));
2935 SynchronizeDemuxer(100);
2941 void COMXPlayer::GetAudioInfo(CStdString &strAudioInfo)
2943 { CSingleLock lock(m_StateSection);
2944 strAudioInfo = StringUtils::Format("D(%s)", m_StateInput.demux_audio.c_str());
2946 strAudioInfo.AppendFormat("\nP(%s)", m_omxPlayerAudio.GetPlayerInfo().c_str());
2949 void COMXPlayer::GetVideoInfo(CStdString &strVideoInfo)
2951 { CSingleLock lock(m_StateSection);
2952 strVideoInfo = StringUtils::Format("D(%s)", m_StateInput.demux_video.c_str());
2954 strVideoInfo.AppendFormat("\nP(%s)", m_omxPlayerVideo.GetPlayerInfo().c_str());
2957 void COMXPlayer::GetGeneralInfo(CStdString& strGeneralInfo)
2961 double apts = m_omxPlayerAudio.GetCurrentPts();
2962 double vpts = m_omxPlayerVideo.GetCurrentPts();
2965 if( apts != DVD_NOPTS_VALUE && vpts != DVD_NOPTS_VALUE )
2966 dDiff = (apts - vpts) / DVD_TIME_BASE;
2969 strEDL.AppendFormat(", edl:%s", m_Edl.GetInfo().c_str());
2972 CSingleLock lock(m_StateSection);
2973 if(m_StateInput.cache_bytes >= 0)
2975 strBuf.AppendFormat(" cache:%s %2.0f%%"
2976 , StringUtils::SizeToString(m_State.cache_bytes).c_str()
2977 , m_State.cache_level * 100);
2978 if(m_playSpeed == 0 || m_caching == CACHESTATE_FULL)
2979 strBuf.AppendFormat(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay));
2982 strGeneralInfo = StringUtils::Format("C( ad:% 6.3f a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s af:%d%% vf:%d%% amp:% 5.2f )"
2983 , m_omxPlayerAudio.GetDelay()
2986 , (int)(CThread::GetRelativeUsage()*100)
2987 , (int)(m_omxPlayerAudio.GetRelativeUsage()*100)
2988 , (int)(m_omxPlayerVideo.GetRelativeUsage()*100)
2992 , m_omxPlayerAudio.GetDynamicRangeAmplification());
2997 void COMXPlayer::SeekPercentage(float iPercent)
2999 int64_t iTotalTime = GetTotalTimeInMsec();
3004 SeekTime((int64_t)(iTotalTime * iPercent / 100));
3007 float COMXPlayer::GetPercentage()
3009 int64_t iTotalTime = GetTotalTimeInMsec();
3014 return GetTime() * 100 / (float)iTotalTime;
3017 float COMXPlayer::GetCachePercentage()
3019 CSingleLock lock(m_StateSection);
3020 return m_StateInput.cache_offset * 100; // NOTE: Percentage returned is relative
3023 void COMXPlayer::SetAVDelay(float fValue)
3025 m_omxPlayerVideo.SetDelay(fValue * DVD_TIME_BASE);
3028 float COMXPlayer::GetAVDelay()
3030 return m_omxPlayerVideo.GetDelay() / (float)DVD_TIME_BASE;
3033 void COMXPlayer::SetSubTitleDelay(float fValue)
3035 m_omxPlayerVideo.SetSubtitleDelay(-fValue * DVD_TIME_BASE);
3038 float COMXPlayer::GetSubTitleDelay()
3040 return -m_omxPlayerVideo.GetSubtitleDelay() / DVD_TIME_BASE;
3043 // priority: 1: libdvdnav, 2: external subtitles, 3: muxed subtitles
3044 int COMXPlayer::GetSubtitleCount()
3046 OMXStreamLock lock(this);
3047 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
3048 return m_SelectionStreams.Count(STREAM_SUBTITLE);
3051 int COMXPlayer::GetSubtitle()
3053 return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, *this);
3056 void COMXPlayer::GetSubtitleStreamInfo(int index, SPlayerSubtitleStreamInfo &info)
3058 if (index < 0 || index > (int) GetSubtitleCount() - 1)
3061 OMXSelectionStream& s = m_SelectionStreams.Get(STREAM_SUBTITLE, index);
3062 if(s.name.length() > 0)
3065 if(s.type == STREAM_NONE)
3066 info.name += "(Invalid)";
3068 info.language = s.language;
3071 void COMXPlayer::SetSubtitle(int iStream)
3073 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = iStream;
3074 m_messenger.Put(new CDVDMsgPlayerSetSubtitleStream(iStream));
3077 bool COMXPlayer::GetSubtitleVisible()
3079 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3081 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
3082 if(pStream->IsInMenu())
3083 return CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn;
3085 return pStream->IsSubtitleStreamEnabled();
3088 return m_omxPlayerVideo.IsSubtitleEnabled();
3091 void COMXPlayer::SetSubtitleVisible(bool bVisible)
3093 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn = bVisible;
3094 m_messenger.Put(new CDVDMsgBool(CDVDMsg::PLAYER_SET_SUBTITLESTREAM_VISIBLE, bVisible));
3097 int COMXPlayer::GetAudioStreamCount()
3099 OMXStreamLock lock(this);
3100 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
3101 return m_SelectionStreams.Count(STREAM_AUDIO);
3104 int COMXPlayer::GetAudioStream()
3106 return m_SelectionStreams.IndexOf(STREAM_AUDIO, *this);
3109 void COMXPlayer::SetAudioStream(int iStream)
3111 CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = iStream;
3112 m_messenger.Put(new CDVDMsgPlayerSetAudioStream(iStream));
3113 SynchronizeDemuxer(100);
3116 TextCacheStruct_t* COMXPlayer::GetTeletextCache()
3118 if (m_CurrentTeletext.id < 0)
3121 return m_dvdPlayerTeletext.GetTeletextCache();
3124 void COMXPlayer::LoadPage(int p, int sp, unsigned char* buffer)
3126 if (m_CurrentTeletext.id < 0)
3129 return m_dvdPlayerTeletext.LoadPage(p, sp, buffer);
3132 void COMXPlayer::SeekTime(int64_t iTime)
3134 int seekOffset = (int)(iTime - GetTime());
3135 m_messenger.Put(new CDVDMsgPlayerSeek((int)iTime, true, true, true));
3136 SynchronizeDemuxer(100);
3137 m_callback.OnPlayBackSeek((int)iTime, seekOffset);
3140 // return the time in milliseconds
3141 int64_t COMXPlayer::GetTime()
3143 CSingleLock lock(m_StateSection);
3145 const double limit = DVD_MSEC_TO_TIME(200);
3146 if(m_State.timestamp > 0)
3148 offset = m_clock.GetAbsoluteClock() - m_State.timestamp;
3149 offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
3150 if(offset > limit) offset = limit;
3151 if(offset < -limit) offset = -limit;
3153 //{CLog::Log(LOGINFO, "%s: time:%.2f stamp:%.2f dts:%d m:%d (p:%d,c:%d) =%llu", __func__, (double)m_State.time, (double)m_State.timestamp, (int)DVD_TIME_TO_MSEC(m_State.dts + m_offset_pts), (int)DVD_TIME_TO_MSEC(m_stamp), (int)m_playSpeed, (int)m_caching, llrint(m_State.time + DVD_TIME_TO_MSEC(offset)));}
3154 return llrint(m_State.time + DVD_TIME_TO_MSEC(offset));
3157 // return length in msec
3158 int64_t COMXPlayer::GetTotalTimeInMsec()
3160 CSingleLock lock(m_StateSection);
3161 return llrint(m_State.time_total);
3164 // return length in seconds.. this should be changed to return in milleseconds throughout xbmc
3165 int64_t COMXPlayer::GetTotalTime()
3167 return GetTotalTimeInMsec();
3170 void COMXPlayer::ToFFRW(int iSpeed)
3172 // can't rewind in menu as seeking isn't possible
3174 if (iSpeed < 0 && IsInMenu()) return;
3175 SetPlaySpeed(iSpeed * DVD_PLAYSPEED_NORMAL);
3178 bool COMXPlayer::OpenAudioStream(int iStream, int source, bool reset)
3180 CLog::Log(LOGNOTICE, "Opening audio stream: %i source: %i", iStream, source);
3184 CLog::Log(LOGWARNING, "Opening audio stream: no demuxer");
3188 CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
3189 if (!pStream || pStream->disabled)
3191 CLog::Log(LOGWARNING, "Opening audio stream: pStream=%p disabled=%d", pStream, pStream ? pStream->disabled:0);
3195 if( m_CurrentAudio.id < 0 && m_CurrentVideo.id >= 0 )
3197 // up until now we wheren't playing audio, but we did play video
3198 // this will change what is used to sync the dvdclock.
3199 // since the new audio data doesn't have to have any relation
3200 // to the current video data in the packet que, we have to
3201 // wait for it to empty
3203 // this happens if a new cell has audio data, but previous didn't
3204 // and both have video data
3206 SynchronizePlayers(SYNCSOURCE_AUDIO);
3209 CDVDStreamInfo hint(*pStream, true);
3211 if(m_CurrentAudio.id < 0
3212 || m_CurrentAudio.hint != hint)
3214 if(!m_omxPlayerAudio.OpenStream(hint))
3216 /* mark stream as disabled, to disallaw further attempts*/
3217 CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
3218 pStream->disabled = true;
3219 pStream->SetDiscard(AVDISCARD_ALL);
3224 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3226 /* store information about stream */
3227 m_CurrentAudio.id = iStream;
3228 m_CurrentAudio.source = source;
3229 m_CurrentAudio.hint = hint;
3230 m_CurrentAudio.stream = (void*)pStream;
3231 m_CurrentAudio.started = false;
3234 /* we are potentially going to be waiting on this */
3235 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
3237 /* software decoding normaly consumes full cpu time so prio it */
3238 m_omxPlayerAudio.SetPriority(GetPriority()+1);
3239 CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = m_SelectionStreams.IndexOf(STREAM_AUDIO, source, iStream);
3243 bool COMXPlayer::OpenVideoStream(int iStream, int source, bool reset)
3245 CLog::Log(LOGNOTICE, "Opening video stream: %i source: %i", iStream, source);
3249 CLog::Log(LOGWARNING, "Opening video stream: no demuxer");
3253 CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
3254 if(!pStream || pStream->disabled)
3256 CLog::Log(LOGWARNING, "Opening video stream: pStream=%p disabled=%d", pStream, pStream ? pStream->disabled:0);
3259 pStream->SetDiscard(AVDISCARD_NONE);
3261 CDVDStreamInfo hint(*pStream, true);
3263 if( m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) )
3265 /* set aspect ratio as requested by navigator for dvd's */
3266 float aspect = static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->GetVideoAspectRatio();
3269 hint.aspect = aspect;
3270 hint.forced_aspect = true;
3272 hint.software = true;
3275 boost::shared_ptr<CPVRClient> client;
3276 if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) &&
3277 pStream->type == STREAM_VIDEO &&
3278 g_PVRClients->GetPlayingClient(client) && client->HandlesDemuxing())
3280 // set the fps in hints
3281 const CDemuxStreamVideo *stream = static_cast<const CDemuxStreamVideo*>(pStream);
3282 hint.fpsrate = stream->iFpsRate;
3283 hint.fpsscale = stream->iFpsScale;
3286 CDVDInputStream::IMenus* pMenus = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
3287 if(pMenus && pMenus->IsInMenu())
3290 if (hint.stereo_mode.empty())
3291 hint.stereo_mode = CStereoscopicsManager::Get().DetectStereoModeByString(m_filename);
3293 if(m_CurrentVideo.id < 0
3294 || m_CurrentVideo.hint != hint)
3296 // for music file, don't open artwork as video
3297 bool disabled = false;
3298 CStdString extension = URIUtils::GetExtension(m_filename);
3299 if (!extension.IsEmpty() && g_advancedSettings.m_musicExtensions.Find(extension.ToLower()) != -1)
3301 CLog::Log(LOGWARNING, "%s - Ignoring video in audio filetype:%s", __FUNCTION__, m_filename.c_str());
3305 if (disabled || !m_omxPlayerVideo.OpenStream(hint))
3307 /* mark stream as disabled, to disallaw further attempts */
3308 CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
3309 pStream->disabled = true;
3310 pStream->SetDiscard(AVDISCARD_ALL);
3315 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3317 /* store information about stream */
3318 m_CurrentVideo.id = iStream;
3319 m_CurrentVideo.source = source;
3320 m_CurrentVideo.hint = hint;
3321 m_CurrentVideo.stream = (void*)pStream;
3322 m_CurrentVideo.started = false;
3325 /* we are potentially going to be waiting on this */
3326 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
3328 /* use same priority for video thread as demuxing thread, as */
3329 /* otherwise demuxer will starve if video consumes the full cpu */
3330 m_omxPlayerVideo.SetPriority(GetPriority());
3335 bool COMXPlayer::OpenSubtitleStream(int iStream, int source)
3337 CLog::Log(LOGNOTICE, "Opening Subtitle stream: %i source: %i", iStream, source);
3339 CDemuxStream* pStream = NULL;
3340 std::string filename;
3341 CDVDStreamInfo hint;
3343 if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_DEMUX_SUB)
3345 int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, source, iStream);
3348 OMXSelectionStream st = m_SelectionStreams.Get(STREAM_SUBTITLE, index);
3350 if(!m_pSubtitleDemuxer || m_pSubtitleDemuxer->GetFileName() != st.filename)
3352 CLog::Log(LOGNOTICE, "Opening Subtitle file: %s", st.filename.c_str());
3353 auto_ptr<CDVDDemuxVobsub> demux(new CDVDDemuxVobsub());
3354 if(!demux->Open(st.filename, st.filename2))
3356 m_pSubtitleDemuxer = demux.release();
3359 pStream = m_pSubtitleDemuxer->GetStream(iStream);
3360 if(!pStream || pStream->disabled)
3362 pStream->SetDiscard(AVDISCARD_NONE);
3363 double pts = m_omxPlayerVideo.GetCurrentPts();
3364 if(pts == DVD_NOPTS_VALUE)
3365 pts = m_CurrentVideo.dts;
3366 if(pts == DVD_NOPTS_VALUE)
3368 pts += m_offset_pts;
3369 m_pSubtitleDemuxer->SeekTime((int)(1000.0 * pts / (double)DVD_TIME_BASE));
3371 hint.Assign(*pStream, true);
3373 else if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_TEXT)
3375 int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, source, iStream);
3378 filename = m_SelectionStreams.Get(STREAM_SUBTITLE, index).filename;
3381 hint.fpsscale = m_CurrentVideo.hint.fpsscale;
3382 hint.fpsrate = m_CurrentVideo.hint.fpsrate;
3388 pStream = m_pDemuxer->GetStream(iStream);
3389 if(!pStream || pStream->disabled)
3391 pStream->SetDiscard(AVDISCARD_NONE);
3393 hint.Assign(*pStream, true);
3395 if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3399 if(m_CurrentSubtitle.id < 0
3400 || m_CurrentSubtitle.hint != hint)
3402 if(m_CurrentSubtitle.id >= 0)
3404 CLog::Log(LOGDEBUG, " - codecs hints have changed, must close previous stream");
3405 CloseSubtitleStream(false);
3408 if(!m_dvdPlayerSubtitle.OpenStream(hint, filename))
3410 CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
3413 pStream->disabled = true;
3414 pStream->SetDiscard(AVDISCARD_ALL);
3420 m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3422 m_CurrentSubtitle.id = iStream;
3423 m_CurrentSubtitle.source = source;
3424 m_CurrentSubtitle.hint = hint;
3425 m_CurrentSubtitle.stream = (void*)pStream;
3426 m_CurrentSubtitle.started = false;
3428 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, source, iStream);
3432 bool COMXPlayer::AdaptForcedSubtitles()
3435 OMXSelectionStream ss = m_SelectionStreams.Get(STREAM_SUBTITLE, GetSubtitle());
3436 if (ss.flags & CDemuxStream::FLAG_FORCED || !GetSubtitleVisible())
3438 OMXSelectionStream as = m_SelectionStreams.Get(STREAM_SUBTITLE, GetAudioStream());
3439 OMXSelectionStreams streams = m_SelectionStreams.Get(STREAM_SUBTITLE);
3441 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
3443 if (it->flags & CDemuxStream::FLAG_FORCED && g_LangCodeExpander.CompareLangCodes(it->language, as.language))
3445 if(OpenSubtitleStream(it->id, it->source))
3448 SetSubtitleVisible(true);
3454 CloseSubtitleStream(true);
3455 SetSubtitleVisible(false);
3461 bool COMXPlayer::OpenTeletextStream(int iStream, int source)
3466 CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
3467 if(!pStream || pStream->disabled)
3470 CDVDStreamInfo hint(*pStream, true);
3472 if (!m_dvdPlayerTeletext.CheckStream(hint))
3475 CLog::Log(LOGNOTICE, "Opening teletext stream: %i source: %i", iStream, source);
3477 if(m_CurrentTeletext.id < 0
3478 || m_CurrentTeletext.hint != hint)
3480 if(m_CurrentTeletext.id >= 0)
3482 CLog::Log(LOGDEBUG, " - teletext codecs hints have changed, must close previous stream");
3483 CloseTeletextStream(true);
3486 if (!m_dvdPlayerTeletext.OpenStream(hint))
3488 /* mark stream as disabled, to disallaw further attempts*/
3489 CLog::Log(LOGWARNING, "%s - Unsupported teletext stream %d. Stream disabled.", __FUNCTION__, iStream);
3490 pStream->disabled = true;
3491 pStream->SetDiscard(AVDISCARD_ALL);
3496 m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3498 /* store information about stream */
3499 m_CurrentTeletext.id = iStream;
3500 m_CurrentTeletext.source = source;
3501 m_CurrentTeletext.hint = hint;
3502 m_CurrentTeletext.stream = (void*)pStream;
3503 m_CurrentTeletext.started = false;
3508 bool COMXPlayer::CloseAudioStream(bool bWaitForBuffers)
3510 if (m_CurrentAudio.id < 0)
3513 CLog::Log(LOGNOTICE, "Closing audio stream");
3516 SetCaching(CACHESTATE_DONE);
3518 m_omxPlayerAudio.CloseStream(bWaitForBuffers);
3520 m_CurrentAudio.Clear();
3524 bool COMXPlayer::CloseVideoStream(bool bWaitForBuffers)
3526 if (m_CurrentVideo.id < 0)
3529 CLog::Log(LOGNOTICE, "Closing video stream");
3532 SetCaching(CACHESTATE_DONE);
3534 m_omxPlayerVideo.CloseStream(bWaitForBuffers);
3536 m_CurrentVideo.Clear();
3540 bool COMXPlayer::CloseSubtitleStream(bool bKeepOverlays)
3542 if (m_CurrentSubtitle.id < 0)
3545 CLog::Log(LOGNOTICE, "Closing subtitle stream");
3547 m_dvdPlayerSubtitle.CloseStream(!bKeepOverlays);
3549 m_CurrentSubtitle.Clear();
3553 bool COMXPlayer::CloseTeletextStream(bool bWaitForBuffers)
3555 if (m_CurrentTeletext.id < 0)
3558 CLog::Log(LOGNOTICE, "Closing teletext stream");
3561 SetCaching(CACHESTATE_DONE);
3563 m_dvdPlayerTeletext.CloseStream(bWaitForBuffers);
3565 m_CurrentTeletext.Clear();
3569 void COMXPlayer::FlushBuffers(bool queued, double pts, bool accurate)
3573 CLog::Log(LOGNOTICE, "FlushBuffers: q:%d pts:%.0f a:%d", queued, pts, accurate);
3575 if (!TP(m_playSpeed))
3576 m_av_clock.OMXStop();
3577 m_av_clock.OMXPause();
3580 /* for now, ignore accurate flag as it discards keyframes and causes corrupt frames */
3584 startpts = DVD_NOPTS_VALUE;
3586 /* call with demuxer pts */
3587 if(startpts != DVD_NOPTS_VALUE)
3588 startpts -= m_offset_pts;
3590 m_CurrentAudio.inited = false;
3591 m_CurrentAudio.dts = DVD_NOPTS_VALUE;
3592 m_CurrentAudio.startpts = startpts;
3594 m_CurrentVideo.inited = false;
3595 m_CurrentVideo.dts = DVD_NOPTS_VALUE;
3596 m_CurrentVideo.startpts = startpts;
3598 m_CurrentSubtitle.inited = false;
3599 m_CurrentSubtitle.dts = DVD_NOPTS_VALUE;
3600 m_CurrentSubtitle.startpts = startpts;
3602 m_CurrentTeletext.inited = false;
3603 m_CurrentTeletext.dts = DVD_NOPTS_VALUE;
3604 m_CurrentTeletext.startpts = startpts;
3608 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3609 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3610 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP));
3611 m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3612 m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3613 SynchronizePlayers(SYNCSOURCE_ALL);
3617 m_omxPlayerAudio.Flush();
3618 m_omxPlayerVideo.Flush();
3619 m_dvdPlayerSubtitle.Flush();
3620 m_dvdPlayerTeletext.Flush();
3622 // clear subtitle and menu overlays
3623 m_overlayContainer.Clear();
3625 if(m_playSpeed == DVD_PLAYSPEED_NORMAL
3626 || m_playSpeed == DVD_PLAYSPEED_PAUSE)
3628 // make sure players are properly flushed, should put them in stalled state
3629 CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(1000, 0);
3630 m_omxPlayerAudio.SendMessage(msg->Acquire(), 1);
3631 m_omxPlayerVideo.SendMessage(msg->Acquire(), 1);
3632 msg->Wait(&m_bStop, 0);
3635 // purge any pending PLAYER_STARTED messages
3636 m_messenger.Flush(CDVDMsg::PLAYER_STARTED);
3638 // we should now wait for init cache
3639 SetCaching(CACHESTATE_FLUSH);
3640 m_CurrentAudio.started = false;
3641 m_CurrentVideo.started = false;
3642 m_CurrentSubtitle.started = false;
3643 m_CurrentTeletext.started = false;
3646 if(pts != DVD_NOPTS_VALUE)
3647 m_clock.Discontinuity(pts);
3650 // update state, buffers are flushed and it may take some time until
3651 // we get an update from players
3652 CSingleLock lock(m_StateSection);
3653 m_State = m_StateInput;
3657 // since we call ffmpeg functions to decode, this is being called in the same thread as ::Process() is
3658 int COMXPlayer::OnDVDNavResult(void* pData, int iMessage)
3660 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY))
3663 m_overlayContainer.Add((CDVDOverlay*)pData);
3664 else if(iMessage == 1)
3665 m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
3666 else if(iMessage == 2)
3667 m_dvd.iSelectedAudioStream = *(int*)pData;
3668 else if(iMessage == 3)
3669 m_dvd.iSelectedSPUStream = *(int*)pData;
3670 else if(iMessage == 4)
3671 m_omxPlayerVideo.EnableSubtitle(*(int*)pData ? true: false);
3672 else if(iMessage == 5)
3674 if (m_dvd.state != DVDSTATE_STILL)
3676 // else notify the player we have received a still frame
3678 m_dvd.iDVDStillTime = *(int*)pData;
3679 m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis();
3681 /* adjust for the output delay in the video queue */
3682 unsigned int time = 0;
3683 if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 )
3685 time = (unsigned int)(m_omxPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 ));
3686 if( time < 10000 && time > 0 )
3687 m_dvd.iDVDStillTime += time;
3689 m_dvd.state = DVDSTATE_STILL;
3691 "DVDNAV_STILL_FRAME - waiting %i sec, with delay of %d sec",
3692 m_dvd.iDVDStillTime, time / 1000);
3699 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3701 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
3705 case DVDNAV_STILL_FRAME:
3707 //CLog::Log(LOGDEBUG, "DVDNAV_STILL_FRAME");
3709 dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)pData;
3710 // should wait the specified time here while we let the player running
3711 // after that call dvdnav_still_skip(m_dvdnav);
3713 if (m_dvd.state != DVDSTATE_STILL)
3715 // else notify the player we have received a still frame
3717 if(still_event->length < 0xff)
3718 m_dvd.iDVDStillTime = still_event->length * 1000;
3720 m_dvd.iDVDStillTime = 0;
3722 m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis();
3724 /* adjust for the output delay in the video queue */
3725 unsigned int time = 0;
3726 if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 )
3728 time = (unsigned int)(m_omxPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 ));
3729 if( time < 10000 && time > 0 )
3730 m_dvd.iDVDStillTime += time;
3732 m_dvd.state = DVDSTATE_STILL;
3734 "DVDNAV_STILL_FRAME - waiting %i sec, with delay of %d sec",
3735 still_event->length, time / 1000);
3737 return NAVRESULT_HOLD;
3740 case DVDNAV_SPU_CLUT_CHANGE:
3742 m_dvdPlayerSubtitle.SendMessage(new CDVDMsgSubtitleClutChange((uint8_t*)pData));
3745 case DVDNAV_SPU_STREAM_CHANGE:
3747 dvdnav_spu_stream_change_event_t* event = (dvdnav_spu_stream_change_event_t*)pData;
3749 int iStream = event->physical_wide;
3750 bool visible = !(iStream & 0x80);
3752 m_omxPlayerVideo.EnableSubtitle(visible);
3755 m_dvd.iSelectedSPUStream = (iStream & ~0x80);
3757 m_dvd.iSelectedSPUStream = -1;
3759 m_CurrentSubtitle.stream = NULL;
3762 case DVDNAV_AUDIO_STREAM_CHANGE:
3764 // This should be the correct way i think, however we don't have any streams right now
3765 // since the demuxer hasn't started so it doesn't change. not sure how to do this.
3766 dvdnav_audio_stream_change_event_t* event = (dvdnav_audio_stream_change_event_t*)pData;
3768 // Tell system what audiostream should be opened by default
3769 if (event->logical >= 0)
3770 m_dvd.iSelectedAudioStream = event->physical;
3772 m_dvd.iSelectedAudioStream = -1;
3774 m_CurrentAudio.stream = NULL;
3777 case DVDNAV_HIGHLIGHT:
3779 //dvdnav_highlight_event_t* pInfo = (dvdnav_highlight_event_t*)pData;
3780 int iButton = pStream->GetCurrentButton();
3781 CLog::Log(LOGDEBUG, "DVDNAV_HIGHLIGHT: Highlight button %d\n", iButton);
3782 m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL);
3785 case DVDNAV_VTS_CHANGE:
3787 //dvdnav_vts_change_event_t* vts_change_event = (dvdnav_vts_change_event_t*)pData;
3788 CLog::Log(LOGDEBUG, "DVDNAV_VTS_CHANGE");
3790 //Make sure we clear all the old overlays here, or else old forced items are left.
3791 m_overlayContainer.Clear();
3793 //Force an aspect ratio that is set in the dvdheaders if available
3794 m_CurrentVideo.hint.aspect = pStream->GetVideoAspectRatio();
3795 if( m_omxPlayerVideo.IsInited() )
3796 m_omxPlayerVideo.SendMessage(new CDVDMsgDouble(CDVDMsg::VIDEO_SET_ASPECT, m_CurrentVideo.hint.aspect));
3798 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV);
3799 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
3801 return NAVRESULT_HOLD;
3804 case DVDNAV_CELL_CHANGE:
3806 //dvdnav_cell_change_event_t* cell_change_event = (dvdnav_cell_change_event_t*)pData;
3807 CLog::Log(LOGDEBUG, "DVDNAV_CELL_CHANGE");
3809 m_dvd.state = DVDSTATE_NORMAL;
3811 if( m_omxPlayerVideo.IsInited() )
3812 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP));
3815 case DVDNAV_NAV_PACKET:
3817 //pci_t* pci = (pci_t*)pData;
3819 // this should be possible to use to make sure we get
3820 // seamless transitions over these boundaries
3821 // if we remember the old vobunits boundaries
3822 // when a packet comes out of demuxer that has
3823 // pts values outside that boundary, it belongs
3824 // to the new vobunit, wich has new timestamps
3828 case DVDNAV_HOP_CHANNEL:
3830 // This event is issued whenever a non-seamless operation has been executed.
3831 // Applications with fifos should drop the fifos content to speed up responsiveness.
3832 CLog::Log(LOGDEBUG, "DVDNAV_HOP_CHANNEL");
3833 if(m_dvd.state == DVDSTATE_SEEK)
3834 m_dvd.state = DVDSTATE_NORMAL;
3836 m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
3838 return NAVRESULT_ERROR;
3843 CLog::Log(LOGDEBUG, "DVDNAV_STOP");
3844 m_dvd.state = DVDSTATE_NORMAL;
3852 return NAVRESULT_NOP;
3855 bool COMXPlayer::ShowPVRChannelInfo(void)
3857 bool bReturn(false);
3859 if (CSettings::Get().GetBool("pvrmenu.infoswitch"))
3861 int iTimeout = CSettings::Get().GetBool("pvrmenu.infotimeout") ? CSettings::Get().GetInt("pvrmenu.infotime") : 0;
3862 g_PVRManager.ShowPlayerInfo(iTimeout);
3870 bool COMXPlayer::OnAction(const CAction &action)
3872 #define THREAD_ACTION(action) \
3874 if (!IsCurrentThread()) { \
3875 m_messenger.Put(new CDVDMsgType<CAction>(CDVDMsg::GENERAL_GUI_ACTION, action)); \
3880 CDVDInputStream::IMenus* pMenus = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
3883 if( m_dvd.state == DVDSTATE_STILL && m_dvd.iDVDStillTime != 0 && pMenus->GetTotalButtons() == 0 )
3885 switch(action.GetID())
3887 case ACTION_NEXT_ITEM:
3888 case ACTION_MOVE_RIGHT:
3889 case ACTION_MOVE_UP:
3890 case ACTION_SELECT_ITEM:
3892 THREAD_ACTION(action);
3893 /* this will force us out of the stillframe */
3894 CLog::Log(LOGDEBUG, "%s - User asked to exit stillframe", __FUNCTION__);
3895 m_dvd.iDVDStillStartTime = 0;
3896 m_dvd.iDVDStillTime = 1;
3903 switch (action.GetID())
3905 /* this code is disabled to allow switching playlist items (dvdimage "stacks") */
3907 case ACTION_PREV_ITEM: // SKIP-:
3909 THREAD_ACTION(action);
3910 CLog::Log(LOGDEBUG, " - pushed prev");
3911 pMenus->OnPrevious();
3912 g_infoManager.SetDisplayAfterSeek();
3916 case ACTION_NEXT_ITEM: // SKIP+:
3918 THREAD_ACTION(action);
3919 CLog::Log(LOGDEBUG, " - pushed next");
3921 g_infoManager.SetDisplayAfterSeek();
3926 case ACTION_SHOW_VIDEOMENU: // start button
3928 THREAD_ACTION(action);
3929 CLog::Log(LOGDEBUG, " - go to menu");
3931 if (m_playSpeed == DVD_PLAYSPEED_PAUSE)
3933 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
3934 m_callback.OnPlayBackResumed();
3936 // send a message to everyone that we've gone to the menu
3937 CGUIMessage msg(GUI_MSG_VIDEO_MENU_STARTED, 0, 0);
3938 g_windowManager.SendThreadMessage(msg);
3944 if (pMenus->IsInMenu())
3946 switch (action.GetID())
3948 case ACTION_NEXT_ITEM:
3949 THREAD_ACTION(action);
3950 CLog::Log(LOGDEBUG, " - pushed next in menu, stream will decide");
3952 g_infoManager.SetDisplayAfterSeek();
3954 case ACTION_PREV_ITEM:
3955 THREAD_ACTION(action);
3956 CLog::Log(LOGDEBUG, " - pushed prev in menu, stream will decide");
3957 pMenus->OnPrevious();
3958 g_infoManager.SetDisplayAfterSeek();
3960 case ACTION_PREVIOUS_MENU:
3961 case ACTION_NAV_BACK:
3963 THREAD_ACTION(action);
3964 CLog::Log(LOGDEBUG, " - menu back");
3968 case ACTION_MOVE_LEFT:
3970 THREAD_ACTION(action);
3971 CLog::Log(LOGDEBUG, " - move left");
3975 case ACTION_MOVE_RIGHT:
3977 THREAD_ACTION(action);
3978 CLog::Log(LOGDEBUG, " - move right");
3982 case ACTION_MOVE_UP:
3984 THREAD_ACTION(action);
3985 CLog::Log(LOGDEBUG, " - move up");
3989 case ACTION_MOVE_DOWN:
3991 THREAD_ACTION(action);
3992 CLog::Log(LOGDEBUG, " - move down");
3997 case ACTION_MOUSE_MOVE:
3998 case ACTION_MOUSE_LEFT_CLICK:
4001 g_renderManager.GetVideoRect(rs, rd);
4002 CPoint pt(action.GetAmount(), action.GetAmount(1));
4003 if (!rd.PtInRect(pt))
4004 return false; // out of bounds
4005 THREAD_ACTION(action);
4006 // convert to video coords...
4007 pt -= CPoint(rd.x1, rd.y1);
4008 pt.x *= rs.Width() / rd.Width();
4009 pt.y *= rs.Height() / rd.Height();
4010 pt += CPoint(rs.x1, rs.y1);
4011 if (action.GetID() == ACTION_MOUSE_LEFT_CLICK)
4012 return pMenus->OnMouseClick(pt);
4013 return pMenus->OnMouseMove(pt);
4016 case ACTION_SELECT_ITEM:
4018 THREAD_ACTION(action);
4019 CLog::Log(LOGDEBUG, " - button select");
4020 // show button pushed overlay
4021 if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
4022 m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_CLICKED);
4024 pMenus->ActivateButton();
4038 THREAD_ACTION(action);
4039 // Offset from key codes back to button number
4040 int button = action.GetID() - REMOTE_0;
4041 CLog::Log(LOGDEBUG, " - button pressed %d", button);
4042 pMenus->SelectButton(button);
4049 return true; // message is handled
4053 if (dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream))
4055 switch (action.GetID())
4057 case ACTION_MOVE_UP:
4058 case ACTION_NEXT_ITEM:
4059 case ACTION_CHANNEL_UP:
4060 m_messenger.Put(new CDVDMsg(CDVDMsg::PLAYER_CHANNEL_NEXT));
4061 g_infoManager.SetDisplayAfterSeek();
4062 ShowPVRChannelInfo();
4066 case ACTION_MOVE_DOWN:
4067 case ACTION_PREV_ITEM:
4068 case ACTION_CHANNEL_DOWN:
4069 m_messenger.Put(new CDVDMsg(CDVDMsg::PLAYER_CHANNEL_PREV));
4070 g_infoManager.SetDisplayAfterSeek();
4071 ShowPVRChannelInfo();
4075 case ACTION_CHANNEL_SWITCH:
4077 // Offset from key codes back to button number
4078 int channel = action.GetAmount();
4079 m_messenger.Put(new CDVDMsgInt(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER, channel));
4080 g_infoManager.SetDisplayAfterSeek();
4081 ShowPVRChannelInfo();
4088 switch (action.GetID())
4090 case ACTION_NEXT_ITEM:
4091 if (GetChapter() > 0 && GetChapter() < GetChapterCount())
4093 m_messenger.Put(new CDVDMsgPlayerSeekChapter(GetChapter() + 1));
4094 g_infoManager.SetDisplayAfterSeek();
4099 case ACTION_PREV_ITEM:
4100 if (GetChapter() > 0)
4102 m_messenger.Put(new CDVDMsgPlayerSeekChapter(GetChapter() - 1));
4103 g_infoManager.SetDisplayAfterSeek();
4110 // return false to inform the caller we didn't handle the message
4114 bool COMXPlayer::IsInMenu() const
4116 CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
4119 if( m_dvd.state == DVDSTATE_STILL )
4122 return pStream->IsInMenu();
4127 bool COMXPlayer::HasMenu()
4129 CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
4136 CStdString COMXPlayer::GetPlayerState()
4138 CSingleLock lock(m_StateSection);
4139 return m_State.player_state;
4142 bool COMXPlayer::SetPlayerState(CStdString state)
4144 m_messenger.Put(new CDVDMsgPlayerSetState(state));
4148 int COMXPlayer::GetChapterCount()
4150 CSingleLock lock(m_StateSection);
4151 return m_State.chapter_count;
4154 int COMXPlayer::GetChapter()
4156 CSingleLock lock(m_StateSection);
4157 return m_State.chapter;
4160 void COMXPlayer::GetChapterName(CStdString& strChapterName)
4162 CSingleLock lock(m_StateSection);
4163 strChapterName = m_State.chapter_name;
4166 int COMXPlayer::SeekChapter(int iChapter)
4168 if (GetChapter() > 0)
4172 if (iChapter > GetChapterCount())
4175 // Seek to the chapter.
4176 m_messenger.Put(new CDVDMsgPlayerSeekChapter(iChapter));
4177 SynchronizeDemuxer(100);
4183 int COMXPlayer::AddSubtitle(const CStdString& strSubPath)
4185 return AddSubtitleFile(strSubPath);
4188 int COMXPlayer::GetCacheLevel() const
4190 CSingleLock lock(m_StateSection);
4191 return (int)(m_StateInput.cache_level * 100);
4194 double COMXPlayer::GetQueueTime()
4196 int a = m_omxPlayerAudio.GetLevel();
4197 int v = m_omxPlayerVideo.GetLevel();
4198 return max(a, v) * 8000.0 / 100;
4201 void COMXPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info)
4203 info.bitrate = m_omxPlayerVideo.GetVideoBitrate();
4206 if (m_pDemuxer && (m_CurrentVideo.id != -1))
4207 m_pDemuxer->GetStreamCodecName(m_CurrentVideo.id, retVal);
4208 info.videoCodecName = retVal;
4209 info.videoAspectRatio = g_renderManager.GetAspectRatio();
4210 g_renderManager.GetVideoRect(info.SrcRect, info.DestRect);
4211 info.stereoMode = m_omxPlayerVideo.GetStereoMode();
4212 if (info.stereoMode == "mono")
4213 info.stereoMode = "";
4216 int COMXPlayer::GetSourceBitrate()
4219 return (int)m_pInputStream->GetBitstreamStats().GetBitrate();
4224 void COMXPlayer::GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info)
4226 if (index < 0 || index > GetAudioStreamCount() - 1)
4229 if (index == GetAudioStream())
4230 info.bitrate = m_omxPlayerAudio.GetAudioBitrate();
4231 else if (m_pDemuxer)
4233 CDemuxStreamAudio* stream = m_pDemuxer->GetStreamFromAudioId(index);
4235 info.bitrate = stream->iBitRate;
4238 OMXSelectionStream& s = m_SelectionStreams.Get(STREAM_AUDIO, index);
4239 if(s.language.length() > 0)
4240 info.language = s.language;
4242 if(s.name.length() > 0)
4245 if(s.type == STREAM_NONE)
4246 info.name += " (Invalid)";
4250 CDemuxStreamAudio* stream = static_cast<CDemuxStreamAudio*>(m_pDemuxer->GetStreamFromAudioId(index));
4253 info.channels = stream->iChannels;
4254 CStdString codecName;
4255 m_pDemuxer->GetStreamCodecName(stream->iId, codecName);
4256 info.audioCodecName = codecName;
4261 int COMXPlayer::AddSubtitleFile(const std::string& filename, const std::string& subfilename, CDemuxStream::EFlags flags)
4263 std::string ext = URIUtils::GetExtension(filename);
4264 std::string vobsubfile = subfilename;
4267 if (vobsubfile.empty())
4268 vobsubfile = URIUtils::ReplaceExtension(filename, ".sub");
4271 if(!v.Open(filename, vobsubfile))
4273 m_SelectionStreams.Update(NULL, &v);
4274 int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, m_SelectionStreams.Source(STREAM_SOURCE_DEMUX_SUB, filename), 0);
4275 m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags;
4276 m_SelectionStreams.Get(STREAM_SUBTITLE, index).filename2 = vobsubfile;
4277 ExternalStreamInfo info;
4278 CUtil::GetExternalStreamDetailsFromFilename(m_filename, vobsubfile, info);
4279 m_SelectionStreams.Get(STREAM_SUBTITLE, index).name = info.name;
4280 if (m_SelectionStreams.Get(STREAM_SUBTITLE, index).language.empty())
4281 m_SelectionStreams.Get(STREAM_SUBTITLE, index).language = info.language;
4283 if (static_cast<CDemuxStream::EFlags>(info.flag) == CDemuxStream::FLAG_NONE)
4284 m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags;
4286 m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = static_cast<CDemuxStream::EFlags>(info.flag);
4292 CStdString strReplace(URIUtils::ReplaceExtension(filename,".idx"));
4293 if (XFILE::CFile::Exists(strReplace))
4296 OMXSelectionStream s;
4297 s.source = m_SelectionStreams.Source(STREAM_SOURCE_TEXT, filename);
4298 s.type = STREAM_SUBTITLE;
4300 s.filename = filename;
4301 ExternalStreamInfo info;
4302 CUtil::GetExternalStreamDetailsFromFilename(m_filename, filename, info);
4304 s.language = info.language;
4305 if (static_cast<CDemuxStream::EFlags>(info.flag) == CDemuxStream::FLAG_NONE)
4308 s.flags = static_cast<CDemuxStream::EFlags>(info.flag);
4310 m_SelectionStreams.Update(s);
4311 return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, s.source, s.id);
4314 void COMXPlayer::UpdatePlayState(double timeout)
4316 if(m_StateInput.timestamp != 0
4317 && m_StateInput.timestamp + DVD_MSEC_TO_TIME(timeout) > m_clock.GetAbsoluteClock())
4320 SPlayerState state(m_StateInput);
4322 if (m_CurrentVideo.dts != DVD_NOPTS_VALUE)
4323 state.dts = m_CurrentVideo.dts;
4324 else if(m_CurrentAudio.dts != DVD_NOPTS_VALUE)
4325 state.dts = m_CurrentAudio.dts;
4329 state.chapter = m_pDemuxer->GetChapter();
4330 state.chapter_count = m_pDemuxer->GetChapterCount();
4331 m_pDemuxer->GetChapterName(state.chapter_name);
4333 if(state.dts == DVD_NOPTS_VALUE)
4336 state.time = DVD_TIME_TO_MSEC(state.dts + m_offset_pts);
4337 state.time_total = m_pDemuxer->GetStreamLength();
4338 state.time_src = ETIMESOURCE_CLOCK;
4341 state.canpause = true;
4342 state.canseek = true;
4346 // override from input stream if needed
4347 CDVDInputStream::IChannel* pChannel = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
4350 state.canrecord = pChannel->CanRecord();
4351 state.recording = pChannel->IsRecording();
4354 CDVDInputStream::IDisplayTime* pDisplayTime = dynamic_cast<CDVDInputStream::IDisplayTime*>(m_pInputStream);
4355 if (pDisplayTime && pDisplayTime->GetTotalTime() > 0)
4357 state.time = pDisplayTime->GetTime();
4358 state.time_total = pDisplayTime->GetTotalTime();
4359 state.time_src = ETIMESOURCE_INPUT;
4362 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
4364 if(!ptr->GetState(state.player_state))
4365 state.player_state = "";
4367 if(m_dvd.state == DVDSTATE_STILL)
4369 state.time = XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime;
4370 state.time_total = m_dvd.iDVDStillTime;
4371 state.time_src = ETIMESOURCE_MENU;
4375 if (CDVDInputStream::ISeekable* ptr = dynamic_cast<CDVDInputStream::ISeekable*>(m_pInputStream))
4377 state.canpause = ptr->CanPause();
4378 state.canseek = ptr->CanSeek();
4384 state.time = m_Edl.RemoveCutTime(llrint(state.time));
4385 state.time_total = m_Edl.RemoveCutTime(llrint(state.time_total));
4388 if(state.time_total <= 0)
4389 state.canseek = false;
4391 if (state.time_src == ETIMESOURCE_CLOCK)
4392 state.time_offset = m_offset_pts;
4393 else if (state.dts != DVD_NOPTS_VALUE)
4394 state.time_offset = DVD_MSEC_TO_TIME(state.time) - state.dts;
4396 if (m_CurrentAudio.id >= 0 && m_pDemuxer)
4398 CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentAudio.id);
4399 if (pStream && pStream->type == STREAM_AUDIO)
4400 ((CDemuxStreamAudio*)pStream)->GetStreamInfo(state.demux_audio);
4403 state.demux_audio = "";
4405 if (m_CurrentVideo.id >= 0 && m_pDemuxer)
4407 CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentVideo.id);
4408 if (pStream && pStream->type == STREAM_VIDEO)
4409 ((CDemuxStreamVideo*)pStream)->GetStreamInfo(state.demux_video);
4412 state.demux_video = "";
4414 double level, delay, offset;
4415 if(GetCachingTimes(level, delay, offset))
4417 state.cache_delay = max(0.0, delay);
4418 state.cache_level = max(0.0, min(1.0, level));
4419 state.cache_offset = offset;
4423 state.cache_delay = 0.0;
4424 state.cache_level = min(1.0, GetQueueTime() / 8000.0);
4425 state.cache_offset = GetQueueTime() / state.time_total;
4428 XFILE::SCacheStatus status;
4429 if(m_pInputStream && m_pInputStream->GetCacheStatus(&status))
4431 state.cache_bytes = status.forward;
4432 if(state.time_total)
4433 state.cache_bytes += m_pInputStream->GetLength() * GetQueueTime() / state.time_total;
4436 state.cache_bytes = 0;
4438 state.timestamp = m_clock.GetAbsoluteClock();
4439 //{CLog::Log(LOGINFO, "%s: time:%.2f stamp:%.2f dts:%d m:%d (p:%d,c:%d) =%llu", __func__, (double)state.time, (double)state.timestamp, (int)DVD_TIME_TO_MSEC(state.dts + m_offset_pts), (int)DVD_TIME_TO_MSEC(m_stamp), (int)m_playSpeed, (int)m_caching, llrint(state.time + DVD_TIME_TO_MSEC(offset)));}
4441 CSingleLock lock(m_StateSection);
4442 m_StateInput = state;
4445 void COMXPlayer::UpdateApplication(double timeout)
4447 if(m_UpdateApplication != 0
4448 && m_UpdateApplication + DVD_MSEC_TO_TIME(timeout) > m_clock.GetAbsoluteClock())
4451 CDVDInputStream::IChannel* pStream = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
4454 CFileItem item(g_application.CurrentFileItem());
4455 if(pStream->UpdateItem(item))
4457 g_application.CurrentFileItem() = item;
4458 CApplicationMessenger::Get().SetCurrentItem(item);
4461 m_UpdateApplication = m_clock.GetAbsoluteClock();
4464 bool COMXPlayer::CanRecord()
4466 CSingleLock lock(m_StateSection);
4467 return m_State.canrecord;
4470 bool COMXPlayer::IsRecording()
4472 CSingleLock lock(m_StateSection);
4473 return m_State.recording;
4476 bool COMXPlayer::Record(bool bOnOff)
4478 if (m_pInputStream && (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV) ||
4479 m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) )
4481 m_messenger.Put(new CDVDMsgBool(CDVDMsg::PLAYER_SET_RECORD, bOnOff));
4487 int COMXPlayer::GetPictureWidth()
4489 if (m_pDemuxer && (m_CurrentVideo.id != -1))
4491 CDemuxStreamVideo* stream = static_cast<CDemuxStreamVideo*>(m_pDemuxer->GetStream(m_CurrentVideo.id));
4493 return stream->iWidth;
4498 int COMXPlayer::GetPictureHeight()
4500 if (m_pDemuxer && (m_CurrentVideo.id != -1))
4502 CDemuxStreamVideo* stream = static_cast<CDemuxStreamVideo*>(m_pDemuxer->GetStream(m_CurrentVideo.id));
4504 return stream->iHeight;
4509 bool COMXPlayer::GetStreamDetails(CStreamDetails &details)
4513 std::vector<OMXSelectionStream> subs = m_SelectionStreams.Get(STREAM_SUBTITLE);
4514 std::vector<CStreamDetailSubtitle> extSubDetails;
4515 for (unsigned int i = 0; i < subs.size(); i++)
4517 if (subs[i].filename == m_filename)
4520 CStreamDetailSubtitle p;
4521 p.m_strLanguage = subs[i].language;
4522 extSubDetails.push_back(p);
4525 bool result = CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, extSubDetails, details);
4526 if (result && details.GetStreamCount(CStreamDetail::VIDEO) > 0) // this is more correct (dvds in particular)
4529 * We can only obtain the aspect & duration from dvdplayer when the Process() thread is running
4530 * and UpdatePlayState() has been called at least once. In this case dvdplayer duration/AR will
4531 * return 0 and we'll have to fallback to the (less accurate) info from the demuxer.
4533 float aspect = m_omxPlayerVideo.GetAspectRatio();
4535 ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_fAspect = aspect;
4537 int64_t duration = GetTotalTime() / 1000;
4539 ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_iDuration = duration;
4547 CStdString COMXPlayer::GetPlayingTitle()
4549 /* Currently we support only Title Name from Teletext line 30 */
4550 TextCacheStruct_t* ttcache = m_dvdPlayerTeletext.GetTeletextCache();
4551 if (ttcache && !ttcache->line30.empty())
4552 return ttcache->line30;
4557 bool COMXPlayer::SwitchChannel(const CPVRChannel &channel)
4559 if (!g_PVRManager.CheckParentalLock(channel))
4563 if (!g_PVRManager.PerformChannelSwitch(channel, true))
4566 UpdateApplication(0);
4569 /* make sure the pvr window is updated */
4570 CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
4572 pWindow->SetInvalid();
4574 /* select the new channel */
4575 m_messenger.Put(new CDVDMsgType<CPVRChannel>(CDVDMsg::PLAYER_CHANNEL_SELECT, channel));
4580 bool COMXPlayer::CachePVRStream(void) const
4582 return m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) &&
4583 !g_PVRManager.IsPlayingRecording() &&
4584 g_advancedSettings.m_bPVRCacheInDvdPlayer;
4587 void COMXPlayer::GetRenderFeatures(std::vector<int> &renderFeatures)
4589 renderFeatures.push_back(RENDERFEATURE_STRETCH);
4590 renderFeatures.push_back(RENDERFEATURE_CROP);
4591 renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO);
4592 renderFeatures.push_back(RENDERFEATURE_ZOOM);
4595 void COMXPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
4597 deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
4600 void COMXPlayer::GetDeinterlaceModes(std::vector<int> &deinterlaceModes)
4602 deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
4603 deinterlaceModes.push_back(VS_DEINTERLACEMODE_OFF);
4604 deinterlaceModes.push_back(VS_DEINTERLACEMODE_FORCE);
4607 void COMXPlayer::GetScalingMethods(std::vector<int> &scalingMethods)
4611 void COMXPlayer::GetAudioCapabilities(std::vector<int> &audioCaps)
4613 audioCaps.push_back(IPC_AUD_OFFSET);
4614 audioCaps.push_back(IPC_AUD_SELECT_STREAM);
4615 audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
4616 audioCaps.push_back(IPC_AUD_AMP);
4619 void COMXPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps)
4621 subCaps.push_back(IPC_SUBS_ALL);