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 "Application.h"
85 #include "ApplicationMessenger.h"
86 #include "DVDPerformanceCounter.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"
126 void COMXSelectionStreams::Clear(StreamType type, StreamSource source)
128 CSingleLock lock(m_section);
129 for(int i=m_Streams.size()-1;i>=0;i--)
131 if(type && m_Streams[i].type != type)
134 if(source && m_Streams[i].source != source)
137 m_Streams.erase(m_Streams.begin() + i);
141 OMXSelectionStream& COMXSelectionStreams::Get(StreamType type, int index)
143 CSingleLock lock(m_section);
145 for(int i=0;i<(int)m_Streams.size();i++)
147 if(m_Streams[i].type != type)
153 CLog::Log(LOGERROR, "%s - failed to get stream", __FUNCTION__);
157 std::vector<OMXSelectionStream> COMXSelectionStreams::Get(StreamType type)
159 std::vector<OMXSelectionStream> streams;
160 int count = Count(type);
161 for(int index = 0; index < count; ++index){
162 streams.push_back(Get(type, index));
167 #define PREDICATE_RETURN(lh, rh) \
170 return (lh) > (rh); \
173 static bool PredicateAudioPriority(const OMXSelectionStream& lh, const OMXSelectionStream& rh)
175 PREDICATE_RETURN(lh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream
176 , rh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream);
178 if(!StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.audiolanguage"), "original"))
180 CStdString audio_language = g_langInfo.GetAudioLanguage();
181 PREDICATE_RETURN(audio_language.Equals(lh.language.c_str())
182 , audio_language.Equals(rh.language.c_str()));
185 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT
186 , rh.flags & CDemuxStream::FLAG_DEFAULT);
188 PREDICATE_RETURN(lh.channels
191 PREDICATE_RETURN(StreamUtils::GetCodecPriority(lh.codec)
192 , StreamUtils::GetCodecPriority(rh.codec));
196 static bool PredicateSubtitlePriority(const OMXSelectionStream& lh, const OMXSelectionStream& rh)
198 if(!CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn)
200 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_FORCED
201 , rh.flags & CDemuxStream::FLAG_FORCED);
204 PREDICATE_RETURN(lh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream
205 , rh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream);
207 CStdString subtitle_language = g_langInfo.GetSubtitleLanguage();
208 if(!StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.subtitlelanguage"), "original"))
210 PREDICATE_RETURN((lh.source == STREAM_SOURCE_DEMUX_SUB || lh.source == STREAM_SOURCE_TEXT) && subtitle_language.Equals(lh.language.c_str())
211 , (rh.source == STREAM_SOURCE_DEMUX_SUB || rh.source == STREAM_SOURCE_TEXT) && subtitle_language.Equals(rh.language.c_str()));
214 PREDICATE_RETURN(lh.source == STREAM_SOURCE_DEMUX_SUB
215 , rh.source == STREAM_SOURCE_DEMUX_SUB);
217 PREDICATE_RETURN(lh.source == STREAM_SOURCE_TEXT
218 , rh.source == STREAM_SOURCE_TEXT);
220 if(!StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.subtitlelanguage"), "original"))
222 PREDICATE_RETURN(subtitle_language.Equals(lh.language.c_str())
223 , subtitle_language.Equals(rh.language.c_str()));
226 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT
227 , rh.flags & CDemuxStream::FLAG_DEFAULT);
232 static bool PredicateVideoPriority(const OMXSelectionStream& lh, const OMXSelectionStream& rh)
234 PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT
235 , rh.flags & CDemuxStream::FLAG_DEFAULT);
239 bool COMXSelectionStreams::Get(StreamType type, CDemuxStream::EFlags flag, OMXSelectionStream& out)
241 CSingleLock lock(m_section);
242 for(int i=0;i<(int)m_Streams.size();i++)
244 if(m_Streams[i].type != type)
246 if((m_Streams[i].flags & flag) != flag)
254 int COMXSelectionStreams::IndexOf(StreamType type, int source, int id) const
256 CSingleLock lock(m_section);
258 for(int i=0;i<(int)m_Streams.size();i++)
260 if(type && m_Streams[i].type != type)
263 if(source && m_Streams[i].source != source)
267 if(m_Streams[i].id == id)
276 int COMXSelectionStreams::IndexOf(StreamType type, COMXPlayer& p) const
278 if (p.m_pInputStream && p.m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
281 if(type == STREAM_AUDIO)
282 id = ((CDVDInputStreamNavigator*)p.m_pInputStream)->GetActiveAudioStream();
283 else if(type == STREAM_VIDEO)
284 id = p.m_CurrentVideo.id;
285 else if(type == STREAM_SUBTITLE)
286 id = ((CDVDInputStreamNavigator*)p.m_pInputStream)->GetActiveSubtitleStream();
288 return IndexOf(type, STREAM_SOURCE_NAV, id);
291 if(type == STREAM_AUDIO)
292 return IndexOf(type, p.m_CurrentAudio.source, p.m_CurrentAudio.id);
293 else if(type == STREAM_VIDEO)
294 return IndexOf(type, p.m_CurrentVideo.source, p.m_CurrentVideo.id);
295 else if(type == STREAM_SUBTITLE)
296 return IndexOf(type, p.m_CurrentSubtitle.source, p.m_CurrentSubtitle.id);
297 else if(type == STREAM_TELETEXT)
298 return IndexOf(type, p.m_CurrentTeletext.source, p.m_CurrentTeletext.id);
303 int COMXSelectionStreams::Source(StreamSource source, std::string filename)
305 CSingleLock lock(m_section);
306 int index = source - 1;
307 for(int i=0;i<(int)m_Streams.size();i++)
309 OMXSelectionStream &s = m_Streams[i];
310 if(STREAM_SOURCE_MASK(s.source) != source)
312 // if it already exists, return same
313 if(s.filename == filename)
322 void COMXSelectionStreams::Update(OMXSelectionStream& s)
324 CSingleLock lock(m_section);
325 int index = IndexOf(s.type, s.source, s.id);
328 OMXSelectionStream& o = Get(s.type, index);
329 s.type_index = o.type_index;
334 s.type_index = Count(s.type);
335 m_Streams.push_back(s);
339 void COMXSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer)
341 if(input && input->IsStreamType(DVDSTREAM_TYPE_DVD))
343 CDVDInputStreamNavigator* nav = (CDVDInputStreamNavigator*)input;
344 string filename = nav->GetFileName();
345 int source = Source(STREAM_SOURCE_NAV, filename);
348 count = nav->GetAudioStreamCount();
349 for(int i=0;i<count;i++)
351 OMXSelectionStream s;
353 s.type = STREAM_AUDIO;
355 s.flags = CDemuxStream::FLAG_NONE;
356 s.filename = filename;
358 DVDNavStreamInfo info;
359 nav->GetAudioStreamInfo(i, info);
361 s.language = info.language;
362 s.channels = info.channels;
366 count = nav->GetSubTitleStreamCount();
367 for(int i=0;i<count;i++)
369 OMXSelectionStream s;
371 s.type = STREAM_SUBTITLE;
373 s.flags = CDemuxStream::FLAG_NONE;
374 s.filename = filename;
377 DVDNavStreamInfo info;
378 nav->GetSubtitleStreamInfo(i, info);
380 s.language = info.language;
386 string filename = demuxer->GetFileName();
387 int count = demuxer->GetNrOfStreams();
389 if(input) /* hack to know this is sub decoder */
390 source = Source(STREAM_SOURCE_DEMUX, filename);
392 source = Source(STREAM_SOURCE_DEMUX_SUB, filename);
395 for(int i=0;i<count;i++)
397 CDemuxStream* stream = demuxer->GetStream(i);
398 /* make sure stream is marked with right source */
399 stream->source = source;
401 OMXSelectionStream s;
403 s.type = stream->type;
405 s.language = stream->language;
407 if (s.language.length() == 2)
410 g_LangCodeExpander.ConvertToThreeCharCode(lang, stream->language);
414 s.flags = stream->flags;
415 s.filename = demuxer->GetFileName();
416 stream->GetStreamName(s.name);
418 demuxer->GetStreamCodecName(stream->iId, codec);
420 s.channels = 0; // Default to 0. Overwrite if STREAM_AUDIO below.
421 if(stream->type == STREAM_AUDIO)
424 ((CDemuxStreamAudio*)stream)->GetStreamType(type);
425 if(type.length() > 0)
427 if(s.name.length() > 0)
431 s.channels = ((CDemuxStreamAudio*)stream)->iChannels;
438 COMXPlayer::COMXPlayer(IPlayerCallback &callback)
440 CThread("OMXPlayer"),
441 m_CurrentAudio(STREAM_AUDIO, DVDPLAYER_AUDIO),
442 m_CurrentVideo(STREAM_VIDEO, DVDPLAYER_VIDEO),
443 m_CurrentSubtitle(STREAM_SUBTITLE, DVDPLAYER_SUBTITLE),
444 m_CurrentTeletext(STREAM_TELETEXT, DVDPLAYER_TELETEXT),
445 m_messenger("player"),
446 m_omxPlayerVideo(&m_av_clock, &m_overlayContainer, m_messenger),
447 m_omxPlayerAudio(&m_av_clock, m_messenger),
448 m_dvdPlayerSubtitle(&m_overlayContainer),
449 m_dvdPlayerTeletext(),
453 m_pSubtitleDemuxer = NULL;
454 m_pInputStream = NULL;
458 m_EdlAutoSkipMarkers.Clear();
459 m_UpdateApplication = 0;
461 m_bAbortRequest = false;
464 m_playSpeed = DVD_PLAYSPEED_NORMAL;
465 m_caching = CACHESTATE_DONE;
469 memset(&m_SpeedState, 0, sizeof(m_SpeedState));
471 #ifdef DVDDEBUG_MESSAGE_TRACKER
472 g_dvdMessageTracker.Init();
476 COMXPlayer::~COMXPlayer()
480 #ifdef DVDDEBUG_MESSAGE_TRACKER
481 g_dvdMessageTracker.DeInit();
485 bool COMXPlayer::OpenFile(const CFileItem &file, const CPlayerOptions &options)
489 CLog::Log(LOGNOTICE, "COMXPlayer: Opening: %s", file.GetPath().c_str());
491 // if playing a file close it first
492 // this has to be changed so we won't have to close it.
496 if(!m_av_clock.OMXInitialize(&m_clock, false, false))
500 if(CSettings::Get().GetBool("videoplayer.adjustrefreshrate"))
501 m_av_clock.HDMIClockSync();
503 m_bAbortRequest = false;
505 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
508 m_UpdateApplication = 0;
510 m_current_volume = 0;
511 m_current_mute = false;
512 m_change_volume = true;
514 m_PlayerOptions = options;
516 m_mimetype = file.GetMimeType();
517 m_filename = file.GetPath();
521 #if defined(HAS_VIDEO_PLAYBACK)
522 g_renderManager.PreInit();
526 if(!m_ready.WaitMSec(100))
528 CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY);
532 while(!m_ready.WaitMSec(1))
533 g_windowManager.ProcessRenderLoop(false);
538 // Playback might have been stopped due to some error
539 if (m_bStop || m_bAbortRequest)
546 CLog::Log(LOGERROR, "%s - Exception thrown on open", __FUNCTION__);
551 bool COMXPlayer::CloseFile()
553 CLog::Log(LOGDEBUG, "COMXPlayer::CloseFile");
555 // unpause the player
556 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
558 // set the abort request so that other threads can finish up
559 m_bAbortRequest = true;
561 // tell demuxer to abort
565 if(m_pSubtitleDemuxer)
566 m_pSubtitleDemuxer->Abort();
569 m_pInputStream->Abort();
571 CLog::Log(LOGDEBUG, "COMXPlayer: waiting for threads to exit");
573 // wait for the main thread to finish up
574 // since this main thread cleans up all other resources and threads
575 // we are done after the StopThread call
579 m_EdlAutoSkipMarkers.Clear();
584 CLog::Log(LOGNOTICE, "DVDPlayer: finished waiting");
585 #if defined(HAS_VIDEO_PLAYBACK)
586 g_renderManager.UnInit();
591 bool COMXPlayer::IsPlaying() const
596 void COMXPlayer::OnStartup()
598 m_CurrentVideo.Clear();
599 m_CurrentAudio.Clear();
600 m_CurrentSubtitle.Clear();
601 m_CurrentTeletext.Clear();
605 CUtil::ClearTempFonts();
608 bool COMXPlayer::OpenInputStream()
611 SAFE_DELETE(m_pInputStream);
613 CLog::Log(LOGNOTICE, "Creating InputStream");
615 // correct the filename if needed
616 CStdString filename(m_filename);
617 if (filename.Find("dvd://") == 0
618 || filename.CompareNoCase("iso9660://video_ts/video_ts.ifo") == 0)
620 m_filename = g_mediaManager.TranslateDevicePath("");
623 // before creating the input stream, if this is an HLS playlist then get the
624 // most appropriate bitrate based on our network settings
625 // ensure to strip off the url options by using a temp CURL object
626 if (filename.Left(7) == "http://" && CURL(filename).GetFileName().Right(5) == ".m3u8")
628 // get the available bandwidth (as per user settings)
629 int maxrate = CSettings::Get().GetInt("network.bandwidth");
633 // determine the most appropriate stream
634 m_filename = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(m_filename, (size_t)maxrate);
636 m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_filename, m_mimetype);
637 if(m_pInputStream == NULL)
639 CLog::Log(LOGERROR, "COMXPlayer::OpenInputStream - unable to create input stream for [%s]", m_filename.c_str());
643 m_pInputStream->SetFileItem(m_item);
645 if (!m_pInputStream->Open(m_filename.c_str(), m_mimetype))
647 CLog::Log(LOGERROR, "COMXPlayer::OpenInputStream - error opening [%s]", m_filename.c_str());
651 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
652 || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY))
654 CLog::Log(LOGINFO, "COMXPlayer::OpenInputStream - DVD/BD not supported - Will try...");
657 // find any available external subtitles for non dvd files
658 if (!m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
659 && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)
660 && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV)
661 && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP))
663 // find any available external subtitles
664 std::vector<CStdString> filenames;
665 CUtil::ScanForExternalSubtitles( m_filename, filenames );
667 // find any upnp subtitles
668 CStdString key("upnp:subtitle:1");
669 for(unsigned s = 1; m_item.HasProperty(key); key.Format("upnp:subtitle:%u", ++s))
670 filenames.push_back(m_item.GetProperty(key).asString());
672 for(unsigned int i=0;i<filenames.size();i++)
674 // if vobsub subtitle:
675 if (URIUtils::HasExtension(filenames[i], ".idx"))
677 CStdString strSubFile;
678 if ( CUtil::FindVobSubPair( filenames, filenames[i], strSubFile ) )
679 AddSubtitleFile(filenames[i], strSubFile);
683 if ( !CUtil::IsVobSub(filenames, filenames[i] ) )
685 AddSubtitleFile(filenames[i]);
688 } // end loop over all subtitle files
690 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true;
693 SetAVDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay);
694 SetSubTitleDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay);
698 m_iChannelEntryTimeOut = 0;
703 bool COMXPlayer::OpenDemuxStream()
706 SAFE_DELETE(m_pDemuxer);
708 CLog::Log(LOGNOTICE, "Creating Demuxer");
713 while(!m_bStop && attempts-- > 0)
715 m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
716 if(!m_pDemuxer && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
720 else if(!m_pDemuxer && m_pInputStream->NextStream() != CDVDInputStream::NEXTSTREAM_NONE)
722 CLog::Log(LOGDEBUG, "%s - New stream available from input, retry open", __FUNCTION__);
730 CLog::Log(LOGERROR, "%s - Error creating demuxer", __FUNCTION__);
737 CLog::Log(LOGERROR, "%s - Exception thrown when opening demuxer", __FUNCTION__);
741 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
742 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV);
743 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
745 int64_t len = m_pInputStream->GetLength();
746 int64_t tim = m_pDemuxer->GetStreamLength();
747 if(len > 0 && tim > 0)
748 m_pInputStream->SetReadRate(len * 1000 / tim);
753 void COMXPlayer::OpenDefaultStreams(bool reset)
755 // if input stream dictate, we will open later
756 if(m_dvd.iSelectedAudioStream >= 0
757 || m_dvd.iSelectedSPUStream >= 0)
760 OMXSelectionStreams streams;
764 streams = m_SelectionStreams.Get(STREAM_VIDEO, PredicateVideoPriority);
766 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
768 if(OpenVideoStream(it->id, it->source, reset))
772 CloseVideoStream(true);
775 if(m_PlayerOptions.video_only)
778 streams = m_SelectionStreams.Get(STREAM_AUDIO, PredicateAudioPriority);
781 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
783 if(OpenAudioStream(it->id, it->source, reset))
787 CloseAudioStream(true);
790 m_omxPlayerVideo.EnableSubtitle(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn);
792 // open subtitle stream
793 streams = m_SelectionStreams.Get(STREAM_SUBTITLE, PredicateSubtitlePriority);
795 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
797 if(OpenSubtitleStream(it->id, it->source))
800 if(it->flags & CDemuxStream::FLAG_FORCED)
801 m_omxPlayerVideo.EnableSubtitle(true);
805 CloseSubtitleStream(true);
807 // open teletext stream
808 streams = m_SelectionStreams.Get(STREAM_TELETEXT);
810 for(OMXSelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it)
812 if(OpenTeletextStream(it->id, it->source))
816 CloseTeletextStream(true);
819 bool COMXPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
822 // check if we should read from subtitle demuxer
823 if(m_dvdPlayerSubtitle.AcceptsData() && m_pSubtitleDemuxer)
825 if(m_pSubtitleDemuxer)
826 packet = m_pSubtitleDemuxer->Read();
830 UpdateCorrection(packet, m_offset_pts);
831 if(packet->iStreamId < 0)
834 stream = m_pSubtitleDemuxer->GetStream(packet->iStreamId);
837 CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__);
840 if(stream->source == STREAM_SOURCE_NONE)
842 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX_SUB);
843 m_SelectionStreams.Update(NULL, m_pSubtitleDemuxer);
849 // read a data frame from stream.
851 packet = m_pDemuxer->Read();
855 // stream changed, update and open defaults
856 if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE)
858 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
859 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
860 OpenDefaultStreams(false);
862 // reevaluate HasVideo/Audio, we may have switched from/to a radio channel
863 if(m_CurrentVideo.id < 0)
865 if(m_CurrentAudio.id < 0)
871 UpdateCorrection(packet, m_offset_pts);
873 if(packet->iStreamId < 0)
878 stream = m_pDemuxer->GetStream(packet->iStreamId);
881 CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__);
884 if(stream->source == STREAM_SOURCE_NONE)
886 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
887 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
895 bool COMXPlayer::IsValidStream(COMXCurrentStream& stream)
898 return true; // we consider non selected as valid
900 int source = STREAM_SOURCE_MASK(stream.source);
901 if(source == STREAM_SOURCE_TEXT)
903 if(source == STREAM_SOURCE_DEMUX_SUB)
905 CDemuxStream* st = m_pSubtitleDemuxer->GetStream(stream.id);
906 if(st == NULL || st->disabled)
908 if(st->type != stream.type)
912 if(source == STREAM_SOURCE_DEMUX)
914 CDemuxStream* st = m_pDemuxer->GetStream(stream.id);
915 if(st == NULL || st->disabled)
917 if(st->type != stream.type)
920 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
922 if(stream.type == STREAM_AUDIO && st->iPhysicalId != m_dvd.iSelectedAudioStream)
924 if(stream.type == STREAM_SUBTITLE && st->iPhysicalId != m_dvd.iSelectedSPUStream)
934 bool COMXPlayer::IsBetterStream(COMXCurrentStream& current, CDemuxStream* stream)
936 // Do not reopen non-video streams if we're in video-only mode
937 if(m_PlayerOptions.video_only && current.type != STREAM_VIDEO)
943 if (m_pInputStream && ( m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
944 || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY) ) )
948 source_type = STREAM_SOURCE_MASK(current.source);
949 if(source_type != STREAM_SOURCE_DEMUX
950 && source_type != STREAM_SOURCE_NONE)
953 source_type = STREAM_SOURCE_MASK(stream->source);
954 if(source_type != STREAM_SOURCE_DEMUX
955 || stream->type != current.type
956 || stream->iId == current.id)
959 if(current.type == STREAM_AUDIO && stream->iPhysicalId == m_dvd.iSelectedAudioStream)
961 if(current.type == STREAM_SUBTITLE && stream->iPhysicalId == m_dvd.iSelectedSPUStream)
963 if(current.type == STREAM_VIDEO && current.id < 0)
968 if(stream->source == current.source
969 && stream->iId == current.id)
972 if(stream->type != current.type)
975 if(current.type == STREAM_SUBTITLE)
984 void COMXPlayer::Process()
986 bool bOmxWaitVideo = false;
987 bool bOmxWaitAudio = false;
988 bool bOmxSentEOFs = false;
990 if (!OpenInputStream())
992 m_bAbortRequest = true;
996 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
998 CLog::Log(LOGNOTICE, "OMXPlayer: playing a file with menu's");
999 m_PlayerOptions.starttime = 0;
1001 if(m_PlayerOptions.state.size() > 0)
1002 ptr->SetState(m_PlayerOptions.state);
1003 else if(CDVDInputStreamNavigator* nav = dynamic_cast<CDVDInputStreamNavigator*>(m_pInputStream))
1004 nav->EnableSubtitleStream(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn);
1006 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true;
1009 if(!OpenDemuxStream())
1011 m_bAbortRequest = true;
1015 // allow renderer to switch to fullscreen if requested
1016 m_omxPlayerVideo.EnableFullscreen(m_PlayerOptions.fullscreen);
1018 OpenDefaultStreams();
1020 // look for any EDL files
1022 m_EdlAutoSkipMarkers.Clear();
1023 float fFramesPerSecond;
1024 if (m_CurrentVideo.id >= 0 && m_CurrentVideo.hint.fpsrate > 0 && m_CurrentVideo.hint.fpsscale > 0)
1026 fFramesPerSecond = (float)m_CurrentVideo.hint.fpsrate / (float)m_CurrentVideo.hint.fpsscale;
1027 m_Edl.ReadEditDecisionLists(m_filename, fFramesPerSecond, m_CurrentVideo.hint.height);
1031 * Check to see if the demuxer should start at something other than time 0. This will be the case
1032 * if there was a start time specified as part of the "Start from where last stopped" (aka
1033 * auto-resume) feature or if there is an EDL cut or commercial break that starts at time 0.
1037 if(m_PlayerOptions.starttime > 0 || m_PlayerOptions.startpercent > 0)
1039 if (m_PlayerOptions.startpercent > 0 && m_pDemuxer)
1041 int64_t playerStartTime = (int64_t) ( ( (float) m_pDemuxer->GetStreamLength() ) * ( m_PlayerOptions.startpercent/(float)100 ) );
1042 starttime = m_Edl.RestoreCutTime(playerStartTime);
1046 starttime = m_Edl.RestoreCutTime((int64_t)m_PlayerOptions.starttime * 1000); // s to ms
1048 CLog::Log(LOGDEBUG, "%s - Start position set to last stopped position: %d", __FUNCTION__, starttime);
1050 else if(m_Edl.InCut(0, &cut)
1051 && (cut.action == CEdl::CUT || cut.action == CEdl::COMM_BREAK))
1053 starttime = cut.end;
1054 CLog::Log(LOGDEBUG, "%s - Start position set to end of first cut or commercial break: %d", __FUNCTION__, starttime);
1055 if(cut.action == CEdl::COMM_BREAK)
1058 * Setup auto skip markers as if the commercial break had been skipped using standard
1061 m_EdlAutoSkipMarkers.commbreak_start = cut.start;
1062 m_EdlAutoSkipMarkers.commbreak_end = cut.end;
1063 m_EdlAutoSkipMarkers.seek_to_start = true;
1068 double startpts = DVD_NOPTS_VALUE;
1071 if (m_pDemuxer->SeekTime(starttime, false, &startpts))
1072 CLog::Log(LOGDEBUG, "%s - starting demuxer from: %d", __FUNCTION__, starttime);
1074 CLog::Log(LOGDEBUG, "%s - failed to start demuxing from: %d", __FUNCTION__, starttime);
1077 if(m_pSubtitleDemuxer)
1079 if(m_pSubtitleDemuxer->SeekTime(starttime, false, &startpts))
1080 CLog::Log(LOGDEBUG, "%s - starting subtitle demuxer from: %d", __FUNCTION__, starttime);
1082 CLog::Log(LOGDEBUG, "%s - failed to start subtitle demuxing from: %d", __FUNCTION__, starttime);
1086 // make sure all selected stream have data on startup
1087 if (CachePVRStream())
1088 SetCaching(CACHESTATE_PVR);
1090 // make sure application know our info
1091 UpdateApplication(0);
1094 if(m_PlayerOptions.identify == false)
1095 m_callback.OnPlayBackStarted();
1097 // we are done initializing now, set the readyevent
1100 if (!CachePVRStream())
1101 SetCaching(CACHESTATE_FLUSH);
1103 while (!m_bAbortRequest)
1107 static unsigned count;
1108 if ((count++ & 15) == 0)
1110 vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
1111 m_omxPlayerVideo.GetDecoderBufferSize()-m_omxPlayerVideo.GetDecoderFreeSpace(),
1112 0 , 0, m_omxPlayerVideo.GetDecoderBufferSize());
1113 vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
1114 (int)(100.0*m_omxPlayerAudio.GetDelay()), 0, 0, 100*AUDIO_BUFFER_SECONDS);
1115 vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d",
1116 m_omxPlayerVideo.GetLevel(), 0, 0, 100);
1117 vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d",
1118 m_omxPlayerAudio.GetLevel(), 0, 0, 100);
1121 // handle messages send to this thread, like seek or demuxer reset requests
1127 // should we open a new input stream?
1130 if (OpenInputStream() == false)
1132 CLog::Log(LOGERROR, "%s - Closing stream due to OpenInputStream()", __FUNCTION__);
1133 m_bAbortRequest = true;
1138 // should we open a new demuxer?
1141 if (m_pInputStream->NextStream() == CDVDInputStream::NEXTSTREAM_NONE)
1144 if (m_pInputStream->IsEOF())
1147 if (OpenDemuxStream() == false)
1149 CLog::Log(LOGERROR, "%s - Closing stream due to OpenDemuxStream()", __FUNCTION__);
1150 m_bAbortRequest = true;
1154 OpenDefaultStreams();
1156 // never allow first frames after open to be skipped
1157 if( m_omxPlayerVideo.IsInited() )
1158 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP));
1160 if (CachePVRStream())
1161 SetCaching(CACHESTATE_PVR);
1163 UpdateApplication(0);
1167 // handle eventual seeks due to playspeed
1170 // update player state
1171 UpdatePlayState(200);
1173 // update application with our state
1174 UpdateApplication(1000);
1176 // OMX emergency exit
1177 if(HasAudio() && m_omxPlayerAudio.BadState())
1179 CLog::Log(LOGERROR, "%s - Closing stream due to m_omxPlayerAudio.BadState()", __FUNCTION__);
1180 m_bAbortRequest = true;
1184 if (CheckDelayedChannelEntry())
1187 // if the queues are full, no need to read more
1188 if ((!m_omxPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) ||
1189 (!m_omxPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0))
1195 // always yield to players if they have data levels > 50 percent
1196 if((m_omxPlayerAudio.GetLevel() > 50 || m_CurrentAudio.id < 0)
1197 && (m_omxPlayerVideo.GetLevel() > 50 || m_CurrentVideo.id < 0))
1200 DemuxPacket* pPacket = NULL;
1201 CDemuxStream *pStream = NULL;
1202 ReadPacket(pPacket, pStream);
1203 if (pPacket && !pStream)
1205 /* probably a empty packet, just free it and move on */
1206 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
1211 // reset eos state when we get a packet (e.g. for case of seek after eos)
1212 bOmxWaitVideo = false;
1213 bOmxWaitAudio = false;
1214 bOmxSentEOFs = false;
1218 // when paused, demuxer could be be returning empty
1219 if (m_playSpeed == DVD_PLAYSPEED_PAUSE)
1222 // check for a still frame state
1223 if (CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
1225 // stills will be skipped
1226 if(m_dvd.state == DVDSTATE_STILL)
1228 if (m_dvd.iDVDStillTime > 0)
1230 if ((XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime) >= m_dvd.iDVDStillTime)
1232 m_dvd.iDVDStillTime = 0;
1233 m_dvd.iDVDStillStartTime = 0;
1234 m_dvd.state = DVDSTATE_NORMAL;
1235 pStream->SkipStill();
1242 // if there is another stream available, reopen demuxer
1243 CDVDInputStream::ENextStream next = m_pInputStream->NextStream();
1244 if(next == CDVDInputStream::NEXTSTREAM_OPEN)
1246 SAFE_DELETE(m_pDemuxer);
1247 m_CurrentAudio.stream = NULL;
1248 m_CurrentVideo.stream = NULL;
1249 m_CurrentSubtitle.stream = NULL;
1253 // input stream asked us to just retry
1254 if(next == CDVDInputStream::NEXTSTREAM_RETRY)
1260 // make sure we tell all players to finish it's data
1263 if(m_CurrentAudio.inited)
1265 m_omxPlayerAudio.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF));
1266 bOmxWaitAudio = true;
1268 if(m_CurrentVideo.inited)
1270 m_omxPlayerVideo.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF));
1271 bOmxWaitVideo = true;
1273 if(m_CurrentSubtitle.inited)
1274 m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF));
1275 if(m_CurrentTeletext.inited)
1276 m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF));
1277 m_CurrentAudio.inited = false;
1278 m_CurrentVideo.inited = false;
1279 m_CurrentSubtitle.inited = false;
1280 m_CurrentTeletext.inited = false;
1281 bOmxSentEOFs = true;
1284 // if we are caching, start playing it again
1285 SetCaching(CACHESTATE_DONE);
1287 // while players are still playing, keep going to allow seekbacks
1288 if(m_omxPlayerVideo.HasData()
1289 || m_omxPlayerAudio.HasData())
1295 // wait for omx components to finish
1296 if(bOmxWaitVideo && !m_omxPlayerVideo.IsEOS())
1301 if(bOmxWaitAudio && !m_omxPlayerAudio.IsEOS())
1307 if (!m_pInputStream->IsEOF())
1308 CLog::Log(LOGINFO, "%s - eof reading from demuxer", __FUNCTION__);
1310 m_CurrentAudio.started = false;
1311 m_CurrentVideo.started = false;
1312 m_CurrentSubtitle.started = false;
1313 m_CurrentTeletext.started = false;
1318 // it's a valid data packet, reset error counter
1321 // check so that none of our streams has become invalid
1322 if (!IsValidStream(m_CurrentAudio) && m_omxPlayerAudio.IsStalled()) CloseAudioStream(true);
1323 if (!IsValidStream(m_CurrentVideo) && m_omxPlayerVideo.IsStalled()) CloseVideoStream(true);
1324 if (!IsValidStream(m_CurrentSubtitle) && m_dvdPlayerSubtitle.IsStalled()) CloseSubtitleStream(true);
1325 if (!IsValidStream(m_CurrentTeletext)) CloseTeletextStream(true);
1327 // see if we can find something better to play
1328 if (IsBetterStream(m_CurrentAudio, pStream)) OpenAudioStream (pStream->iId, pStream->source);
1329 if (IsBetterStream(m_CurrentVideo, pStream)) OpenVideoStream (pStream->iId, pStream->source);
1330 if (IsBetterStream(m_CurrentSubtitle, pStream)) OpenSubtitleStream(pStream->iId, pStream->source);
1331 if (IsBetterStream(m_CurrentTeletext, pStream)) OpenTeletextStream(pStream->iId, pStream->source);
1333 if(m_change_volume && m_CurrentAudio.started)
1335 if(m_player_audio.SetCurrentVolume(m_current_mute ? VOLUME_MINIMUM : m_current_volume))
1336 m_change_volume = false;
1339 // process the packet
1340 ProcessPacket(pStream, pPacket);
1342 // check if in a cut or commercial break that should be automatically skipped
1343 CheckAutoSceneSkip();
1347 bool COMXPlayer::CheckDelayedChannelEntry(void)
1349 bool bReturn(false);
1351 if (m_iChannelEntryTimeOut > 0 && XbmcThreads::SystemClockMillis() >= m_iChannelEntryTimeOut)
1353 CFileItem currentFile(g_application.CurrentFileItem());
1354 CPVRChannel *currentChannel = currentFile.GetPVRChannelInfoTag();
1355 SwitchChannel(*currentChannel);
1358 m_iChannelEntryTimeOut = 0;
1364 void COMXPlayer::ProcessPacket(CDemuxStream* pStream, DemuxPacket* pPacket)
1366 /* process packet if it belongs to selected stream. for dvd's don't allow automatic opening of streams*/
1367 OMXStreamLock lock(this);
1371 if (pPacket->iStreamId == m_CurrentAudio.id && pStream->source == m_CurrentAudio.source && pStream->type == STREAM_AUDIO)
1372 ProcessAudioData(pStream, pPacket);
1373 else if (pPacket->iStreamId == m_CurrentVideo.id && pStream->source == m_CurrentVideo.source && pStream->type == STREAM_VIDEO)
1374 ProcessVideoData(pStream, pPacket);
1375 else if (pPacket->iStreamId == m_CurrentSubtitle.id && pStream->source == m_CurrentSubtitle.source && pStream->type == STREAM_SUBTITLE)
1376 ProcessSubData(pStream, pPacket);
1377 else if (pPacket->iStreamId == m_CurrentTeletext.id && pStream->source == m_CurrentTeletext.source && pStream->type == STREAM_TELETEXT)
1378 ProcessTeletextData(pStream, pPacket);
1381 pStream->SetDiscard(AVDISCARD_ALL);
1382 CDVDDemuxUtils::FreeDemuxPacket(pPacket); // free it since we won't do anything with it
1387 CLog::Log(LOGERROR, "%s - Exception thrown when processing demux packet", __FUNCTION__);
1392 void COMXPlayer::ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket)
1394 if (m_CurrentAudio.stream != (void*)pStream
1395 || m_CurrentAudio.changes != pStream->changes)
1397 /* check so that dmuxer hints or extra data hasn't changed */
1398 /* if they have, reopen stream */
1400 if (m_CurrentAudio.hint != CDVDStreamInfo(*pStream, true))
1401 OpenAudioStream( pPacket->iStreamId, pStream->source );
1403 m_CurrentAudio.stream = (void*)pStream;
1406 // check if we are too slow and need to recache
1407 CheckStartCaching(m_CurrentAudio);
1409 CheckContinuity(m_CurrentAudio, pPacket);
1410 UpdateTimestamps(m_CurrentAudio, pPacket);
1413 if (CheckPlayerInit(m_CurrentAudio, DVDPLAYER_AUDIO))
1417 * If CheckSceneSkip() returns true then demux point is inside an EDL cut and the packets are dropped.
1418 * If not inside a hard cut, but the demux point has reached an EDL mute section then trigger the
1419 * AUDIO_SILENCE state. The AUDIO_SILENCE state is reverted as soon as the demux point is outside
1420 * of any EDL section while EDL mute is still active.
1423 if (CheckSceneSkip(m_CurrentAudio))
1425 else if (m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) && cut.action == CEdl::MUTE // Inside EDL mute
1426 && !m_EdlAutoSkipMarkers.mute) // Mute not already triggered
1428 m_omxPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, true));
1429 m_EdlAutoSkipMarkers.mute = true;
1431 else if (!m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) // Outside of any EDL
1432 && m_EdlAutoSkipMarkers.mute) // But the mute hasn't been removed yet
1434 m_omxPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, false));
1435 m_EdlAutoSkipMarkers.mute = false;
1438 m_omxPlayerAudio.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1441 void COMXPlayer::ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket)
1443 if (m_CurrentVideo.stream != (void*)pStream
1444 || m_CurrentVideo.changes != pStream->changes)
1446 /* check so that dmuxer hints or extra data hasn't changed */
1447 /* if they have reopen stream */
1449 if (m_CurrentVideo.hint != CDVDStreamInfo(*pStream, true))
1450 OpenVideoStream(pPacket->iStreamId, pStream->source);
1452 m_CurrentVideo.stream = (void*)pStream;
1455 // check if we are too slow and need to recache
1456 CheckStartCaching(m_CurrentVideo);
1458 if( pPacket->iSize != 4) //don't check the EOF_SEQUENCE of stillframes
1460 CheckContinuity(m_CurrentVideo, pPacket);
1461 UpdateTimestamps(m_CurrentVideo, pPacket);
1465 if (CheckPlayerInit(m_CurrentVideo, DVDPLAYER_VIDEO))
1468 if (CheckSceneSkip(m_CurrentVideo))
1471 m_omxPlayerVideo.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1474 void COMXPlayer::ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket)
1476 if (m_CurrentSubtitle.stream != (void*)pStream
1477 || m_CurrentSubtitle.changes != pStream->changes)
1479 /* check so that dmuxer hints or extra data hasn't changed */
1480 /* if they have reopen stream */
1482 if (m_CurrentSubtitle.hint != CDVDStreamInfo(*pStream, true))
1483 OpenSubtitleStream(pPacket->iStreamId, pStream->source);
1485 m_CurrentSubtitle.stream = (void*)pStream;
1488 UpdateTimestamps(m_CurrentSubtitle, pPacket);
1491 if (CheckPlayerInit(m_CurrentSubtitle, DVDPLAYER_SUBTITLE))
1494 if (CheckSceneSkip(m_CurrentSubtitle))
1497 m_dvdPlayerSubtitle.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1499 if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
1500 m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL);
1503 void COMXPlayer::ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket)
1505 if (m_CurrentTeletext.stream != (void*)pStream
1506 || m_CurrentTeletext.changes != pStream->changes)
1508 /* check so that dmuxer hints or extra data hasn't changed */
1509 /* if they have, reopen stream */
1510 if (m_CurrentTeletext.hint != CDVDStreamInfo(*pStream, true))
1511 OpenTeletextStream( pPacket->iStreamId, pStream->source );
1513 m_CurrentTeletext.stream = (void*)pStream;
1515 UpdateTimestamps(m_CurrentTeletext, pPacket);
1518 if (CheckPlayerInit(m_CurrentTeletext, DVDPLAYER_TELETEXT))
1521 if (CheckSceneSkip(m_CurrentTeletext))
1524 m_dvdPlayerTeletext.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop));
1527 bool COMXPlayer::GetCachingTimes(double& level, double& delay, double& offset)
1529 if(!m_pInputStream || !m_pDemuxer)
1532 XFILE::SCacheStatus status;
1533 if (!m_pInputStream->GetCacheStatus(&status))
1536 int64_t cached = status.forward;
1537 unsigned currate = status.currate;
1538 unsigned maxrate = status.maxrate;
1539 bool full = status.full;
1541 int64_t length = m_pInputStream->GetLength();
1542 int64_t remain = length - m_pInputStream->Seek(0, SEEK_CUR);
1544 if(cached < 0 || length <= 0 || remain < 0)
1547 double play_sbp = DVD_MSEC_TO_TIME(m_pDemuxer->GetStreamLength()) / length;
1548 double queued = 1000.0 * GetQueueTime() / play_sbp;
1552 offset = (double)(cached + queued) / length;
1557 double cache_sbp = 1.1 * (double)DVD_TIME_BASE / currate; /* underestimate by 10 % */
1558 double play_left = play_sbp * (remain + queued); /* time to play out all remaining bytes */
1559 double cache_left = cache_sbp * (remain - cached); /* time to cache the remaining bytes */
1560 double cache_need = std::max(0.0, remain - play_left / cache_sbp); /* bytes needed until play_left == cache_left */
1562 delay = cache_left - play_left;
1564 if (full && (currate < maxrate) )
1565 level = -1.0; /* buffer is full & our read rate is too low */
1567 level = (cached + queued) / (cache_need + queued);
1572 void COMXPlayer::HandlePlaySpeed()
1574 ECacheState caching = m_caching;
1576 if(IsInMenu() && caching != CACHESTATE_DONE)
1577 caching = CACHESTATE_DONE;
1579 if(caching == CACHESTATE_FULL)
1581 double level, delay, offset;
1582 if(GetCachingTimes(level, delay, offset))
1586 CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(21454), g_localizeStrings.Get(21455));
1587 caching = CACHESTATE_INIT;
1590 caching = CACHESTATE_INIT;
1594 if ((!m_omxPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0)
1595 || (!m_omxPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0))
1596 caching = CACHESTATE_INIT;
1600 if(caching == CACHESTATE_INIT)
1602 // if all enabled streams have been inited we are done
1603 if((m_CurrentVideo.id < 0 || m_CurrentVideo.started)
1604 && (m_CurrentAudio.id < 0 || m_CurrentAudio.started))
1605 caching = CACHESTATE_PLAY;
1607 // handle situation that we get no data on one stream
1608 if(m_CurrentAudio.id >= 0 && m_CurrentVideo.id >= 0)
1610 if ((!m_omxPlayerAudio.AcceptsData() && !m_CurrentVideo.started)
1611 || (!m_omxPlayerVideo.AcceptsData() && !m_CurrentAudio.started))
1613 caching = CACHESTATE_DONE;
1618 if (caching == CACHESTATE_PVR)
1620 bool bGotAudio(m_pDemuxer->GetNrOfAudioStreams() > 0);
1621 bool bGotVideo(m_pDemuxer->GetNrOfVideoStreams() > 0);
1622 bool bAudioLevelOk(m_omxPlayerAudio.GetLevel() > g_advancedSettings.m_iPVRMinAudioCacheLevel);
1623 bool bVideoLevelOk(m_omxPlayerVideo.GetLevel() > g_advancedSettings.m_iPVRMinVideoCacheLevel);
1624 bool bAudioFull(!m_omxPlayerAudio.AcceptsData());
1625 bool bVideoFull(!m_omxPlayerVideo.AcceptsData());
1627 if (/* if all streams got at least g_advancedSettings.m_iPVRMinCacheLevel in their buffers, we're done */
1628 ((bGotVideo || bGotAudio) && (!bGotAudio || bAudioLevelOk) && (!bGotVideo || bVideoLevelOk)) ||
1629 /* or if one of the buffers is full */
1630 (bAudioFull || bVideoFull))
1632 CLog::Log(LOGDEBUG, "set caching from pvr to done. audio (%d) = %d. video (%d) = %d",
1633 bGotAudio, m_omxPlayerAudio.GetLevel(),
1634 bGotVideo, m_omxPlayerVideo.GetLevel());
1636 CFileItem currentItem(g_application.CurrentFileItem());
1637 if (currentItem.HasPVRChannelInfoTag())
1638 g_PVRManager.LoadCurrentChannelSettings();
1640 caching = CACHESTATE_DONE;
1644 /* ensure that automatically started players are stopped while caching */
1645 if (m_CurrentAudio.started)
1646 m_omxPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE);
1647 if (m_CurrentVideo.started)
1648 m_omxPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE);
1652 if(caching == CACHESTATE_PLAY)
1654 // if all enabled streams have started playing we are done
1655 if((m_CurrentVideo.id < 0 || !m_omxPlayerVideo.IsStalled())
1656 && (m_CurrentAudio.id < 0 || !m_omxPlayerAudio.IsStalled()))
1657 caching = CACHESTATE_DONE;
1660 if(m_caching != caching)
1661 SetCaching(caching);
1664 if(GetPlaySpeed() != DVD_PLAYSPEED_NORMAL && GetPlaySpeed() != DVD_PLAYSPEED_PAUSE)
1668 // this can't be done in menu
1669 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
1672 else if (m_CurrentVideo.id >= 0
1673 && m_CurrentVideo.inited == true
1674 && m_SpeedState.lastpts != m_omxPlayerVideo.GetCurrentPts()
1675 && m_SpeedState.lasttime != GetTime())
1677 m_SpeedState.lastpts = m_omxPlayerVideo.GetCurrentPts();
1678 m_SpeedState.lasttime = GetTime();
1679 // check how much off clock video is when ff/rw:ing
1680 // a problem here is that seeking isn't very accurate
1681 // and since the clock will be resynced after seek
1682 // we might actually not really be playing at the wanted
1683 // speed. we'd need to have some way to not resync the clock
1684 // after a seek to remember timing. still need to handle
1685 // discontinuities somehow
1687 // when seeking, give the player a headstart to make sure
1688 // the time it takes to seek doesn't make a difference.
1690 error = m_clock.GetClock() - m_SpeedState.lastpts;
1691 error *= m_playSpeed / abs(m_playSpeed);
1693 if(error > DVD_MSEC_TO_TIME(1000))
1695 CLog::Log(LOGDEBUG, "COMXPlayer::Process - Seeking to catch up");
1696 int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL);
1697 m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true));
1703 bool COMXPlayer::CheckStartCaching(COMXCurrentStream& current)
1705 if(m_caching != CACHESTATE_DONE
1706 || m_playSpeed != DVD_PLAYSPEED_NORMAL)
1712 if((current.type == STREAM_AUDIO && m_omxPlayerAudio.IsStalled())
1713 || (current.type == STREAM_VIDEO && m_omxPlayerVideo.IsStalled()))
1715 if (CachePVRStream())
1717 if ((current.type == STREAM_AUDIO && current.started && m_omxPlayerAudio.GetLevel() == 0) ||
1718 (current.type == STREAM_VIDEO && current.started && m_omxPlayerVideo.GetLevel() == 0))
1720 CLog::Log(LOGDEBUG, "%s stream stalled. start buffering", current.type == STREAM_AUDIO ? "audio" : "video");
1721 SetCaching(CACHESTATE_PVR);
1726 // don't start caching if it's only a single stream that has run dry
1727 if(m_omxPlayerAudio.GetLevel() > 50
1728 || m_omxPlayerVideo.GetLevel() > 50)
1732 SetCaching(CACHESTATE_FULL);
1734 SetCaching(CACHESTATE_INIT);
1740 bool COMXPlayer::CheckPlayerInit(COMXCurrentStream& current, unsigned int source)
1745 if(current.startpts != DVD_NOPTS_VALUE)
1747 if(current.dts == DVD_NOPTS_VALUE)
1749 CLog::Log(LOGDEBUG, "%s - dropping packet type:%d dts:%f to get to start point at %f", __FUNCTION__, source, current.dts, current.startpts);
1753 if((current.startpts - current.dts) > DVD_SEC_TO_TIME(20))
1755 CLog::Log(LOGDEBUG, "%s - too far to decode before finishing seek", __FUNCTION__);
1756 if(m_CurrentAudio.startpts != DVD_NOPTS_VALUE)
1757 m_CurrentAudio.startpts = current.dts;
1758 if(m_CurrentVideo.startpts != DVD_NOPTS_VALUE)
1759 m_CurrentVideo.startpts = current.dts;
1760 if(m_CurrentSubtitle.startpts != DVD_NOPTS_VALUE)
1761 m_CurrentSubtitle.startpts = current.dts;
1762 if(m_CurrentTeletext.startpts != DVD_NOPTS_VALUE)
1763 m_CurrentTeletext.startpts = current.dts;
1766 if(current.dts < current.startpts)
1768 CLog::Log(LOGDEBUG, "%s - dropping packet type:%d dts:%f to get to start point at %f", __FUNCTION__, source, current.dts, current.startpts);
1773 //If this is the first packet after a discontinuity, send it as a resync
1774 if (current.dts != DVD_NOPTS_VALUE)
1776 current.inited = true;
1777 current.startpts = current.dts;
1779 bool setclock = false;
1780 if(m_playSpeed == DVD_PLAYSPEED_NORMAL)
1782 if( source == DVDPLAYER_AUDIO)
1783 setclock = !m_CurrentVideo.inited;
1784 else if(source == DVDPLAYER_VIDEO)
1785 setclock = !m_CurrentAudio.inited;
1789 if(source == DVDPLAYER_VIDEO)
1793 double starttime = current.startpts;
1794 if(m_CurrentAudio.inited
1795 && m_CurrentAudio.startpts != DVD_NOPTS_VALUE
1796 && m_CurrentAudio.startpts < starttime)
1797 starttime = m_CurrentAudio.startpts;
1798 if(m_CurrentVideo.inited
1799 && m_CurrentVideo.startpts != DVD_NOPTS_VALUE
1800 && m_CurrentVideo.startpts < starttime)
1801 starttime = m_CurrentVideo.startpts;
1803 starttime = current.startpts - starttime;
1804 if(starttime > 0 && setclock)
1806 if(starttime > DVD_SEC_TO_TIME(2))
1807 CLog::Log(LOGWARNING, "COMXPlayer::CheckPlayerInit(%d) - Ignoring too large delay of %f", source, starttime);
1809 SendPlayerMessage(new CDVDMsgDouble(CDVDMsg::GENERAL_DELAY, starttime), source);
1812 SendPlayerMessage(new CDVDMsgGeneralResync(current.dts, setclock), source);
1817 void COMXPlayer::UpdateCorrection(DemuxPacket* pkt, double correction)
1819 //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);
1820 if(pkt->dts != DVD_NOPTS_VALUE) pkt->dts -= correction;
1821 if(pkt->pts != DVD_NOPTS_VALUE) pkt->pts -= correction;
1824 void COMXPlayer::UpdateTimestamps(COMXCurrentStream& current, DemuxPacket* pPacket)
1826 double dts = current.dts;
1827 /* update stored values */
1828 if(pPacket->dts != DVD_NOPTS_VALUE)
1830 else if(pPacket->pts != DVD_NOPTS_VALUE)
1833 /* calculate some average duration */
1834 if(pPacket->duration != DVD_NOPTS_VALUE)
1835 current.dur = pPacket->duration;
1836 else if(dts != DVD_NOPTS_VALUE && current.dts != DVD_NOPTS_VALUE)
1837 current.dur = 0.1 * (current.dur * 9 + (dts - current.dts));
1841 /* send a playback state structure periodically */
1842 if(current.dts_state == DVD_NOPTS_VALUE
1843 || abs(current.dts - current.dts_state) > DVD_MSEC_TO_TIME(200))
1845 current.dts_state = current.dts;
1848 // make sure we send no outdated state to a/v players
1850 SendPlayerMessage(new CDVDMsgType<SPlayerState>(CDVDMsg::PLAYER_DISPLAYTIME, m_StateInput), current.player);
1854 CSingleLock lock(m_StateSection);
1855 m_State = m_StateInput;
1860 static void UpdateLimits(double& minimum, double& maximum, double dts)
1862 if(dts == DVD_NOPTS_VALUE)
1864 if(minimum == DVD_NOPTS_VALUE || minimum > dts) minimum = dts;
1865 if(maximum == DVD_NOPTS_VALUE || maximum < dts) maximum = dts;
1868 void COMXPlayer::CheckContinuity(COMXCurrentStream& current, DemuxPacket* pPacket)
1870 if (m_playSpeed < DVD_PLAYSPEED_PAUSE)
1873 if( pPacket->dts == DVD_NOPTS_VALUE || current.dts == DVD_NOPTS_VALUE)
1876 double mindts = DVD_NOPTS_VALUE, maxdts = DVD_NOPTS_VALUE;
1877 UpdateLimits(mindts, maxdts, m_CurrentAudio.dts);
1878 UpdateLimits(mindts, maxdts, m_CurrentVideo.dts);
1879 UpdateLimits(mindts, maxdts, m_CurrentAudio.dts_end());
1880 UpdateLimits(mindts, maxdts, m_CurrentVideo.dts_end());
1882 /* if we don't have max and min, we can't do anything more */
1883 if( mindts == DVD_NOPTS_VALUE || maxdts == DVD_NOPTS_VALUE )
1886 double correction = 0.0;
1887 if( pPacket->dts > maxdts + DVD_MSEC_TO_TIME(1000))
1889 CLog::Log(LOGDEBUG, "COMXPlayer::CheckContinuity - resync forward :%d, prev:%f, curr:%f, diff:%f"
1890 , current.type, current.dts, pPacket->dts, pPacket->dts - maxdts);
1891 correction = pPacket->dts - maxdts;
1894 /* if it's large scale jump, correct for it */
1895 if(pPacket->dts + DVD_MSEC_TO_TIME(100) < current.dts_end())
1897 CLog::Log(LOGDEBUG, "COMXPlayer::CheckContinuity - resync backward :%d, prev:%f, curr:%f, diff:%f"
1898 , current.type, current.dts, pPacket->dts, pPacket->dts - current.dts);
1899 correction = pPacket->dts - current.dts_end();
1901 else if(pPacket->dts < current.dts)
1903 CLog::Log(LOGDEBUG, "COMXPlayer::CheckContinuity - wrapback :%d, prev:%f, curr:%f, diff:%f"
1904 , current.type, current.dts, pPacket->dts, pPacket->dts - current.dts);
1907 if(correction != 0.0)
1909 /* disable detection on next packet on other stream to avoid ping pong-ing */
1910 if(m_CurrentAudio.player != current.player) m_CurrentAudio.dts = DVD_NOPTS_VALUE;
1911 if(m_CurrentVideo.player != current.player) m_CurrentVideo.dts = DVD_NOPTS_VALUE;
1913 m_offset_pts += correction;
1914 UpdateCorrection(pPacket, correction);
1918 bool COMXPlayer::CheckSceneSkip(COMXCurrentStream& current)
1923 if(current.dts == DVD_NOPTS_VALUE)
1926 if(current.inited == false)
1930 return m_Edl.InCut(DVD_TIME_TO_MSEC(current.dts + m_offset_pts), &cut) && cut.action == CEdl::CUT;
1933 void COMXPlayer::CheckAutoSceneSkip()
1939 * Check that there is an audio and video stream.
1941 if(m_CurrentAudio.id < 0
1942 || m_CurrentVideo.id < 0)
1946 * If there is a startpts defined for either the audio or video stream then dvdplayer is still
1947 * still decoding frames to get to the previously requested seek point.
1949 if(m_CurrentAudio.inited == false
1950 || m_CurrentVideo.inited == false)
1953 if(m_CurrentAudio.dts == DVD_NOPTS_VALUE
1954 || m_CurrentVideo.dts == DVD_NOPTS_VALUE)
1957 const int64_t clock = DVD_TIME_TO_MSEC(min(m_CurrentAudio.dts, m_CurrentVideo.dts) + m_offset_pts);
1960 if(!m_Edl.InCut(clock, &cut))
1963 if(cut.action == CEdl::CUT
1964 && !(cut.end == m_EdlAutoSkipMarkers.cut || cut.start == m_EdlAutoSkipMarkers.cut)) // To prevent looping if same cut again
1966 CLog::Log(LOGDEBUG, "%s - Clock in EDL cut [%s - %s]: %s. Automatically skipping over.",
1967 __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(),
1968 CEdl::MillisecondsToTimeString(cut.end).c_str(), CEdl::MillisecondsToTimeString(clock).c_str());
1970 * Seeking either goes to the start or the end of the cut depending on the play direction.
1972 int64_t seek = GetPlaySpeed() >= 0 ? cut.end : cut.start;
1974 * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
1976 m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, false, true, false, true));
1978 * Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping
1979 * if there was an error with seeking and it landed somewhere unexpected, perhaps back in the
1980 * cut. The cut automatic skip marker is reset every 500ms allowing another attempt at the seek.
1982 m_EdlAutoSkipMarkers.cut = GetPlaySpeed() >= 0 ? cut.end : cut.start;
1984 else if(cut.action == CEdl::COMM_BREAK
1985 && GetPlaySpeed() >= 0
1986 && cut.start > m_EdlAutoSkipMarkers.commbreak_end)
1988 CLog::Log(LOGDEBUG, "%s - Clock in commercial break [%s - %s]: %s. Automatically skipping to end of commercial break (only done once per break)",
1989 __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), CEdl::MillisecondsToTimeString(cut.end).c_str(),
1990 CEdl::MillisecondsToTimeString(clock).c_str());
1992 * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
1994 m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true));
1996 * Each commercial break is only skipped once so poorly detected commercial breaks can be
1997 * manually re-entered. Start and end are recorded to prevent looping and to allow seeking back
1998 * to the start of the commercial break if incorrectly flagged.
2000 m_EdlAutoSkipMarkers.commbreak_start = cut.start;
2001 m_EdlAutoSkipMarkers.commbreak_end = cut.end;
2002 m_EdlAutoSkipMarkers.seek_to_start = true; // Allow backwards Seek() to go directly to the start
2006 void COMXPlayer::SynchronizeDemuxer(unsigned int timeout)
2008 if(IsCurrentThread())
2010 if(!m_messenger.IsInited())
2013 CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, 0);
2014 m_messenger.Put(message->Acquire());
2015 message->Wait(&m_bStop, 0);
2019 void COMXPlayer::SynchronizePlayers(unsigned int sources)
2021 /* we need a big timeout as audio queue is about 8seconds for 2ch ac3 */
2022 const int timeout = 10*1000; // in milliseconds
2024 CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, sources);
2025 if (m_CurrentAudio.id >= 0)
2026 m_omxPlayerAudio.SendMessage(message->Acquire());
2028 if (m_CurrentVideo.id >= 0)
2029 m_omxPlayerVideo.SendMessage(message->Acquire());
2030 /* TODO - we have to rewrite the sync class, to not require
2031 all other players waiting for subtitle, should only
2033 if (m_CurrentSubtitle.id >= 0)
2034 m_dvdPlayerSubtitle.SendMessage(message->Acquire());
2039 void COMXPlayer::SendPlayerMessage(CDVDMsg* pMsg, unsigned int target)
2041 if(target == DVDPLAYER_AUDIO)
2042 m_omxPlayerAudio.SendMessage(pMsg);
2043 if(target == DVDPLAYER_VIDEO)
2044 m_omxPlayerVideo.SendMessage(pMsg);
2045 if(target == DVDPLAYER_SUBTITLE)
2046 m_dvdPlayerSubtitle.SendMessage(pMsg);
2047 if(target == DVDPLAYER_TELETEXT)
2048 m_dvdPlayerTeletext.SendMessage(pMsg);
2051 void COMXPlayer::OnExit()
2055 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit()");
2057 m_av_clock.OMXStop();
2058 m_av_clock.OMXStateIdle();
2060 // set event to inform openfile something went wrong in case openfile is still waiting for this event
2061 SetCaching(CACHESTATE_DONE);
2063 // close each stream
2064 if (!m_bAbortRequest) CLog::Log(LOGNOTICE, "OMXPlayer: eof, waiting for queues to empty");
2065 if (m_CurrentAudio.id >= 0)
2067 CLog::Log(LOGNOTICE, "OMXPlayer: closing audio stream");
2068 CloseAudioStream(!m_bAbortRequest);
2070 if (m_CurrentVideo.id >= 0)
2072 CLog::Log(LOGNOTICE, "OMXPlayer: closing video stream");
2073 CloseVideoStream(!m_bAbortRequest);
2075 if (m_CurrentSubtitle.id >= 0)
2077 CLog::Log(LOGNOTICE, "OMXPlayer: closing subtitle stream");
2078 CloseSubtitleStream(!m_bAbortRequest);
2080 if (m_CurrentTeletext.id >= 0)
2082 CLog::Log(LOGNOTICE, "OMXPlayer: closing teletext stream");
2083 CloseTeletextStream(!m_bAbortRequest);
2085 // destroy the demuxer
2088 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit() deleting demuxer");
2093 if (m_pSubtitleDemuxer)
2095 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit() deleting subtitle demuxer");
2096 delete m_pSubtitleDemuxer;
2098 m_pSubtitleDemuxer = NULL;
2100 // destroy the inputstream
2103 CLog::Log(LOGNOTICE, "COMXPlayer::OnExit() deleting input stream");
2104 delete m_pInputStream;
2106 m_pInputStream = NULL;
2108 // clean up all selection streams
2109 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NONE);
2113 m_av_clock.OMXDeinitialize();
2118 CLog::Log(LOGERROR, "%s - Exception thrown when trying to close down player, memory leak will follow", __FUNCTION__);
2119 m_pInputStream = NULL;
2124 // if we didn't stop playing, advance to the next item in xbmc's playlist
2125 if(m_PlayerOptions.identify == false)
2127 if (m_bAbortRequest)
2128 m_callback.OnPlayBackStopped();
2130 m_callback.OnPlayBackEnded();
2133 // set event to inform openfile something went wrong in case openfile is still waiting for this event
2137 void COMXPlayer::HandleMessages()
2140 OMXStreamLock lock(this);
2142 while (m_messenger.Get(&pMsg, 0) == MSGQ_OK)
2147 if (pMsg->IsType(CDVDMsg::PLAYER_SEEK) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK) == 0
2148 && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK_CHAPTER) == 0)
2150 CDVDMsgPlayerSeek &msg(*((CDVDMsgPlayerSeek*)pMsg));
2152 if (!m_State.canseek)
2158 if(!msg.GetTrickPlay())
2160 g_infoManager.SetDisplayAfterSeek(100000);
2162 SetCaching(CACHESTATE_FLUSH);
2165 double start = DVD_NOPTS_VALUE;
2167 int time = msg.GetRestore() ? (int)m_Edl.RestoreCutTime(msg.GetTime()) : msg.GetTime();
2169 // if input streams doesn't support seektime we must convert back to clock
2170 if(dynamic_cast<CDVDInputStream::ISeekTime*>(m_pInputStream) == NULL)
2171 time -= DVD_TIME_TO_MSEC(m_State.time_offset - m_offset_pts);
2173 CLog::Log(LOGDEBUG, "demuxer seek to: %d", time);
2174 if (m_pDemuxer && m_pDemuxer->SeekTime(time, msg.GetBackward(), &start))
2176 CLog::Log(LOGDEBUG, "demuxer seek to: %.0f, success", start);
2177 if(m_pSubtitleDemuxer)
2179 if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward()))
2180 CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time);
2182 // dts after successful seek
2183 if (m_StateInput.time_src == ETIMESOURCE_CLOCK && start == DVD_NOPTS_VALUE)
2184 m_StateInput.dts = DVD_MSEC_TO_TIME(time);
2186 m_StateInput.dts = start;
2188 FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate());
2189 // let clock know the new time so progress bar updates immediately
2190 if(m_StateInput.dts != DVD_NOPTS_VALUE)
2191 m_av_clock.OMXMediaTime(m_StateInput.dts);
2194 CLog::Log(LOGWARNING, "error while seeking");
2196 // set flag to indicate we have finished a seeking request
2197 if(!msg.GetTrickPlay())
2198 g_infoManager.SetDisplayAfterSeek();
2200 // dvd's will issue a HOP_CHANNEL that we need to skip
2201 if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2202 m_dvd.state = DVDSTATE_SEEK;
2204 else if (pMsg->IsType(CDVDMsg::PLAYER_SEEK_CHAPTER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK) == 0
2205 && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK_CHAPTER) == 0)
2207 g_infoManager.SetDisplayAfterSeek(100000);
2208 SetCaching(CACHESTATE_FLUSH);
2210 CDVDMsgPlayerSeekChapter &msg(*((CDVDMsgPlayerSeekChapter*)pMsg));
2211 double start = DVD_NOPTS_VALUE;
2213 // This should always be the case.
2214 if(m_pDemuxer && m_pDemuxer->SeekChapter(msg.GetChapter(), &start))
2216 FlushBuffers(false, start, true);
2217 // let clock know the new time so progress bar updates immediately
2218 if(start != DVD_NOPTS_VALUE)
2219 m_av_clock.OMXMediaTime(start);
2221 m_callback.OnPlayBackSeekChapter(msg.GetChapter());
2224 g_infoManager.SetDisplayAfterSeek();
2226 else if (pMsg->IsType(CDVDMsg::DEMUXER_RESET))
2228 m_CurrentAudio.stream = NULL;
2229 m_CurrentVideo.stream = NULL;
2230 m_CurrentSubtitle.stream = NULL;
2232 // we need to reset the demuxer, probably because the streams have changed
2234 m_pDemuxer->Reset();
2235 if(m_pSubtitleDemuxer)
2236 m_pSubtitleDemuxer->Reset();
2238 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_AUDIOSTREAM))
2240 CDVDMsgPlayerSetAudioStream* pMsg2 = (CDVDMsgPlayerSetAudioStream*)pMsg;
2242 OMXSelectionStream& st = m_SelectionStreams.Get(STREAM_AUDIO, pMsg2->GetStreamId());
2243 if(st.source != STREAM_SOURCE_NONE)
2245 if(st.source == STREAM_SOURCE_NAV && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2247 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
2248 if(pStream->SetActiveAudioStream(st.id))
2250 m_dvd.iSelectedAudioStream = -1;
2251 CloseAudioStream(false);
2252 m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true));
2257 CloseAudioStream(false);
2258 OpenAudioStream(st.id, st.source);
2259 m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true));
2263 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_SUBTITLESTREAM))
2265 CDVDMsgPlayerSetSubtitleStream* pMsg2 = (CDVDMsgPlayerSetSubtitleStream*)pMsg;
2267 OMXSelectionStream& st = m_SelectionStreams.Get(STREAM_SUBTITLE, pMsg2->GetStreamId());
2268 if(st.source != STREAM_SOURCE_NONE)
2270 if(st.source == STREAM_SOURCE_NAV && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2272 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
2273 if(pStream->SetActiveSubtitleStream(st.id))
2275 m_dvd.iSelectedSPUStream = -1;
2276 CloseSubtitleStream(false);
2281 CloseSubtitleStream(false);
2282 OpenSubtitleStream(st.id, st.source);
2286 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_SUBTITLESTREAM_VISIBLE))
2288 CDVDMsgBool* pValue = (CDVDMsgBool*)pMsg;
2290 m_omxPlayerVideo.EnableSubtitle(pValue->m_value);
2292 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2293 static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->EnableSubtitleStream(pValue->m_value);
2295 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_STATE))
2297 g_infoManager.SetDisplayAfterSeek(100000);
2298 SetCaching(CACHESTATE_FLUSH);
2300 CDVDMsgPlayerSetState* pMsgPlayerSetState = (CDVDMsgPlayerSetState*)pMsg;
2302 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
2304 if(ptr->SetState(pMsgPlayerSetState->GetState()))
2306 m_dvd.state = DVDSTATE_NORMAL;
2307 m_dvd.iDVDStillStartTime = 0;
2308 m_dvd.iDVDStillTime = 0;
2312 g_infoManager.SetDisplayAfterSeek();
2314 else if (pMsg->IsType(CDVDMsg::PLAYER_SET_RECORD))
2316 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2318 input->Record(*(CDVDMsgBool*)pMsg);
2320 else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
2322 FlushBuffers(false);
2324 else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
2326 int speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
2328 // correct our current clock, as it would start going wrong otherwise
2329 if(m_State.timestamp > 0)
2332 offset = m_clock.GetAbsoluteClock() - m_State.timestamp;
2333 offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
2334 if(offset > 1000) offset = 1000;
2335 if(offset < -1000) offset = -1000;
2336 m_State.time += DVD_TIME_TO_MSEC(offset);
2337 m_State.timestamp = m_clock.GetAbsoluteClock();
2340 if (speed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_PAUSE && speed != m_playSpeed)
2341 m_callback.OnPlayBackSpeedChanged(speed / DVD_PLAYSPEED_NORMAL);
2343 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && speed != m_playSpeed)
2345 CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream);
2346 pvrinputstream->Pause( speed == 0 );
2349 // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
2350 // audioplayer, stops outputing audio to audiorender, but still tries to
2351 // sleep an correct amount for each packet
2352 // videoplayer just plays faster after the clock speed has been increased
2354 // 2. skip frames and adjust their pts or the clock
2355 m_playSpeed = speed;
2356 m_caching = CACHESTATE_DONE;
2357 m_clock.SetSpeed(speed);
2358 m_av_clock.OMXSetSpeed(speed);
2359 m_omxPlayerAudio.SetSpeed(speed);
2360 m_omxPlayerVideo.SetSpeed(speed);
2362 // TODO - we really shouldn't pause demuxer
2363 // until our buffers are somewhat filled
2365 m_pDemuxer->SetSpeed(speed);
2367 CLog::Log(LOGDEBUG, "COMXPlayer - CDVDMsg::PLAYER_SETSPEED speed : %d", speed);
2369 else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) == 0)
2371 FlushBuffers(false);
2372 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2373 if(input && input->SelectChannelByNumber(static_cast<CDVDMsgInt*>(pMsg)->m_value))
2375 SAFE_DELETE(m_pDemuxer);
2378 CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__);
2379 CApplicationMessenger::Get().MediaStop(false);
2382 else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT) == 0)
2384 FlushBuffers(false);
2385 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2386 if(input && input->SelectChannel(static_cast<CDVDMsgType <CPVRChannel> *>(pMsg)->m_value))
2388 SAFE_DELETE(m_pDemuxer);
2391 CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__);
2392 CApplicationMessenger::Get().MediaStop(false);
2395 else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT) || pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_PREV))
2397 CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
2400 bool bSwitchSuccessful(false);
2401 bool bShowPreview(CSettings::Get().GetInt("pvrplayback.channelentrytimeout") > 0);
2405 g_infoManager.SetDisplayAfterSeek(100000);
2406 FlushBuffers(false);
2409 if(pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT))
2410 bSwitchSuccessful = input->NextChannel(bShowPreview);
2412 bSwitchSuccessful = input->PrevChannel(bShowPreview);
2414 if(bSwitchSuccessful)
2418 UpdateApplication(0);
2419 m_iChannelEntryTimeOut = XbmcThreads::SystemClockMillis() + CSettings::Get().GetInt("pvrplayback.channelentrytimeout");
2423 m_iChannelEntryTimeOut = 0;
2424 SAFE_DELETE(m_pDemuxer);
2426 g_infoManager.SetDisplayAfterSeek();
2431 CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__);
2432 CApplicationMessenger::Get().MediaStop(false);
2436 else if (pMsg->IsType(CDVDMsg::GENERAL_GUI_ACTION))
2437 OnAction(((CDVDMsgType<CAction>*)pMsg)->m_value);
2438 else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
2440 int player = ((CDVDMsgInt*)pMsg)->m_value;
2441 if(player == DVDPLAYER_AUDIO)
2442 m_CurrentAudio.started = true;
2443 if(player == DVDPLAYER_VIDEO)
2444 m_CurrentVideo.started = true;
2445 CLog::Log(LOGDEBUG, "COMXPlayer::HandleMessages - player started %d", player);
2447 else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME))
2449 COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value;
2451 CSingleLock lock(m_StateSection);
2452 /* prioritize data from video player, but only accept data *
2453 * after it has been started to avoid race conditions after seeks */
2454 if(m_CurrentVideo.started && !m_omxPlayerVideo.SubmittedEOS())
2456 if(state.player == DVDPLAYER_VIDEO)
2459 else if(m_CurrentAudio.started)
2461 if(state.player == DVDPLAYER_AUDIO)
2468 CLog::Log(LOGERROR, "%s - Exception thrown when handling message", __FUNCTION__);
2476 void COMXPlayer::SetCaching(ECacheState state)
2478 if(state == CACHESTATE_FLUSH)
2480 double level, delay, offset;
2481 if(GetCachingTimes(level, delay, offset))
2482 state = CACHESTATE_FULL;
2484 state = CACHESTATE_INIT;
2487 if(m_caching == state)
2490 CLog::Log(LOGDEBUG, "COMXPlayer::SetCaching - caching state %d", state);
2491 if(state == CACHESTATE_FULL
2492 || state == CACHESTATE_INIT
2493 || state == CACHESTATE_PVR)
2495 m_clock.SetSpeed(DVD_PLAYSPEED_PAUSE);
2496 m_av_clock.OMXSetSpeed(DVD_PLAYSPEED_PAUSE);
2497 m_omxPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE);
2498 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
2499 m_omxPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE);
2500 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
2502 if (state == CACHESTATE_PVR)
2503 m_pInputStream->ResetScanTimeout((unsigned int) CSettings::Get().GetInt("pvrplayback.scantime") * 1000);
2506 if(state == CACHESTATE_PLAY
2507 ||(state == CACHESTATE_DONE && m_caching != CACHESTATE_PLAY))
2509 m_clock.SetSpeed(m_playSpeed);
2510 m_av_clock.OMXSetSpeed(m_playSpeed);
2511 m_omxPlayerAudio.SetSpeed(m_playSpeed);
2512 m_omxPlayerVideo.SetSpeed(m_playSpeed);
2513 m_pInputStream->ResetScanTimeout(0);
2518 void COMXPlayer::SetPlaySpeed(int speed)
2520 /* only pause and normal playspeeds are allowed */
2521 if(speed < 0 || speed > DVD_PLAYSPEED_NORMAL)
2524 m_messenger.Put(new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed));
2525 m_omxPlayerAudio.SetSpeed(speed);
2526 m_omxPlayerVideo.SetSpeed(speed);
2527 SynchronizeDemuxer(100);
2530 bool COMXPlayer::CanPause()
2532 CSingleLock lock(m_StateSection);
2533 return m_State.canpause;
2536 void COMXPlayer::Pause()
2538 CSingleLock lock(m_StateSection);
2539 if (!m_State.canpause)
2543 if(m_playSpeed != DVD_PLAYSPEED_PAUSE && (m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR))
2545 SetCaching(CACHESTATE_DONE);
2549 // return to normal speed if it was paused before, pause otherwise
2550 if (m_playSpeed == DVD_PLAYSPEED_PAUSE)
2552 SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
2553 m_callback.OnPlayBackResumed();
2557 SetPlaySpeed(DVD_PLAYSPEED_PAUSE);
2558 m_callback.OnPlayBackPaused();
2562 bool COMXPlayer::IsPaused() const
2564 return m_playSpeed == DVD_PLAYSPEED_PAUSE || m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR;
2567 bool COMXPlayer::HasVideo() const
2572 bool COMXPlayer::HasAudio() const
2577 bool COMXPlayer::IsPassthrough() const
2579 return m_omxPlayerAudio.Passthrough();
2582 bool COMXPlayer::CanSeek()
2584 CSingleLock lock(m_StateSection);
2585 return m_State.canseek;
2588 void COMXPlayer::Seek(bool bPlus, bool bLargeStep)
2591 // sadly this doesn't work for now, audio player must
2592 // drop packets at the same rate as we play frames
2593 if( m_playSpeed == DVD_PLAYSPEED_PAUSE && bPlus && !bLargeStep)
2595 m_omxPlayerVideo.StepFrame();
2599 if (!m_State.canseek)
2602 if(((bPlus && GetChapter() < GetChapterCount())
2603 || (!bPlus && GetChapter() > 1)) && bLargeStep)
2606 SeekChapter(GetChapter() + 1);
2608 SeekChapter(GetChapter() - 1);
2613 if (g_advancedSettings.m_videoUseTimeSeeking && GetTotalTime() > 2000*g_advancedSettings.m_videoTimeSeekForwardBig)
2616 seek = bPlus ? g_advancedSettings.m_videoTimeSeekForwardBig : g_advancedSettings.m_videoTimeSeekBackwardBig;
2618 seek = bPlus ? g_advancedSettings.m_videoTimeSeekForward : g_advancedSettings.m_videoTimeSeekBackward;
2626 percent = bPlus ? g_advancedSettings.m_videoPercentSeekForwardBig : g_advancedSettings.m_videoPercentSeekBackwardBig;
2628 percent = bPlus ? g_advancedSettings.m_videoPercentSeekForward : g_advancedSettings.m_videoPercentSeekBackward;
2629 seek = (int64_t)(GetTotalTimeInMsec()*(GetPercentage()+percent)/100);
2632 bool restore = true;
2636 * Alter the standard seek position based on whether any commercial breaks have been
2637 * automatically skipped.
2639 const int clock = DVD_TIME_TO_MSEC(m_clock.GetClock());
2641 * If a large backwards seek occurs within 10 seconds of the end of the last automated
2642 * commercial skip, then seek back to the start of the commercial break under the assumption
2643 * it was flagged incorrectly. 10 seconds grace period is allowed in case the watcher has to
2644 * fumble around finding the remote. Only happens once per commercial break.
2646 * Small skip does not trigger this in case the start of the commercial break was in fact fine
2647 * but it skipped too far into the program. In that case small skip backwards behaves as normal.
2649 if (!bPlus && bLargeStep
2650 && m_EdlAutoSkipMarkers.seek_to_start
2651 && clock >= m_EdlAutoSkipMarkers.commbreak_end
2652 && clock <= m_EdlAutoSkipMarkers.commbreak_end + 10*1000) // Only if within 10 seconds of the end (in msec)
2654 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).",
2655 __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(),
2656 CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str());
2657 seek = m_EdlAutoSkipMarkers.commbreak_start;
2659 m_EdlAutoSkipMarkers.seek_to_start = false; // So this will only happen within the 10 second grace period once.
2662 * If big skip forward within the last "reverted" commercial break, seek to the end of the
2663 * commercial break under the assumption that the break was incorrectly flagged and playback has
2664 * now reached the actual start of the commercial break. Assume that the end is flagged more
2665 * correctly than the landing point for a standard big skip (ends seem to be flagged more
2666 * accurately than the start).
2668 else if (bPlus && bLargeStep
2669 && clock >= m_EdlAutoSkipMarkers.commbreak_start
2670 && clock <= m_EdlAutoSkipMarkers.commbreak_end)
2672 CLog::Log(LOGDEBUG, "%s - Seeking to end of previously skipped commercial break [%s - %s] as big forwards skip activated within the break.",
2673 __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(),
2674 CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str());
2675 seek = m_EdlAutoSkipMarkers.commbreak_end;
2680 int64_t time = GetTime();
2681 if(g_application.CurrentFileItem().IsStack()
2682 && (seek > GetTotalTimeInMsec() || seek < 0))
2684 g_application.SeekTime((seek - time) * 0.001 + g_application.GetTime());
2685 // warning, don't access any dvdplayer variables here as
2686 // the dvdplayer object may have been destroyed
2690 m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, !bPlus, true, false, restore));
2691 SynchronizeDemuxer(100);
2692 if (seek < 0) seek = 0;
2693 m_callback.OnPlayBackSeek((int)seek, (int)(seek - time));
2696 bool COMXPlayer::SeekScene(bool bPlus)
2698 if (!m_Edl.HasSceneMarker())
2702 * There is a 5 second grace period applied when seeking for scenes backwards. If there is no
2703 * grace period applied it is impossible to go backwards past a scene marker.
2705 int64_t clock = GetTime();
2706 if (!bPlus && clock > 5 * 1000) // 5 seconds
2709 int64_t iScenemarker;
2710 if (m_Edl.GetNextSceneMarker(bPlus, clock, &iScenemarker))
2713 * Seeking is flushed and inaccurate, just like Seek()
2715 m_messenger.Put(new CDVDMsgPlayerSeek((int)iScenemarker, !bPlus, true, false, false));
2716 SynchronizeDemuxer(100);
2722 void COMXPlayer::GetAudioInfo(CStdString &strAudioInfo)
2724 { CSingleLock lock(m_StateSection);
2725 strAudioInfo.Format("D(%s)", m_StateInput.demux_audio.c_str());
2727 strAudioInfo.AppendFormat("\nP(%s)", m_omxPlayerAudio.GetPlayerInfo().c_str());
2730 void COMXPlayer::GetVideoInfo(CStdString &strVideoInfo)
2732 { CSingleLock lock(m_StateSection);
2733 strVideoInfo.Format("D(%s)", m_StateInput.demux_video.c_str());
2735 strVideoInfo.AppendFormat("\nP(%s)", m_omxPlayerVideo.GetPlayerInfo().c_str());
2738 void COMXPlayer::GetGeneralInfo(CStdString& strGeneralInfo)
2742 double dDelay = m_omxPlayerVideo.GetDelay() / DVD_TIME_BASE - g_renderManager.GetDisplayLatency();
2744 double apts = m_omxPlayerAudio.GetCurrentPts();
2745 double vpts = m_omxPlayerVideo.GetCurrentPts();
2748 if( apts != DVD_NOPTS_VALUE && vpts != DVD_NOPTS_VALUE )
2749 dDiff = (apts - vpts) / DVD_TIME_BASE;
2752 strEDL.AppendFormat(", edl:%s", m_Edl.GetInfo().c_str());
2755 CSingleLock lock(m_StateSection);
2756 if(m_StateInput.cache_bytes >= 0)
2758 strBuf.AppendFormat(" cache:%s %2.0f%%"
2759 , StringUtils::SizeToString(m_State.cache_bytes).c_str()
2760 , m_State.cache_level * 100);
2761 if(m_playSpeed == 0 || m_caching == CACHESTATE_FULL)
2762 strBuf.AppendFormat(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay));
2765 strGeneralInfo.Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s, omx vb:%8d ad:% 6.3f )"
2769 , (int)(CThread::GetRelativeUsage()*100)
2770 , (int)(m_omxPlayerAudio.GetRelativeUsage()*100)
2771 , (int)(m_omxPlayerVideo.GetRelativeUsage()*100)
2773 , m_omxPlayerVideo.GetFreeSpace()
2774 , m_omxPlayerAudio.GetDelay());
2779 void COMXPlayer::SeekPercentage(float iPercent)
2781 int64_t iTotalTime = GetTotalTimeInMsec();
2786 SeekTime((int64_t)(iTotalTime * iPercent / 100));
2789 float COMXPlayer::GetPercentage()
2791 int64_t iTotalTime = GetTotalTimeInMsec();
2796 return GetTime() * 100 / (float)iTotalTime;
2799 float COMXPlayer::GetCachePercentage()
2801 CSingleLock lock(m_StateSection);
2802 return m_StateInput.cache_offset * 100; // NOTE: Percentage returned is relative
2805 void COMXPlayer::SetAVDelay(float fValue)
2807 m_omxPlayerVideo.SetDelay(fValue * DVD_TIME_BASE);
2810 float COMXPlayer::GetAVDelay()
2812 return m_omxPlayerVideo.GetDelay() / (float)DVD_TIME_BASE;
2815 void COMXPlayer::SetSubTitleDelay(float fValue)
2817 m_omxPlayerVideo.SetSubtitleDelay(-fValue * DVD_TIME_BASE);
2820 float COMXPlayer::GetSubTitleDelay()
2822 return -m_omxPlayerVideo.GetSubtitleDelay() / DVD_TIME_BASE;
2825 // priority: 1: libdvdnav, 2: external subtitles, 3: muxed subtitles
2826 int COMXPlayer::GetSubtitleCount()
2828 OMXStreamLock lock(this);
2829 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
2830 return m_SelectionStreams.Count(STREAM_SUBTITLE);
2833 int COMXPlayer::GetSubtitle()
2835 return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, *this);
2838 void COMXPlayer::GetSubtitleStreamInfo(int index, SPlayerSubtitleStreamInfo &info)
2840 if (index < 0 || index > (int) GetSubtitleCount() - 1)
2843 OMXSelectionStream& s = m_SelectionStreams.Get(STREAM_SUBTITLE, index);
2844 if(s.name.length() > 0)
2847 if(s.type == STREAM_NONE)
2848 info.name += "(Invalid)";
2850 info.language = s.language;
2853 void COMXPlayer::SetSubtitle(int iStream)
2855 m_messenger.Put(new CDVDMsgPlayerSetSubtitleStream(iStream));
2858 bool COMXPlayer::GetSubtitleVisible()
2860 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
2862 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
2863 if(pStream->IsInMenu())
2864 return CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn;
2866 return pStream->IsSubtitleStreamEnabled();
2869 return m_omxPlayerVideo.IsSubtitleEnabled();
2872 void COMXPlayer::SetSubtitleVisible(bool bVisible)
2874 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn = bVisible;
2875 m_messenger.Put(new CDVDMsgBool(CDVDMsg::PLAYER_SET_SUBTITLESTREAM_VISIBLE, bVisible));
2878 int COMXPlayer::GetAudioStreamCount()
2880 OMXStreamLock lock(this);
2881 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
2882 return m_SelectionStreams.Count(STREAM_AUDIO);
2885 int COMXPlayer::GetAudioStream()
2887 return m_SelectionStreams.IndexOf(STREAM_AUDIO, *this);
2890 void COMXPlayer::SetAudioStream(int iStream)
2892 m_messenger.Put(new CDVDMsgPlayerSetAudioStream(iStream));
2893 SynchronizeDemuxer(100);
2896 TextCacheStruct_t* COMXPlayer::GetTeletextCache()
2898 if (m_CurrentTeletext.id < 0)
2901 return m_dvdPlayerTeletext.GetTeletextCache();
2904 void COMXPlayer::LoadPage(int p, int sp, unsigned char* buffer)
2906 if (m_CurrentTeletext.id < 0)
2909 return m_dvdPlayerTeletext.LoadPage(p, sp, buffer);
2912 void COMXPlayer::SeekTime(int64_t iTime)
2914 int seekOffset = (int)(iTime - GetTime());
2915 m_messenger.Put(new CDVDMsgPlayerSeek((int)iTime, true, true, true));
2916 SynchronizeDemuxer(100);
2917 m_callback.OnPlayBackSeek((int)iTime, seekOffset);
2920 // return the time in milliseconds
2921 int64_t COMXPlayer::GetTime()
2923 CSingleLock lock(m_StateSection);
2925 const double limit = DVD_MSEC_TO_TIME(200);
2926 if(m_State.timestamp > 0)
2928 offset = m_clock.GetAbsoluteClock() - m_State.timestamp;
2929 offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL;
2930 if(offset > limit) offset = limit;
2931 if(offset < -limit) offset = -limit;
2933 //{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_av_clock.OMXMediaTime()), (int)m_playSpeed, (int)m_caching, llrint(m_State.time + DVD_TIME_TO_MSEC(offset)));}
2934 return llrint(m_State.time + DVD_TIME_TO_MSEC(offset));
2937 // return length in msec
2938 int64_t COMXPlayer::GetTotalTimeInMsec()
2940 CSingleLock lock(m_StateSection);
2941 return llrint(m_State.time_total);
2944 // return length in seconds.. this should be changed to return in milleseconds throughout xbmc
2945 int64_t COMXPlayer::GetTotalTime()
2947 return GetTotalTimeInMsec();
2950 void COMXPlayer::ToFFRW(int iSpeed)
2952 // can't rewind in menu as seeking isn't possible
2954 if (iSpeed < 0 && IsInMenu()) return;
2956 /* only pause and normal playspeeds are allowed */
2957 if(iSpeed > 1 || iSpeed < 0)
2960 SetPlaySpeed(iSpeed * DVD_PLAYSPEED_NORMAL);
2963 bool COMXPlayer::OpenAudioStream(int iStream, int source, bool reset)
2965 CLog::Log(LOGNOTICE, "Opening audio stream: %i source: %i", iStream, source);
2969 CLog::Log(LOGWARNING, "Opening audio stream: no demuxer");
2973 CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
2974 if (!pStream || pStream->disabled)
2976 CLog::Log(LOGWARNING, "Opening audio stream: pStream=%p disabled=%d", pStream, pStream ? pStream->disabled:0);
2980 if( m_CurrentAudio.id < 0 && m_CurrentVideo.id >= 0 )
2982 // up until now we wheren't playing audio, but we did play video
2983 // this will change what is used to sync the dvdclock.
2984 // since the new audio data doesn't have to have any relation
2985 // to the current video data in the packet que, we have to
2986 // wait for it to empty
2988 // this happens if a new cell has audio data, but previous didn't
2989 // and both have video data
2991 SynchronizePlayers(SYNCSOURCE_AUDIO);
2994 CDVDStreamInfo hint(*pStream, true);
2996 if(m_CurrentAudio.id < 0
2997 || m_CurrentAudio.hint != hint)
2999 if(!m_omxPlayerAudio.OpenStream(hint))
3001 /* mark stream as disabled, to disallaw further attempts*/
3002 CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
3003 pStream->disabled = true;
3004 pStream->SetDiscard(AVDISCARD_ALL);
3009 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3011 /* store information about stream */
3012 m_CurrentAudio.id = iStream;
3013 m_CurrentAudio.source = source;
3014 m_CurrentAudio.hint = hint;
3015 m_CurrentAudio.stream = (void*)pStream;
3016 m_CurrentAudio.started = false;
3017 m_clock.SetMasterClock(false);
3020 /* we are potentially going to be waiting on this */
3021 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
3023 /* software decoding normaly consumes full cpu time so prio it */
3024 m_omxPlayerAudio.SetPriority(GetPriority()+1);
3029 bool COMXPlayer::OpenVideoStream(int iStream, int source, bool reset)
3031 CLog::Log(LOGNOTICE, "Opening video stream: %i source: %i", iStream, source);
3035 CLog::Log(LOGWARNING, "Opening video stream: no demuxer");
3039 CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
3040 if(!pStream || pStream->disabled)
3042 CLog::Log(LOGWARNING, "Opening video stream: pStream=%p disabled=%d", pStream, pStream ? pStream->disabled:0);
3045 pStream->SetDiscard(AVDISCARD_NONE);
3047 CDVDStreamInfo hint(*pStream, true);
3049 if( m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) )
3051 /* set aspect ratio as requested by navigator for dvd's */
3052 float aspect = static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->GetVideoAspectRatio();
3055 hint.aspect = aspect;
3056 hint.forced_aspect = true;
3058 hint.software = true;
3061 boost::shared_ptr<CPVRClient> client;
3062 if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) &&
3063 pStream->type == STREAM_VIDEO &&
3064 g_PVRClients->GetPlayingClient(client) && client->HandlesDemuxing())
3066 // set the fps in hints
3067 const CDemuxStreamVideo *stream = static_cast<const CDemuxStreamVideo*>(pStream);
3068 hint.fpsrate = stream->iFpsRate;
3069 hint.fpsscale = stream->iFpsScale;
3072 CDVDInputStream::IMenus* pMenus = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
3073 if(pMenus && pMenus->IsInMenu())
3076 if(m_CurrentVideo.id < 0
3077 || m_CurrentVideo.hint != hint)
3079 // for music file, don't open artwork as video
3080 bool disabled = false;
3081 CStdString extension = URIUtils::GetExtension(m_filename);
3082 if (!extension.IsEmpty() && g_advancedSettings.m_musicExtensions.Find(extension.ToLower()) != -1)
3084 CLog::Log(LOGWARNING, "%s - Ignoring video in audio filetype:%s", __FUNCTION__, m_filename.c_str());
3088 if (disabled || !m_omxPlayerVideo.OpenStream(hint))
3090 /* mark stream as disabled, to disallaw further attempts */
3091 CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
3092 pStream->disabled = true;
3093 pStream->SetDiscard(AVDISCARD_ALL);
3098 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3101 if(m_filename.find("3DSBS") != string::npos || m_filename.find("HSBS") != string::npos)
3102 flags = CONF_FLAGS_FORMAT_SBS;
3103 else if(m_filename.find("3DTAB") != string::npos || m_filename.find("HTAB") != string::npos)
3104 flags = CONF_FLAGS_FORMAT_TB;
3105 m_omxPlayerVideo.SetFlags(flags);
3107 /* store information about stream */
3108 m_CurrentVideo.id = iStream;
3109 m_CurrentVideo.source = source;
3110 m_CurrentVideo.hint = hint;
3111 m_CurrentVideo.stream = (void*)pStream;
3112 m_CurrentVideo.started = false;
3115 /* we are potentially going to be waiting on this */
3116 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
3118 /* use same priority for video thread as demuxing thread, as */
3119 /* otherwise demuxer will starve if video consumes the full cpu */
3120 m_omxPlayerVideo.SetPriority(GetPriority());
3125 bool COMXPlayer::OpenSubtitleStream(int iStream, int source)
3127 CLog::Log(LOGNOTICE, "Opening Subtitle stream: %i source: %i", iStream, source);
3129 CDemuxStream* pStream = NULL;
3130 std::string filename;
3131 CDVDStreamInfo hint;
3133 if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_DEMUX_SUB)
3135 int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, source, iStream);
3138 OMXSelectionStream st = m_SelectionStreams.Get(STREAM_SUBTITLE, index);
3140 if(!m_pSubtitleDemuxer || m_pSubtitleDemuxer->GetFileName() != st.filename)
3142 CLog::Log(LOGNOTICE, "Opening Subtitle file: %s", st.filename.c_str());
3143 auto_ptr<CDVDDemuxVobsub> demux(new CDVDDemuxVobsub());
3144 if(!demux->Open(st.filename, st.filename2))
3146 m_pSubtitleDemuxer = demux.release();
3149 pStream = m_pSubtitleDemuxer->GetStream(iStream);
3150 if(!pStream || pStream->disabled)
3152 pStream->SetDiscard(AVDISCARD_NONE);
3153 double pts = m_omxPlayerVideo.GetCurrentPts();
3154 if(pts == DVD_NOPTS_VALUE)
3155 pts = m_CurrentVideo.dts;
3156 if(pts == DVD_NOPTS_VALUE)
3158 pts += m_offset_pts;
3159 m_pSubtitleDemuxer->SeekTime((int)(1000.0 * pts / (double)DVD_TIME_BASE));
3161 hint.Assign(*pStream, true);
3163 else if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_TEXT)
3165 int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, source, iStream);
3168 filename = m_SelectionStreams.Get(STREAM_SUBTITLE, index).filename;
3171 hint.fpsscale = m_CurrentVideo.hint.fpsscale;
3172 hint.fpsrate = m_CurrentVideo.hint.fpsrate;
3178 pStream = m_pDemuxer->GetStream(iStream);
3179 if(!pStream || pStream->disabled)
3181 pStream->SetDiscard(AVDISCARD_NONE);
3183 hint.Assign(*pStream, true);
3185 if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3189 if(m_CurrentSubtitle.id < 0
3190 || m_CurrentSubtitle.hint != hint)
3192 if(m_CurrentSubtitle.id >= 0)
3194 CLog::Log(LOGDEBUG, " - codecs hints have changed, must close previous stream");
3195 CloseSubtitleStream(false);
3198 if(!m_dvdPlayerSubtitle.OpenStream(hint, filename))
3200 CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
3203 pStream->disabled = true;
3204 pStream->SetDiscard(AVDISCARD_ALL);
3210 m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3212 m_CurrentSubtitle.id = iStream;
3213 m_CurrentSubtitle.source = source;
3214 m_CurrentSubtitle.hint = hint;
3215 m_CurrentSubtitle.stream = (void*)pStream;
3216 m_CurrentSubtitle.started = false;
3221 bool COMXPlayer::OpenTeletextStream(int iStream, int source)
3226 CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
3227 if(!pStream || pStream->disabled)
3230 CDVDStreamInfo hint(*pStream, true);
3232 if (!m_dvdPlayerTeletext.CheckStream(hint))
3235 CLog::Log(LOGNOTICE, "Opening teletext stream: %i source: %i", iStream, source);
3237 if(m_CurrentTeletext.id < 0
3238 || m_CurrentTeletext.hint != hint)
3240 if(m_CurrentTeletext.id >= 0)
3242 CLog::Log(LOGDEBUG, " - teletext codecs hints have changed, must close previous stream");
3243 CloseTeletextStream(true);
3246 if (!m_dvdPlayerTeletext.OpenStream(hint))
3248 /* mark stream as disabled, to disallaw further attempts*/
3249 CLog::Log(LOGWARNING, "%s - Unsupported teletext stream %d. Stream disabled.", __FUNCTION__, iStream);
3250 pStream->disabled = true;
3251 pStream->SetDiscard(AVDISCARD_ALL);
3256 m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3258 /* store information about stream */
3259 m_CurrentTeletext.id = iStream;
3260 m_CurrentTeletext.source = source;
3261 m_CurrentTeletext.hint = hint;
3262 m_CurrentTeletext.stream = (void*)pStream;
3263 m_CurrentTeletext.started = false;
3268 bool COMXPlayer::CloseAudioStream(bool bWaitForBuffers)
3270 if (m_CurrentAudio.id < 0)
3273 CLog::Log(LOGNOTICE, "Closing audio stream");
3276 SetCaching(CACHESTATE_DONE);
3278 m_omxPlayerAudio.CloseStream(bWaitForBuffers);
3280 m_CurrentAudio.Clear();
3284 bool COMXPlayer::CloseVideoStream(bool bWaitForBuffers)
3286 if (m_CurrentVideo.id < 0)
3289 CLog::Log(LOGNOTICE, "Closing video stream");
3292 SetCaching(CACHESTATE_DONE);
3294 m_omxPlayerVideo.CloseStream(bWaitForBuffers);
3296 m_CurrentVideo.Clear();
3300 bool COMXPlayer::CloseSubtitleStream(bool bKeepOverlays)
3302 if (m_CurrentSubtitle.id < 0)
3305 CLog::Log(LOGNOTICE, "Closing subtitle stream");
3307 m_dvdPlayerSubtitle.CloseStream(!bKeepOverlays);
3309 m_CurrentSubtitle.Clear();
3313 bool COMXPlayer::CloseTeletextStream(bool bWaitForBuffers)
3315 if (m_CurrentTeletext.id < 0)
3318 CLog::Log(LOGNOTICE, "Closing teletext stream");
3321 SetCaching(CACHESTATE_DONE);
3323 m_dvdPlayerTeletext.CloseStream(bWaitForBuffers);
3325 m_CurrentTeletext.Clear();
3329 void COMXPlayer::FlushBuffers(bool queued, double pts, bool accurate)
3333 CLog::Log(LOGNOTICE, "FlushBuffers: q:%d pts:%.0f a:%d", queued, pts, accurate);
3338 startpts = DVD_NOPTS_VALUE;
3340 /* call with demuxer pts */
3341 if(startpts != DVD_NOPTS_VALUE)
3342 startpts -= m_offset_pts;
3344 m_CurrentAudio.inited = false;
3345 m_CurrentAudio.dts = DVD_NOPTS_VALUE;
3346 m_CurrentAudio.startpts = startpts;
3348 m_CurrentVideo.inited = false;
3349 m_CurrentVideo.dts = DVD_NOPTS_VALUE;
3350 m_CurrentVideo.startpts = startpts;
3352 m_CurrentSubtitle.inited = false;
3353 m_CurrentSubtitle.dts = DVD_NOPTS_VALUE;
3354 m_CurrentSubtitle.startpts = startpts;
3356 m_CurrentTeletext.inited = false;
3357 m_CurrentTeletext.dts = DVD_NOPTS_VALUE;
3358 m_CurrentTeletext.startpts = startpts;
3362 m_omxPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3363 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3364 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP));
3365 m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3366 m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET));
3367 SynchronizePlayers(SYNCSOURCE_ALL);
3371 m_omxPlayerAudio.Flush();
3372 m_omxPlayerVideo.Flush();
3373 m_dvdPlayerSubtitle.Flush();
3374 m_dvdPlayerTeletext.Flush();
3376 // clear subtitle and menu overlays
3377 m_overlayContainer.Clear();
3379 if(m_playSpeed == DVD_PLAYSPEED_NORMAL
3380 || m_playSpeed == DVD_PLAYSPEED_PAUSE)
3382 // make sure players are properly flushed, should put them in stalled state
3383 CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(1000, 0);
3384 m_omxPlayerAudio.SendMessage(msg->Acquire(), 1);
3385 m_omxPlayerVideo.SendMessage(msg->Acquire(), 1);
3386 msg->Wait(&m_bStop, 0);
3389 // purge any pending PLAYER_STARTED messages
3390 m_messenger.Flush(CDVDMsg::PLAYER_STARTED);
3392 // we should now wait for init cache
3393 SetCaching(CACHESTATE_FLUSH);
3394 m_CurrentAudio.started = false;
3395 m_CurrentVideo.started = false;
3396 m_CurrentSubtitle.started = false;
3397 m_CurrentTeletext.started = false;
3400 if(pts != DVD_NOPTS_VALUE)
3401 m_clock.Discontinuity(pts);
3404 // update state, buffers are flushed and it may take some time until
3405 // we get an update from players
3406 CSingleLock lock(m_StateSection);
3407 m_State = m_StateInput;
3411 // since we call ffmpeg functions to decode, this is being called in the same thread as ::Process() is
3412 int COMXPlayer::OnDVDNavResult(void* pData, int iMessage)
3414 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY))
3417 m_overlayContainer.Add((CDVDOverlay*)pData);
3418 else if(iMessage == 1)
3419 m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
3420 else if(iMessage == 2)
3421 m_dvd.iSelectedAudioStream = *(int*)pData;
3422 else if(iMessage == 3)
3423 m_dvd.iSelectedSPUStream = *(int*)pData;
3424 else if(iMessage == 4)
3425 m_omxPlayerVideo.EnableSubtitle(*(int*)pData ? true: false);
3426 else if(iMessage == 5)
3428 if (m_dvd.state != DVDSTATE_STILL)
3430 // else notify the player we have received a still frame
3432 m_dvd.iDVDStillTime = *(int*)pData;
3433 m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis();
3435 /* adjust for the output delay in the video queue */
3436 unsigned int time = 0;
3437 if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 )
3439 time = (unsigned int)(m_omxPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 ));
3440 if( time < 10000 && time > 0 )
3441 m_dvd.iDVDStillTime += time;
3443 m_dvd.state = DVDSTATE_STILL;
3445 "DVDNAV_STILL_FRAME - waiting %i sec, with delay of %d sec",
3446 m_dvd.iDVDStillTime, time / 1000);
3453 if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3455 CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;
3459 case DVDNAV_STILL_FRAME:
3461 //CLog::Log(LOGDEBUG, "DVDNAV_STILL_FRAME");
3463 dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)pData;
3464 // should wait the specified time here while we let the player running
3465 // after that call dvdnav_still_skip(m_dvdnav);
3467 if (m_dvd.state != DVDSTATE_STILL)
3469 // else notify the player we have received a still frame
3471 if(still_event->length < 0xff)
3472 m_dvd.iDVDStillTime = still_event->length * 1000;
3474 m_dvd.iDVDStillTime = 0;
3476 m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis();
3478 /* adjust for the output delay in the video queue */
3480 if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 )
3482 time = (DWORD)(m_omxPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 ));
3483 if( time < 10000 && time > 0 )
3484 m_dvd.iDVDStillTime += time;
3486 m_dvd.state = DVDSTATE_STILL;
3488 "DVDNAV_STILL_FRAME - waiting %i sec, with delay of %d sec",
3489 still_event->length, time / 1000);
3491 return NAVRESULT_HOLD;
3494 case DVDNAV_SPU_CLUT_CHANGE:
3496 m_dvdPlayerSubtitle.SendMessage(new CDVDMsgSubtitleClutChange((BYTE*)pData));
3499 case DVDNAV_SPU_STREAM_CHANGE:
3501 dvdnav_spu_stream_change_event_t* event = (dvdnav_spu_stream_change_event_t*)pData;
3503 int iStream = event->physical_wide;
3504 bool visible = !(iStream & 0x80);
3506 m_omxPlayerVideo.EnableSubtitle(visible);
3509 m_dvd.iSelectedSPUStream = (iStream & ~0x80);
3511 m_dvd.iSelectedSPUStream = -1;
3513 m_CurrentSubtitle.stream = NULL;
3516 case DVDNAV_AUDIO_STREAM_CHANGE:
3518 // This should be the correct way i think, however we don't have any streams right now
3519 // since the demuxer hasn't started so it doesn't change. not sure how to do this.
3520 dvdnav_audio_stream_change_event_t* event = (dvdnav_audio_stream_change_event_t*)pData;
3522 // Tell system what audiostream should be opened by default
3523 if (event->logical >= 0)
3524 m_dvd.iSelectedAudioStream = event->physical;
3526 m_dvd.iSelectedAudioStream = -1;
3528 m_CurrentAudio.stream = NULL;
3531 case DVDNAV_HIGHLIGHT:
3533 //dvdnav_highlight_event_t* pInfo = (dvdnav_highlight_event_t*)pData;
3534 int iButton = pStream->GetCurrentButton();
3535 CLog::Log(LOGDEBUG, "DVDNAV_HIGHLIGHT: Highlight button %d\n", iButton);
3536 m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL);
3539 case DVDNAV_VTS_CHANGE:
3541 //dvdnav_vts_change_event_t* vts_change_event = (dvdnav_vts_change_event_t*)pData;
3542 CLog::Log(LOGDEBUG, "DVDNAV_VTS_CHANGE");
3544 //Make sure we clear all the old overlays here, or else old forced items are left.
3545 m_overlayContainer.Clear();
3547 //Force an aspect ratio that is set in the dvdheaders if available
3548 m_CurrentVideo.hint.aspect = pStream->GetVideoAspectRatio();
3549 if( m_omxPlayerVideo.IsInited() )
3550 m_omxPlayerVideo.SendMessage(new CDVDMsgDouble(CDVDMsg::VIDEO_SET_ASPECT, m_CurrentVideo.hint.aspect));
3552 m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV);
3553 m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
3555 return NAVRESULT_HOLD;
3558 case DVDNAV_CELL_CHANGE:
3560 //dvdnav_cell_change_event_t* cell_change_event = (dvdnav_cell_change_event_t*)pData;
3561 CLog::Log(LOGDEBUG, "DVDNAV_CELL_CHANGE");
3563 m_dvd.state = DVDSTATE_NORMAL;
3565 if( m_omxPlayerVideo.IsInited() )
3566 m_omxPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP));
3569 case DVDNAV_NAV_PACKET:
3571 //pci_t* pci = (pci_t*)pData;
3573 // this should be possible to use to make sure we get
3574 // seamless transitions over these boundaries
3575 // if we remember the old vobunits boundaries
3576 // when a packet comes out of demuxer that has
3577 // pts values outside that boundary, it belongs
3578 // to the new vobunit, wich has new timestamps
3582 case DVDNAV_HOP_CHANNEL:
3584 // This event is issued whenever a non-seamless operation has been executed.
3585 // Applications with fifos should drop the fifos content to speed up responsiveness.
3586 CLog::Log(LOGDEBUG, "DVDNAV_HOP_CHANNEL");
3587 if(m_dvd.state == DVDSTATE_SEEK)
3588 m_dvd.state = DVDSTATE_NORMAL;
3590 m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
3592 return NAVRESULT_ERROR;
3597 CLog::Log(LOGDEBUG, "DVDNAV_STOP");
3598 m_dvd.state = DVDSTATE_NORMAL;
3606 return NAVRESULT_NOP;
3609 bool COMXPlayer::ShowPVRChannelInfo(void)
3611 bool bReturn(false);
3613 if (CSettings::Get().GetBool("pvrmenu.infoswitch"))
3615 int iTimeout = CSettings::Get().GetBool("pvrmenu.infotimeout") ? CSettings::Get().GetInt("pvrmenu.infotime") : 0;
3616 g_PVRManager.ShowPlayerInfo(iTimeout);
3624 bool COMXPlayer::OnAction(const CAction &action)
3626 #define THREAD_ACTION(action) \
3628 if (!IsCurrentThread()) { \
3629 m_messenger.Put(new CDVDMsgType<CAction>(CDVDMsg::GENERAL_GUI_ACTION, action)); \
3634 CDVDInputStream::IMenus* pMenus = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
3637 if( m_dvd.state == DVDSTATE_STILL && m_dvd.iDVDStillTime != 0 && pMenus->GetTotalButtons() == 0 )
3639 switch(action.GetID())
3641 case ACTION_NEXT_ITEM:
3642 case ACTION_MOVE_RIGHT:
3643 case ACTION_MOVE_UP:
3644 case ACTION_SELECT_ITEM:
3646 THREAD_ACTION(action);
3647 /* this will force us out of the stillframe */
3648 CLog::Log(LOGDEBUG, "%s - User asked to exit stillframe", __FUNCTION__);
3649 m_dvd.iDVDStillStartTime = 0;
3650 m_dvd.iDVDStillTime = 1;
3657 switch (action.GetID())
3659 /* this code is disabled to allow switching playlist items (dvdimage "stacks") */
3661 case ACTION_PREV_ITEM: // SKIP-:
3663 THREAD_ACTION(action);
3664 CLog::Log(LOGDEBUG, " - pushed prev");
3665 pMenus->OnPrevious();
3666 g_infoManager.SetDisplayAfterSeek();
3670 case ACTION_NEXT_ITEM: // SKIP+:
3672 THREAD_ACTION(action);
3673 CLog::Log(LOGDEBUG, " - pushed next");
3675 g_infoManager.SetDisplayAfterSeek();
3680 case ACTION_SHOW_VIDEOMENU: // start button
3682 THREAD_ACTION(action);
3683 CLog::Log(LOGDEBUG, " - go to menu");
3685 // send a message to everyone that we've gone to the menu
3686 CGUIMessage msg(GUI_MSG_VIDEO_MENU_STARTED, 0, 0);
3687 g_windowManager.SendThreadMessage(msg);
3693 if (pMenus->IsInMenu())
3695 switch (action.GetID())
3697 case ACTION_NEXT_ITEM:
3698 THREAD_ACTION(action);
3699 CLog::Log(LOGDEBUG, " - pushed next in menu, stream will decide");
3701 g_infoManager.SetDisplayAfterSeek();
3703 case ACTION_PREV_ITEM:
3704 THREAD_ACTION(action);
3705 CLog::Log(LOGDEBUG, " - pushed prev in menu, stream will decide");
3706 pMenus->OnPrevious();
3707 g_infoManager.SetDisplayAfterSeek();
3709 case ACTION_PREVIOUS_MENU:
3710 case ACTION_NAV_BACK:
3712 THREAD_ACTION(action);
3713 CLog::Log(LOGDEBUG, " - menu back");
3717 case ACTION_MOVE_LEFT:
3719 THREAD_ACTION(action);
3720 CLog::Log(LOGDEBUG, " - move left");
3724 case ACTION_MOVE_RIGHT:
3726 THREAD_ACTION(action);
3727 CLog::Log(LOGDEBUG, " - move right");
3731 case ACTION_MOVE_UP:
3733 THREAD_ACTION(action);
3734 CLog::Log(LOGDEBUG, " - move up");
3738 case ACTION_MOVE_DOWN:
3740 THREAD_ACTION(action);
3741 CLog::Log(LOGDEBUG, " - move down");
3746 case ACTION_MOUSE_MOVE:
3747 case ACTION_MOUSE_LEFT_CLICK:
3750 g_renderManager.GetVideoRect(rs, rd);
3751 CPoint pt(action.GetAmount(), action.GetAmount(1));
3752 if (!rd.PtInRect(pt))
3753 return false; // out of bounds
3754 THREAD_ACTION(action);
3755 // convert to video coords...
3756 pt -= CPoint(rd.x1, rd.y1);
3757 pt.x *= rs.Width() / rd.Width();
3758 pt.y *= rs.Height() / rd.Height();
3759 pt += CPoint(rs.x1, rs.y1);
3760 if (action.GetID() == ACTION_MOUSE_LEFT_CLICK)
3761 return pMenus->OnMouseClick(pt);
3762 return pMenus->OnMouseMove(pt);
3765 case ACTION_SELECT_ITEM:
3767 THREAD_ACTION(action);
3768 CLog::Log(LOGDEBUG, " - button select");
3769 // show button pushed overlay
3770 if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3771 m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_CLICKED);
3773 pMenus->ActivateButton();
3787 THREAD_ACTION(action);
3788 // Offset from key codes back to button number
3789 int button = action.GetID() - REMOTE_0;
3790 CLog::Log(LOGDEBUG, " - button pressed %d", button);
3791 pMenus->SelectButton(button);
3798 return true; // message is handled
3802 if (dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream))
3804 switch (action.GetID())
3806 case ACTION_MOVE_UP:
3807 case ACTION_NEXT_ITEM:
3808 case ACTION_CHANNEL_UP:
3809 m_messenger.Put(new CDVDMsg(CDVDMsg::PLAYER_CHANNEL_NEXT));
3810 g_infoManager.SetDisplayAfterSeek();
3811 ShowPVRChannelInfo();
3815 case ACTION_MOVE_DOWN:
3816 case ACTION_PREV_ITEM:
3817 case ACTION_CHANNEL_DOWN:
3818 m_messenger.Put(new CDVDMsg(CDVDMsg::PLAYER_CHANNEL_PREV));
3819 g_infoManager.SetDisplayAfterSeek();
3820 ShowPVRChannelInfo();
3824 case ACTION_CHANNEL_SWITCH:
3826 // Offset from key codes back to button number
3827 int channel = action.GetAmount();
3828 m_messenger.Put(new CDVDMsgInt(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER, channel));
3829 g_infoManager.SetDisplayAfterSeek();
3830 ShowPVRChannelInfo();
3837 switch (action.GetID())
3839 case ACTION_NEXT_ITEM:
3840 if(GetChapterCount() > 0)
3842 m_messenger.Put(new CDVDMsgPlayerSeekChapter(GetChapter()+1));
3843 g_infoManager.SetDisplayAfterSeek();
3848 case ACTION_PREV_ITEM:
3849 if(GetChapterCount() > 0)
3851 m_messenger.Put(new CDVDMsgPlayerSeekChapter(GetChapter()-1));
3852 g_infoManager.SetDisplayAfterSeek();
3859 // return false to inform the caller we didn't handle the message
3863 bool COMXPlayer::IsInMenu() const
3865 CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
3868 if( m_dvd.state == DVDSTATE_STILL )
3871 return pStream->IsInMenu();
3876 bool COMXPlayer::HasMenu()
3878 CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream);
3885 bool COMXPlayer::GetCurrentSubtitle(CStdString& strSubtitle)
3887 double pts = m_av_clock.OMXMediaTime(false);
3889 if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
3892 m_dvdPlayerSubtitle.GetCurrentSubtitle(strSubtitle, pts - m_omxPlayerVideo.GetSubtitleDelay());
3894 // In case we stalled, don't output any subs
3895 if ((m_omxPlayerVideo.IsStalled() && HasVideo()) || (m_omxPlayerAudio.IsStalled() && HasAudio()))
3896 strSubtitle = m_lastSub;
3898 m_lastSub = strSubtitle;
3900 return !strSubtitle.IsEmpty();
3903 CStdString COMXPlayer::GetPlayerState()
3905 CSingleLock lock(m_StateSection);
3906 return m_State.player_state;
3909 bool COMXPlayer::SetPlayerState(CStdString state)
3911 m_messenger.Put(new CDVDMsgPlayerSetState(state));
3915 int COMXPlayer::GetChapterCount()
3917 CSingleLock lock(m_StateSection);
3918 return m_State.chapter_count;
3921 int COMXPlayer::GetChapter()
3923 CSingleLock lock(m_StateSection);
3924 return m_State.chapter;
3927 void COMXPlayer::GetChapterName(CStdString& strChapterName)
3929 CSingleLock lock(m_StateSection);
3930 strChapterName = m_State.chapter_name;
3933 int COMXPlayer::SeekChapter(int iChapter)
3935 if (GetChapterCount() > 0)
3939 if (iChapter > GetChapterCount())
3942 // Seek to the chapter.
3943 m_messenger.Put(new CDVDMsgPlayerSeekChapter(iChapter));
3944 SynchronizeDemuxer(100);
3948 // Do a regular big jump.
3949 if (GetChapter() > 0 && iChapter > GetChapter())
3957 int COMXPlayer::AddSubtitle(const CStdString& strSubPath)
3959 return AddSubtitleFile(strSubPath);
3962 int COMXPlayer::GetCacheLevel() const
3964 CSingleLock lock(m_StateSection);
3965 return (int)(m_StateInput.cache_level * 100);
3968 double COMXPlayer::GetQueueTime()
3970 int a = m_omxPlayerVideo.GetLevel();
3971 int v = m_omxPlayerAudio.GetLevel();
3972 return max(a, v) * 8000.0 / 100;
3975 void COMXPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info)
3977 info.bitrate = m_omxPlayerVideo.GetVideoBitrate();
3980 if (m_pDemuxer && (m_CurrentVideo.id != -1))
3981 m_pDemuxer->GetStreamCodecName(m_CurrentVideo.id, retVal);
3982 info.videoCodecName = retVal;
3983 info.videoAspectRatio = g_renderManager.GetAspectRatio();
3984 g_renderManager.GetVideoRect(info.SrcRect, info.DestRect);
3987 int COMXPlayer::GetSourceBitrate()
3990 return (int)m_pInputStream->GetBitstreamStats().GetBitrate();
3995 void COMXPlayer::GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info)
3997 if (index < 0 || index > GetAudioStreamCount() - 1)
4000 if (index == GetAudioStream())
4001 info.bitrate = m_omxPlayerAudio.GetAudioBitrate();
4003 info.bitrate = m_pDemuxer->GetStreamFromAudioId(index)->iBitRate;
4005 OMXSelectionStream& s = m_SelectionStreams.Get(STREAM_AUDIO, index);
4006 if(s.language.length() > 0)
4007 info.language = s.language;
4009 if(s.name.length() > 0)
4012 if(s.type == STREAM_NONE)
4013 info.name += " (Invalid)";
4017 CDemuxStreamAudio* stream = static_cast<CDemuxStreamAudio*>(m_pDemuxer->GetStreamFromAudioId(index));
4020 info.channels = stream->iChannels;
4021 CStdString codecName;
4022 m_pDemuxer->GetStreamCodecName(stream->iId, codecName);
4023 info.audioCodecName = codecName;
4028 int COMXPlayer::AddSubtitleFile(const std::string& filename, const std::string& subfilename, CDemuxStream::EFlags flags)
4030 std::string ext = URIUtils::GetExtension(filename);
4031 std::string vobsubfile = subfilename;
4034 if (vobsubfile.empty())
4035 vobsubfile = URIUtils::ReplaceExtension(filename, ".sub");
4038 if(!v.Open(filename, vobsubfile))
4040 m_SelectionStreams.Update(NULL, &v);
4041 int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, m_SelectionStreams.Source(STREAM_SOURCE_DEMUX_SUB, filename), 0);
4042 m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags;
4043 m_SelectionStreams.Get(STREAM_SUBTITLE, index).filename2 = vobsubfile;
4048 CStdString strReplace(URIUtils::ReplaceExtension(filename,".idx"));
4049 if (XFILE::CFile::Exists(strReplace))
4052 OMXSelectionStream s;
4053 s.source = m_SelectionStreams.Source(STREAM_SOURCE_TEXT, filename);
4054 s.type = STREAM_SUBTITLE;
4056 s.filename = filename;
4057 s.name = URIUtils::GetFileName(filename);
4059 m_SelectionStreams.Update(s);
4060 return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, s.source, s.id);
4063 void COMXPlayer::UpdatePlayState(double timeout)
4065 if(m_StateInput.timestamp != 0
4066 && m_StateInput.timestamp + DVD_MSEC_TO_TIME(timeout) > m_clock.GetAbsoluteClock())
4069 SPlayerState state(m_StateInput);
4071 if (m_CurrentVideo.dts != DVD_NOPTS_VALUE)
4072 state.dts = m_CurrentVideo.dts;
4073 else if(m_CurrentAudio.dts != DVD_NOPTS_VALUE)
4074 state.dts = m_CurrentAudio.dts;
4078 state.chapter = m_pDemuxer->GetChapter();
4079 state.chapter_count = m_pDemuxer->GetChapterCount();
4080 m_pDemuxer->GetChapterName(state.chapter_name);
4082 if(state.dts == DVD_NOPTS_VALUE)
4085 state.time = DVD_TIME_TO_MSEC(state.dts + m_offset_pts);
4086 state.time_total = m_pDemuxer->GetStreamLength();
4087 state.time_src = ETIMESOURCE_CLOCK;
4090 state.canpause = true;
4091 state.canseek = true;
4095 // override from input stream if needed
4096 CDVDInputStream::IChannel* pChannel = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
4099 state.canrecord = pChannel->CanRecord();
4100 state.recording = pChannel->IsRecording();
4103 CDVDInputStream::IDisplayTime* pDisplayTime = dynamic_cast<CDVDInputStream::IDisplayTime*>(m_pInputStream);
4104 if (pDisplayTime && pDisplayTime->GetTotalTime() > 0)
4106 state.time = pDisplayTime->GetTime();
4107 state.time_total = pDisplayTime->GetTotalTime();
4108 state.time_src = ETIMESOURCE_INPUT;
4111 if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream))
4113 if(!ptr->GetState(state.player_state))
4114 state.player_state = "";
4116 if(m_dvd.state == DVDSTATE_STILL)
4118 state.time = XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime;
4119 state.time_total = m_dvd.iDVDStillTime;
4120 state.time_src = ETIMESOURCE_MENU;
4124 if (CDVDInputStream::ISeekable* ptr = dynamic_cast<CDVDInputStream::ISeekable*>(m_pInputStream))
4126 state.canpause = ptr->CanPause();
4127 state.canseek = ptr->CanSeek();
4133 state.time = m_Edl.RemoveCutTime(llrint(state.time));
4134 state.time_total = m_Edl.RemoveCutTime(llrint(state.time_total));
4137 if(state.time_total <= 0)
4138 state.canseek = false;
4140 if (state.time_src == ETIMESOURCE_CLOCK)
4141 state.time_offset = m_offset_pts;
4142 else if (state.dts != DVD_NOPTS_VALUE)
4143 state.time_offset = DVD_MSEC_TO_TIME(state.time) - state.dts;
4145 if (m_CurrentAudio.id >= 0 && m_pDemuxer)
4147 CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentAudio.id);
4148 if (pStream && pStream->type == STREAM_AUDIO)
4149 ((CDemuxStreamAudio*)pStream)->GetStreamInfo(state.demux_audio);
4152 state.demux_audio = "";
4154 if (m_CurrentVideo.id >= 0 && m_pDemuxer)
4156 CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentVideo.id);
4157 if (pStream && pStream->type == STREAM_VIDEO)
4158 ((CDemuxStreamVideo*)pStream)->GetStreamInfo(state.demux_video);
4161 state.demux_video = "";
4163 double level, delay, offset;
4164 if(GetCachingTimes(level, delay, offset))
4166 state.cache_delay = max(0.0, delay);
4167 state.cache_level = max(0.0, min(1.0, level));
4168 state.cache_offset = offset;
4172 state.cache_delay = 0.0;
4173 state.cache_level = min(1.0, GetQueueTime() / 8000.0);
4174 state.cache_offset = GetQueueTime() / state.time_total;
4177 XFILE::SCacheStatus status;
4178 if(m_pInputStream && m_pInputStream->GetCacheStatus(&status))
4180 state.cache_bytes = status.forward;
4181 if(state.time_total)
4182 state.cache_bytes += m_pInputStream->GetLength() * GetQueueTime() / state.time_total;
4185 state.cache_bytes = 0;
4187 state.timestamp = m_clock.GetAbsoluteClock();
4188 //{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_av_clock.OMXMediaTime()), (int)m_playSpeed, (int)m_caching, llrint(state.time + DVD_TIME_TO_MSEC(offset)));}
4190 CSingleLock lock(m_StateSection);
4191 m_StateInput = state;
4194 void COMXPlayer::UpdateApplication(double timeout)
4196 if(m_UpdateApplication != 0
4197 && m_UpdateApplication + DVD_MSEC_TO_TIME(timeout) > m_clock.GetAbsoluteClock())
4200 CDVDInputStream::IChannel* pStream = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream);
4203 CFileItem item(g_application.CurrentFileItem());
4204 if(pStream->UpdateItem(item))
4206 g_application.CurrentFileItem() = item;
4207 CApplicationMessenger::Get().SetCurrentItem(item);
4210 m_UpdateApplication = m_clock.GetAbsoluteClock();
4213 bool COMXPlayer::CanRecord()
4215 CSingleLock lock(m_StateSection);
4216 return m_State.canrecord;
4219 bool COMXPlayer::IsRecording()
4221 CSingleLock lock(m_StateSection);
4222 return m_State.recording;
4225 bool COMXPlayer::Record(bool bOnOff)
4227 if (m_pInputStream && (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV) ||
4228 m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) )
4230 m_messenger.Put(new CDVDMsgBool(CDVDMsg::PLAYER_SET_RECORD, bOnOff));
4236 int COMXPlayer::GetPictureWidth()
4238 if (m_pDemuxer && (m_CurrentVideo.id != -1))
4240 CDemuxStreamVideo* stream = static_cast<CDemuxStreamVideo*>(m_pDemuxer->GetStream(m_CurrentVideo.id));
4242 return stream->iWidth;
4247 int COMXPlayer::GetPictureHeight()
4249 if (m_pDemuxer && (m_CurrentVideo.id != -1))
4251 CDemuxStreamVideo* stream = static_cast<CDemuxStreamVideo*>(m_pDemuxer->GetStream(m_CurrentVideo.id));
4253 return stream->iHeight;
4258 bool COMXPlayer::GetStreamDetails(CStreamDetails &details)
4262 bool result = CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, details);
4263 if (result && details.GetStreamCount(CStreamDetail::VIDEO) > 0) // this is more correct (dvds in particular)
4266 * We can only obtain the aspect & duration from dvdplayer when the Process() thread is running
4267 * and UpdatePlayState() has been called at least once. In this case dvdplayer duration/AR will
4268 * return 0 and we'll have to fallback to the (less accurate) info from the demuxer.
4270 float aspect = m_omxPlayerVideo.GetAspectRatio();
4272 ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_fAspect = aspect;
4274 int64_t duration = GetTotalTime() / 1000;
4276 ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_iDuration = duration;
4284 CStdString COMXPlayer::GetPlayingTitle()
4286 /* Currently we support only Title Name from Teletext line 30 */
4287 TextCacheStruct_t* ttcache = m_dvdPlayerTeletext.GetTeletextCache();
4288 if (ttcache && !ttcache->line30.empty())
4289 return ttcache->line30;
4294 bool COMXPlayer::SwitchChannel(const CPVRChannel &channel)
4296 if (!g_PVRManager.CheckParentalLock(channel))
4300 if (!g_PVRManager.PerformChannelSwitch(channel, true))
4303 UpdateApplication(0);
4306 /* make sure the pvr window is updated */
4307 CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
4309 pWindow->SetInvalid();
4311 /* select the new channel */
4312 m_messenger.Put(new CDVDMsgType<CPVRChannel>(CDVDMsg::PLAYER_CHANNEL_SELECT, channel));
4317 bool COMXPlayer::CachePVRStream(void) const
4319 return m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) &&
4320 !g_PVRManager.IsPlayingRecording() &&
4321 g_advancedSettings.m_bPVRCacheInDvdPlayer;
4324 void COMXPlayer::SetMute(bool bOnOff)
4326 m_current_mute = bOnOff;
4327 m_change_volume = true;
4330 void COMXPlayer::SetVolume(float fVolume)
4332 m_current_volume = fVolume;
4333 m_change_volume = true;
4336 void COMXPlayer::GetRenderFeatures(std::vector<int> &renderFeatures)
4338 renderFeatures.push_back(RENDERFEATURE_STRETCH);
4339 renderFeatures.push_back(RENDERFEATURE_CROP);
4342 void COMXPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
4344 deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
4347 void COMXPlayer::GetDeinterlaceModes(std::vector<int> &deinterlaceModes)
4349 deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
4350 deinterlaceModes.push_back(VS_DEINTERLACEMODE_OFF);
4351 deinterlaceModes.push_back(VS_DEINTERLACEMODE_FORCE);
4354 void COMXPlayer::GetScalingMethods(std::vector<int> &scalingMethods)
4358 void COMXPlayer::GetAudioCapabilities(std::vector<int> &audioCaps)
4360 audioCaps.push_back(IPC_AUD_OFFSET);
4361 audioCaps.push_back(IPC_AUD_SELECT_STREAM);
4362 audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
4365 void COMXPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps)
4367 subCaps.push_back(IPC_SUBS_ALL);