diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2014-09-04 04:42:52 +0200 |
---|---|---|
committer | Rainer Hochecker <fernetmenta@online.de> | 2014-09-04 04:42:52 +0200 |
commit | 661706dc4a27b223d14bc463e5e71489d598b477 (patch) | |
tree | 8ec73624b6b4be405a3324db9afb55a5f105a43c | |
parent | d3f48dd9128debf6a3b5b1749292ef19cdc37bbf (diff) | |
parent | 2d110347201448110782659b60586212801aeab4 (diff) |
Merge pull request #5084 from popcornmix/dvdrefactor
[players] Make omxplayer be derived from dvdplayer [RFC]
33 files changed, 729 insertions, 5254 deletions
diff --git a/language/English/strings.po b/language/English/strings.po index 1ff8f1313a..fea6e0837b 100755 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -6196,7 +6196,18 @@ msgctxt "#13457" msgid "Prefer VAAPI render method" msgstr "" -#empty strings from id 13458 to 13499 +#: system/settings/settings.xml +msgctxt "#13458" +msgid "Allow hardware acceleration (OMXPlayer)" +msgstr "" + +#. Description of setting "Videos -> Playback -> Allow hardware acceleration (OMXPlayer)" with label #13457 +#: system/settings/settings.xml +msgctxt "#13459" +msgid "Use OMXPlayer for decoding of video files." +msgstr "" + +#empty strings from id 13460 to 13499 #: system/settings/settings.xml msgctxt "#13500" diff --git a/system/settings/settings.xml b/system/settings/settings.xml index f604b30e3c..af05fb7ddc 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -752,6 +752,15 @@ <default>true</default> <control type="toggle" /> </setting> + <setting id="videoplayer.useomxplayer" type="boolean" label="13458" help="13459"> + <requirement>HAS_OMXPLAYER</requirement> + <dependencies> + <dependency type="enable" setting="videoplayer.decodingmethod" operator="is">1</dependency> + </dependencies> + <level>2</level> + <default>true</default> + <control type="toggle" /> + </setting> <setting id="videoplayer.useomx" type="boolean" label="13430" help="36161"> <requirement>HAVE_LIBOPENMAX</requirement> <dependencies> diff --git a/xbmc/ApplicationPlayer.cpp b/xbmc/ApplicationPlayer.cpp index fcf3dc3653..6981d24780 100644 --- a/xbmc/ApplicationPlayer.cpp +++ b/xbmc/ApplicationPlayer.cpp @@ -64,9 +64,6 @@ void CApplicationPlayer::ClosePlayerGapless(PLAYERCOREID newCore) return; bool gaplessSupported = (m_eCurrentPlayer == EPC_DVDPLAYER || m_eCurrentPlayer == EPC_PAPLAYER); -#if defined(HAS_OMXPLAYER) - gaplessSupported = gaplessSupported || (m_eCurrentPlayer == EPC_OMXPLAYER); -#endif gaplessSupported = gaplessSupported && (m_eCurrentPlayer == newCore); if (!gaplessSupported) { @@ -116,20 +113,6 @@ bool CApplicationPlayer::HasPlayer() const return player != NULL; } -void CApplicationPlayer::RegisterAudioCallback(IAudioCallback* pCallback) -{ - boost::shared_ptr<IPlayer> player = GetInternal(); - if (player) - player->RegisterAudioCallback(pCallback); -} - -void CApplicationPlayer::UnRegisterAudioCallback() -{ - boost::shared_ptr<IPlayer> player = GetInternal(); - if (player) - player->UnRegisterAudioCallback(); -} - int CApplicationPlayer::GetChapter() { boost::shared_ptr<IPlayer> player = GetInternal(); @@ -621,28 +604,28 @@ void CApplicationPlayer::GetRenderFeatures(std::vector<int> &renderFeatures) { boost::shared_ptr<IPlayer> player = GetInternal(); if (player) - player->GetRenderFeatures(renderFeatures); + player->OMXGetRenderFeatures(renderFeatures); } void CApplicationPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods) { boost::shared_ptr<IPlayer> player = GetInternal(); if (player) - player->GetDeinterlaceMethods(deinterlaceMethods); + player->OMXGetDeinterlaceMethods(deinterlaceMethods); } void CApplicationPlayer::GetDeinterlaceModes(std::vector<int> &deinterlaceModes) { boost::shared_ptr<IPlayer> player = GetInternal(); if (player) - player->GetDeinterlaceModes(deinterlaceModes); + player->OMXGetDeinterlaceModes(deinterlaceModes); } void CApplicationPlayer::GetScalingMethods(std::vector<int> &scalingMethods) { boost::shared_ptr<IPlayer> player = GetInternal(); if (player) - player->GetScalingMethods(scalingMethods); + player->OMXGetScalingMethods(scalingMethods); } void CApplicationPlayer::SetPlaySpeed(int iSpeed, bool bApplicationMuted) diff --git a/xbmc/ApplicationPlayer.h b/xbmc/ApplicationPlayer.h index 964570c251..8abcd46ec7 100644 --- a/xbmc/ApplicationPlayer.h +++ b/xbmc/ApplicationPlayer.h @@ -37,7 +37,6 @@ namespace PVR class CPVRChannel; } -class IAudioCallback; class CAction; class CPlayerOptions; class CStreamDetails; @@ -133,7 +132,6 @@ public: void Pause(); bool QueueNextFile(const CFileItem &file); bool Record(bool bOnOff); - void RegisterAudioCallback(IAudioCallback* pCallback); void Seek(bool bPlus = true, bool bLargeStep = false, bool bChapterOverride = false); int SeekChapter(int iChapter); void SeekPercentage(float fPercent = 0); @@ -150,5 +148,4 @@ public: void SetVolume(float volume); bool SwitchChannel(const PVR::CPVRChannel &channel); void ToFFRW(int iSpeed = 0); - void UnRegisterAudioCallback(); }; diff --git a/xbmc/addons/Visualisation.cpp b/xbmc/addons/Visualisation.cpp index 9412963a78..810e5b2ff2 100644 --- a/xbmc/addons/Visualisation.cpp +++ b/xbmc/addons/Visualisation.cpp @@ -109,7 +109,6 @@ bool CVisualisation::Create(int x, int y, int w, int h, void *device) CreateBuffers(); - g_application.m_pPlayer->RegisterAudioCallback(this); CAEFactory::RegisterAudioCallback(this); return true; @@ -174,7 +173,6 @@ void CVisualisation::Render() void CVisualisation::Stop() { - g_application.m_pPlayer->UnRegisterAudioCallback(); CAEFactory::UnregisterAudioCallback(); if (Initialized()) { diff --git a/xbmc/cores/DummyVideoPlayer.h b/xbmc/cores/DummyVideoPlayer.h index 85cb90edab..5bc12fd617 100644 --- a/xbmc/cores/DummyVideoPlayer.h +++ b/xbmc/cores/DummyVideoPlayer.h @@ -28,8 +28,6 @@ class CDummyVideoPlayer : public IPlayer, public CThread public: CDummyVideoPlayer(IPlayerCallback& callback); virtual ~CDummyVideoPlayer(); - virtual void RegisterAudioCallback(IAudioCallback* pCallback) {} - virtual void UnRegisterAudioCallback() {} virtual bool OpenFile(const CFileItem& file, const CPlayerOptions &options); virtual bool CloseFile(); virtual bool IsPlaying() const; diff --git a/xbmc/cores/ExternalPlayer/ExternalPlayer.h b/xbmc/cores/ExternalPlayer/ExternalPlayer.h index 66f1cbfa56..06ebf92c44 100644 --- a/xbmc/cores/ExternalPlayer/ExternalPlayer.h +++ b/xbmc/cores/ExternalPlayer/ExternalPlayer.h @@ -35,8 +35,6 @@ public: CExternalPlayer(IPlayerCallback& callback); virtual ~CExternalPlayer(); virtual bool Initialize(TiXmlElement* pConfig); - virtual void RegisterAudioCallback(IAudioCallback* pCallback) {} - virtual void UnRegisterAudioCallback() {} virtual bool OpenFile(const CFileItem& file, const CPlayerOptions &options); virtual bool CloseFile(bool reopen = false); virtual bool IsPlaying() const; diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h index 26489cbe81..a72c219c22 100644 --- a/xbmc/cores/IPlayer.h +++ b/xbmc/cores/IPlayer.h @@ -128,8 +128,6 @@ public: IPlayer(IPlayerCallback& callback): m_callback(callback){}; virtual ~IPlayer(){}; virtual bool Initialize(TiXmlElement* pConfig) { return true; }; - virtual void RegisterAudioCallback(IAudioCallback* pCallback) {}; - virtual void UnRegisterAudioCallback() {}; virtual bool OpenFile(const CFileItem& file, const CPlayerOptions& options){ return false;} virtual bool QueueNextFile(const CFileItem &file) { return false; } virtual void OnNothingToQueueNotify() {} @@ -221,22 +219,24 @@ public: virtual bool SwitchChannel(const PVR::CPVRChannel &channel) { return false; } + // Note: the following "OMX" methods are deprecated and will be removed in the future + // They should be handled by the video renderer, not the player /*! \brief If the player uses bypass mode, define its rendering capabilities */ - virtual void GetRenderFeatures(std::vector<int> &renderFeatures) {}; + virtual void OMXGetRenderFeatures(std::vector<int> &renderFeatures) {}; /*! \brief If the player uses bypass mode, define its deinterlace algorithms */ - virtual void GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods) {}; + virtual void OMXGetDeinterlaceMethods(std::vector<int> &deinterlaceMethods) {}; /*! \brief If the player uses bypass mode, define how deinterlace is set */ - virtual void GetDeinterlaceModes(std::vector<int> &deinterlaceModes) {}; + virtual void OMXGetDeinterlaceModes(std::vector<int> &deinterlaceModes) {}; /*! \brief If the player uses bypass mode, define its scaling capabilities */ - virtual void GetScalingMethods(std::vector<int> &scalingMethods) {}; + virtual void OMXGetScalingMethods(std::vector<int> &scalingMethods) {}; /*! \brief define the audio capabilities of the player (default=all) */ diff --git a/xbmc/cores/dvdplayer/DVDAudio.cpp b/xbmc/cores/dvdplayer/DVDAudio.cpp index 46e9509b6b..6514030357 100644 --- a/xbmc/cores/dvdplayer/DVDAudio.cpp +++ b/xbmc/cores/dvdplayer/DVDAudio.cpp @@ -95,7 +95,6 @@ CDVDAudio::CDVDAudio(volatile bool &bStop) : m_bStop(bStop) { m_pAudioStream = NULL; - m_pAudioCallback = NULL; m_bPassthrough = false; m_iBitsPerSample = 0; m_iBitrate = 0; @@ -146,9 +145,6 @@ bool CDVDAudio::Create(const DVDAudioFrame &audioframe, AVCodecID codec, bool ne SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100)); - if (m_pAudioCallback) - RegisterAudioCallback(m_pAudioCallback); - return true; } @@ -225,22 +221,6 @@ void CDVDAudio::Drain() m_pAudioStream->Drain(true); } -void CDVDAudio::RegisterAudioCallback(IAudioCallback* pCallback) -{ - CSingleLock lock (m_critSection); - m_pAudioCallback = pCallback; - if (m_pAudioStream) - m_pAudioStream->RegisterAudioCallback(pCallback); -} - -void CDVDAudio::UnRegisterAudioCallback() -{ - CSingleLock lock (m_critSection); - if (m_pAudioStream) - m_pAudioStream->UnRegisterAudioCallback(); - m_pAudioCallback = NULL; -} - void CDVDAudio::SetVolume(float volume) { CSingleLock lock (m_critSection); diff --git a/xbmc/cores/dvdplayer/DVDAudio.h b/xbmc/cores/dvdplayer/DVDAudio.h index 54c34e5d93..629fb3237e 100644 --- a/xbmc/cores/dvdplayer/DVDAudio.h +++ b/xbmc/cores/dvdplayer/DVDAudio.h @@ -52,7 +52,6 @@ public: }; class CSingleLock; -class IAudioCallback; class CDVDAudio { @@ -60,9 +59,6 @@ public: CDVDAudio(volatile bool& bStop); ~CDVDAudio(); - void RegisterAudioCallback(IAudioCallback* pCallback); - void UnRegisterAudioCallback(); - void SetVolume(float fVolume); void SetDynamicRangeCompression(long drc); float GetCurrentAttenuation(); @@ -97,7 +93,6 @@ protected: bool m_bPaused; volatile bool& m_bStop; - IAudioCallback* m_pAudioCallback; //the viz audio callback //counter that will go from 0 to m_iSpeed-1 and reset, data will only be output when speedstep is 0 //int m_iSpeedStep; }; diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp index 39951a3110..8f41c763fc 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -85,6 +85,11 @@ #include "utils/LangCodeExpander.h" #include "video/VideoReferenceClock.h" +#ifdef HAS_OMXPLAYER +#include "cores/omxplayer/OMXPlayerAudio.h" +#include "cores/omxplayer/OMXPlayerVideo.h" +#endif + using namespace std; using namespace PVR; @@ -483,6 +488,39 @@ void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer) } } +void CDVDPlayer::CreatePlayers() +{ + if (m_players_created) + return; + + if (m_omxplayer_mode) + { +#ifdef HAS_OMXPLAYER + m_dvdPlayerVideo = new OMXPlayerVideo(&m_OmxPlayerState.av_clock, &m_overlayContainer, m_messenger); + m_dvdPlayerAudio = new OMXPlayerAudio(&m_OmxPlayerState.av_clock, m_messenger); +#endif + } + else + { + m_dvdPlayerVideo = new CDVDPlayerVideo(&m_clock, &m_overlayContainer, m_messenger); + m_dvdPlayerAudio = new CDVDPlayerAudio(&m_clock, m_messenger); + } + m_dvdPlayerSubtitle = new CDVDPlayerSubtitle(&m_overlayContainer); + m_dvdPlayerTeletext = new CDVDTeletextData(); + m_players_created = true; +} + +void CDVDPlayer::DestroyPlayers() +{ + if (!m_players_created) + return; + delete m_dvdPlayerVideo; + delete m_dvdPlayerAudio; + delete m_dvdPlayerSubtitle; + delete m_dvdPlayerTeletext; + m_players_created = false; +} + CDVDPlayer::CDVDPlayer(IPlayerCallback& callback) : IPlayer(callback), CThread("DVDPlayer"), @@ -491,13 +529,10 @@ CDVDPlayer::CDVDPlayer(IPlayerCallback& callback) m_CurrentSubtitle(STREAM_SUBTITLE, DVDPLAYER_SUBTITLE), m_CurrentTeletext(STREAM_TELETEXT, DVDPLAYER_TELETEXT), m_messenger("player"), - m_dvdPlayerVideo(&m_clock, &m_overlayContainer, m_messenger), - m_dvdPlayerAudio(&m_clock, m_messenger), - m_dvdPlayerSubtitle(&m_overlayContainer), - m_dvdPlayerTeletext(), m_ready(true), m_DemuxerPausePending(false) { + m_players_created = false; m_pDemuxer = NULL; m_pSubtitleDemuxer = NULL; m_pInputStream = NULL; @@ -516,11 +551,30 @@ CDVDPlayer::CDVDPlayer(IPlayerCallback& callback) m_HasAudio = false; memset(&m_SpeedState, 0, sizeof(m_SpeedState)); + + // omxplayer variables + m_OmxPlayerState.video_fifo = 0; + m_OmxPlayerState.audio_fifo = 0; + m_OmxPlayerState.last_check_time = 0.0; + m_OmxPlayerState.stamp = 0.0; + m_OmxPlayerState.bOmxWaitVideo = false; + m_OmxPlayerState.bOmxWaitAudio = false; + m_OmxPlayerState.bOmxSentEOFs = false; + m_OmxPlayerState.threshold = 0.2f; + m_OmxPlayerState.current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +#ifdef HAS_OMXPLAYER + m_omxplayer_mode = CSettings::Get().GetBool("videoplayer.useomxplayer"); +#else + m_omxplayer_mode = false; +#endif + + CreatePlayers(); } CDVDPlayer::~CDVDPlayer() { CloseFile(); + DestroyPlayers(); } bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) @@ -812,7 +866,7 @@ bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream) { // check if we should read from subtitle demuxer - if( m_pSubtitleDemuxer && m_dvdPlayerSubtitle.AcceptsData() ) + if( m_pSubtitleDemuxer && m_dvdPlayerSubtitle->AcceptsData() ) { packet = m_pSubtitleDemuxer->Read(); @@ -837,6 +891,16 @@ bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream) } } + if (m_omxplayer_mode) + { + // reset eos state when we get a packet (e.g. for case of seek after eos) + if (packet && stream) + { + m_OmxPlayerState.bOmxWaitVideo = false; + m_OmxPlayerState.bOmxWaitAudio = false; + m_OmxPlayerState.bOmxSentEOFs = false; + } + } // read a data frame from stream. if(m_pDemuxer) packet = m_pDemuxer->Read(); @@ -982,6 +1046,120 @@ void CDVDPlayer::CheckBetterStream(CCurrentStream& current, CDemuxStream* stream OpenStream(current, stream->iId, stream->source); } +void CDVDPlayer::OMXDoProcessing() +{ +#ifdef HAS_OMXPLAYER + double now = CDVDClock::GetAbsoluteClock(); + if (m_OmxPlayerState.last_check_time == 0.0 || m_OmxPlayerState.last_check_time + DVD_MSEC_TO_TIME(20) <= now) + { + m_OmxPlayerState.last_check_time = now; + m_OmxPlayerState.stamp = m_OmxPlayerState.av_clock.OMXMediaTime(); + const bool m_Pause = m_playSpeed == DVD_PLAYSPEED_PAUSE; + const bool not_accepts_data = (!m_dvdPlayerAudio->AcceptsData() && m_CurrentAudio.id >= 0) || + (!m_dvdPlayerVideo->AcceptsData() && m_CurrentVideo.id >= 0); + /* when the video/audio fifos are low, we pause clock, when high we resume */ + double audio_pts = floor(m_dvdPlayerAudio->GetCurrentPts()); + double video_pts = floor(m_dvdPlayerVideo->GetCurrentPts()); + + float audio_fifo = audio_pts / DVD_TIME_BASE - m_OmxPlayerState.stamp * 1e-6; + float video_fifo = video_pts / DVD_TIME_BASE - m_OmxPlayerState.stamp * 1e-6; + float threshold = 0.1f; + bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false; + + // if deinterlace setting has changed, we should close and open video + if (m_OmxPlayerState.current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode) + { + CloseStream(m_CurrentVideo, false); + OpenStream(m_CurrentVideo, m_CurrentVideo.id, m_CurrentVideo.source); + if (m_State.canseek) + m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true)); + m_OmxPlayerState.current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; + } + + m_OmxPlayerState.video_fifo = (int)(100.0*(m_dvdPlayerVideo->GetDecoderBufferSize()-m_dvdPlayerVideo->GetDecoderFreeSpace())/m_dvdPlayerVideo->GetDecoderBufferSize()); + m_OmxPlayerState.audio_fifo = (int)(100.0*audio_fifo/m_dvdPlayerAudio->GetCacheTotal()); + + #ifdef _DEBUG + static unsigned count; + if ((count++ & 7) == 0) + { + char response[80]; + if (m_dvdPlayerVideo->GetDecoderBufferSize() && m_dvdPlayerAudio->GetCacheTotal()) + vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d", + m_OmxPlayerState.video_fifo, + (int)(100.0*video_fifo/m_dvdPlayerAudio->GetCacheTotal()), + 0, 100); + if (m_dvdPlayerAudio->GetCacheTotal()) + vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d", + m_OmxPlayerState.audio_fifo, + (int)(100.0*m_dvdPlayerAudio->GetDelay()/m_dvdPlayerAudio->GetCacheTotal()), + 0, 100); + vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d", + m_dvdPlayerVideo->GetLevel(), 0, 0, 100); + vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d", + m_dvdPlayerAudio->GetLevel(), 0, 0, 100); + } + #endif + if (audio_pts != DVD_NOPTS_VALUE) + { + audio_fifo_low = m_HasAudio && audio_fifo < threshold; + audio_fifo_high = audio_pts != DVD_NOPTS_VALUE && audio_fifo >= m_OmxPlayerState.threshold; + } + if (video_pts != DVD_NOPTS_VALUE) + { + video_fifo_low = m_HasVideo && video_fifo < threshold; + video_fifo_high = video_pts != DVD_NOPTS_VALUE && video_fifo >= m_OmxPlayerState.threshold; + } + if (!m_HasAudio && m_HasVideo) + audio_fifo_high = true; + if (!m_HasVideo && m_HasAudio) + video_fifo_high = true; + + #ifdef _DEBUG + CLog::Log(LOGDEBUG, "%s::%s M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", "CDVDPlayer", __FUNCTION__, + m_OmxPlayerState.stamp*1e-6, m_OmxPlayerState.av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6, m_OmxPlayerState.av_clock.OMXIsPaused(), m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL), + audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_OmxPlayerState.threshold, + audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, + m_dvdPlayerAudio->GetLevel(), m_dvdPlayerVideo->GetLevel(), m_dvdPlayerAudio->GetDelay(), (float)m_dvdPlayerAudio->GetCacheTotal()); + #endif + + if(!m_Pause && (m_OmxPlayerState.bOmxSentEOFs || not_accepts_data || (audio_fifo_high && video_fifo_high) || m_playSpeed != DVD_PLAYSPEED_NORMAL)) + { + if (m_OmxPlayerState.av_clock.OMXIsPaused()) + { + CLog::Log(LOGDEBUG, "%s::%s Resume %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f", "CDVDPlayer", __FUNCTION__, audio_fifo, video_fifo, + audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_OmxPlayerState.threshold); + m_OmxPlayerState.av_clock.OMXResume(); + } + } + else if ((m_Pause || audio_fifo_low || video_fifo_low) && m_playSpeed == DVD_PLAYSPEED_NORMAL) + { + if (!m_OmxPlayerState.av_clock.OMXIsPaused()) + { + if (!m_Pause) + m_OmxPlayerState.threshold = std::min(2.0f*m_OmxPlayerState.threshold, 16.0f); + CLog::Log(LOGDEBUG, "%s::%s Pause %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f", "CDVDPlayer", __FUNCTION__, audio_fifo, video_fifo, + audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_OmxPlayerState.threshold); + m_OmxPlayerState.av_clock.OMXPause(); + } + } + } +#endif +} + +bool CDVDPlayer::OMXStillPlaying() +{ + if (m_omxplayer_mode) + { + // wait for omx components to finish + if(m_OmxPlayerState.bOmxWaitVideo && !m_dvdPlayerVideo->IsEOS()) + return true; + if(m_OmxPlayerState.bOmxWaitAudio && !m_dvdPlayerAudio->IsEOS()) + return true; + } + return false; +} + void CDVDPlayer::Process() { if (!OpenInputStream()) @@ -1011,7 +1189,19 @@ void CDVDPlayer::Process() } // allow renderer to switch to fullscreen if requested - m_dvdPlayerVideo.EnableFullscreen(m_PlayerOptions.fullscreen); + m_dvdPlayerVideo->EnableFullscreen(m_PlayerOptions.fullscreen); + + if (m_omxplayer_mode) + { + if (!m_OmxPlayerState.av_clock.OMXInitialize(&m_clock)) + m_bAbortRequest = true; + if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF) + m_OmxPlayerState.av_clock.HDMIClockSync(); + m_OmxPlayerState.av_clock.OMXStateIdle(); + m_OmxPlayerState.av_clock.OMXStateExecute(); + m_OmxPlayerState.av_clock.OMXStop(); + m_OmxPlayerState.av_clock.OMXPause(); + } OpenDefaultStreams(); @@ -1099,6 +1289,9 @@ void CDVDPlayer::Process() while (!m_bAbortRequest) { + if (m_omxplayer_mode) + OMXDoProcessing(); + // handle messages send to this thread, like seek or demuxer reset requests HandleMessages(); @@ -1133,8 +1326,8 @@ void CDVDPlayer::Process() OpenDefaultStreams(); // never allow first frames after open to be skipped - if( m_dvdPlayerVideo.IsInited() ) - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); + if( m_dvdPlayerVideo->IsInited() ) + m_dvdPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); if (CachePVRStream()) SetCaching(CACHESTATE_PVR); @@ -1153,14 +1346,14 @@ void CDVDPlayer::Process() UpdateApplication(1000); // make sure we run subtitle process here - m_dvdPlayerSubtitle.Process(m_clock.GetClock() + m_State.time_offset - m_dvdPlayerVideo.GetSubtitleDelay(), m_State.time_offset); + m_dvdPlayerSubtitle->Process(m_clock.GetClock() + m_State.time_offset - m_dvdPlayerVideo->GetSubtitleDelay(), m_State.time_offset); if (CheckDelayedChannelEntry()) continue; // if the queues are full, no need to read more - if ((!m_dvdPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) || - (!m_dvdPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0)) + if ((!m_dvdPlayerAudio->AcceptsData() && m_CurrentAudio.id >= 0) || + (!m_dvdPlayerVideo->AcceptsData() && m_CurrentVideo.id >= 0)) { if(m_pDemuxer && m_DemuxerPausePending) { @@ -1173,8 +1366,8 @@ void CDVDPlayer::Process() } // always yield to players if they have data levels > 50 percent - if((m_dvdPlayerAudio.GetLevel() > 50 || m_CurrentAudio.id < 0) - && (m_dvdPlayerVideo.GetLevel() > 50 || m_CurrentVideo.id < 0)) + if((m_dvdPlayerAudio->GetLevel() > 50 || m_CurrentAudio.id < 0) + && (m_dvdPlayerVideo->GetLevel() > 50 || m_CurrentVideo.id < 0)) Sleep(0); DemuxPacket* pPacket = NULL; @@ -1232,14 +1425,24 @@ void CDVDPlayer::Process() } // make sure we tell all players to finish it's data + if (m_omxplayer_mode && !m_OmxPlayerState.bOmxSentEOFs) + { + if(m_CurrentAudio.inited) + m_OmxPlayerState.bOmxWaitAudio = true; + + if(m_CurrentVideo.inited) + m_OmxPlayerState.bOmxWaitVideo = true; + + m_OmxPlayerState.bOmxSentEOFs = true; + } if(m_CurrentAudio.inited) - m_dvdPlayerAudio.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF)); + m_dvdPlayerAudio->SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentVideo.inited) - m_dvdPlayerVideo.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF)); + m_dvdPlayerVideo->SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentSubtitle.inited) - m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); + m_dvdPlayerSubtitle->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); if(m_CurrentTeletext.inited) - m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); + m_dvdPlayerTeletext->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); m_CurrentAudio.inited = false; m_CurrentVideo.inited = false; m_CurrentSubtitle.inited = false; @@ -1249,8 +1452,9 @@ void CDVDPlayer::Process() SetCaching(CACHESTATE_DONE); // while players are still playing, keep going to allow seekbacks - if(m_dvdPlayerAudio.HasData() - || m_dvdPlayerVideo.HasData()) + if(m_dvdPlayerAudio->HasData() + || m_dvdPlayerVideo->HasData() + || OMXStillPlaying()) { Sleep(100); continue; @@ -1372,17 +1576,17 @@ void CDVDPlayer::ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket) else if (m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) && cut.action == CEdl::MUTE // Inside EDL mute && !m_EdlAutoSkipMarkers.mute) // Mute not already triggered { - m_dvdPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, true)); + m_dvdPlayerAudio->SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, true)); m_EdlAutoSkipMarkers.mute = true; } else if (!m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) // Outside of any EDL && m_EdlAutoSkipMarkers.mute) // But the mute hasn't been removed yet { - m_dvdPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, false)); + m_dvdPlayerAudio->SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, false)); m_EdlAutoSkipMarkers.mute = false; } - m_dvdPlayerAudio.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); + m_dvdPlayerAudio->SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); } void CDVDPlayer::ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket) @@ -1405,7 +1609,7 @@ void CDVDPlayer::ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket) if (CheckSceneSkip(m_CurrentVideo)) drop = true; - m_dvdPlayerVideo.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); + m_dvdPlayerVideo->SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); } void CDVDPlayer::ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket) @@ -1421,10 +1625,10 @@ void CDVDPlayer::ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket) if (CheckSceneSkip(m_CurrentSubtitle)) drop = true; - m_dvdPlayerSubtitle.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); + m_dvdPlayerSubtitle->SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL); + m_dvdPlayerSubtitle->UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL); } void CDVDPlayer::ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket) @@ -1440,7 +1644,7 @@ void CDVDPlayer::ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket if (CheckSceneSkip(m_CurrentTeletext)) drop = true; - m_dvdPlayerTeletext.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); + m_dvdPlayerTeletext->SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); } bool CDVDPlayer::GetCachingTimes(double& level, double& delay, double& offset) @@ -1510,8 +1714,8 @@ void CDVDPlayer::HandlePlaySpeed() } else { - if ((!m_dvdPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) - || (!m_dvdPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0)) + if ((!m_dvdPlayerAudio->AcceptsData() && m_CurrentAudio.id >= 0) + || (!m_dvdPlayerVideo->AcceptsData() && m_CurrentVideo.id >= 0)) caching = CACHESTATE_INIT; } } @@ -1526,8 +1730,8 @@ void CDVDPlayer::HandlePlaySpeed() // handle situation that we get no data on one stream if(m_CurrentAudio.id >= 0 && m_CurrentVideo.id >= 0) { - if ((!m_dvdPlayerAudio.AcceptsData() && !m_CurrentVideo.started) - || (!m_dvdPlayerVideo.AcceptsData() && !m_CurrentAudio.started)) + if ((!m_dvdPlayerAudio->AcceptsData() && !m_CurrentVideo.started) + || (!m_dvdPlayerVideo->AcceptsData() && !m_CurrentAudio.started)) { caching = CACHESTATE_DONE; } @@ -1538,10 +1742,10 @@ void CDVDPlayer::HandlePlaySpeed() { bool bGotAudio(m_pDemuxer->GetNrOfAudioStreams() > 0); bool bGotVideo(m_pDemuxer->GetNrOfVideoStreams() > 0); - bool bAudioLevelOk(m_dvdPlayerAudio.GetLevel() > g_advancedSettings.m_iPVRMinAudioCacheLevel); - bool bVideoLevelOk(m_dvdPlayerVideo.GetLevel() > g_advancedSettings.m_iPVRMinVideoCacheLevel); - bool bAudioFull(!m_dvdPlayerAudio.AcceptsData()); - bool bVideoFull(!m_dvdPlayerVideo.AcceptsData()); + bool bAudioLevelOk(m_dvdPlayerAudio->GetLevel() > g_advancedSettings.m_iPVRMinAudioCacheLevel); + bool bVideoLevelOk(m_dvdPlayerVideo->GetLevel() > g_advancedSettings.m_iPVRMinVideoCacheLevel); + bool bAudioFull(!m_dvdPlayerAudio->AcceptsData()); + bool bVideoFull(!m_dvdPlayerVideo->AcceptsData()); if (/* if all streams got at least g_advancedSettings.m_iPVRMinCacheLevel in their buffers, we're done */ ((bGotVideo || bGotAudio) && (!bGotAudio || bAudioLevelOk) && (!bGotVideo || bVideoLevelOk)) || @@ -1549,8 +1753,8 @@ void CDVDPlayer::HandlePlaySpeed() (bAudioFull || bVideoFull)) { CLog::Log(LOGDEBUG, "set caching from pvr to done. audio (%d) = %d. video (%d) = %d", - bGotAudio, m_dvdPlayerAudio.GetLevel(), - bGotVideo, m_dvdPlayerVideo.GetLevel()); + bGotAudio, m_dvdPlayerAudio->GetLevel(), + bGotVideo, m_dvdPlayerVideo->GetLevel()); caching = CACHESTATE_DONE; } @@ -1558,17 +1762,17 @@ void CDVDPlayer::HandlePlaySpeed() { /* ensure that automatically started players are stopped while caching */ if (m_CurrentAudio.started) - m_dvdPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE); + m_dvdPlayerAudio->SetSpeed(DVD_PLAYSPEED_PAUSE); if (m_CurrentVideo.started) - m_dvdPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE); + m_dvdPlayerVideo->SetSpeed(DVD_PLAYSPEED_PAUSE); } } if(caching == CACHESTATE_PLAY) { // if all enabled streams have started playing we are done - if((m_CurrentVideo.id < 0 || !m_dvdPlayerVideo.IsStalled()) - && (m_CurrentAudio.id < 0 || !m_dvdPlayerAudio.IsStalled())) + if((m_CurrentVideo.id < 0 || !m_dvdPlayerVideo->IsStalled()) + && (m_CurrentAudio.id < 0 || !m_dvdPlayerAudio->IsStalled())) caching = CACHESTATE_DONE; } @@ -1586,10 +1790,10 @@ void CDVDPlayer::HandlePlaySpeed() } else if (m_CurrentVideo.id >= 0 && m_CurrentVideo.inited == true - && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() + && m_SpeedState.lastpts != m_dvdPlayerVideo->GetCurrentPts() && m_SpeedState.lasttime != GetTime()) { - m_SpeedState.lastpts = m_dvdPlayerVideo.GetCurrentPts(); + m_SpeedState.lastpts = m_dvdPlayerVideo->GetCurrentPts(); m_SpeedState.lasttime = (double) GetTime(); // check how much off clock video is when ff/rw:ing // a problem here is that seeking isn't very accurate @@ -1624,13 +1828,13 @@ bool CDVDPlayer::CheckStartCaching(CCurrentStream& current) if(IsInMenu()) return false; - if((current.type == STREAM_AUDIO && m_dvdPlayerAudio.IsStalled()) - || (current.type == STREAM_VIDEO && m_dvdPlayerVideo.IsStalled())) + if((current.type == STREAM_AUDIO && m_dvdPlayerAudio->IsStalled()) + || (current.type == STREAM_VIDEO && m_dvdPlayerVideo->IsStalled())) { if (CachePVRStream()) { - if ((current.type == STREAM_AUDIO && current.started && m_dvdPlayerAudio.GetLevel() == 0) || - (current.type == STREAM_VIDEO && current.started && m_dvdPlayerVideo.GetLevel() == 0)) + if ((current.type == STREAM_AUDIO && current.started && m_dvdPlayerAudio->GetLevel() == 0) || + (current.type == STREAM_VIDEO && current.started && m_dvdPlayerVideo->GetLevel() == 0)) { CLog::Log(LOGDEBUG, "%s stream stalled. start buffering", current.type == STREAM_AUDIO ? "audio" : "video"); SetCaching(CACHESTATE_PVR); @@ -1639,8 +1843,8 @@ bool CDVDPlayer::CheckStartCaching(CCurrentStream& current) } // don't start caching if it's only a single stream that has run dry - if(m_dvdPlayerAudio.GetLevel() > 50 - || m_dvdPlayerVideo.GetLevel() > 50) + if(m_dvdPlayerAudio->GetLevel() > 50 + || m_dvdPlayerVideo->GetLevel() > 50) return false; if(current.inited) @@ -1879,7 +2083,7 @@ void CDVDPlayer::CheckAutoSceneSkip() || m_CurrentVideo.dts == DVD_NOPTS_VALUE) return; - const int64_t clock = DVD_TIME_TO_MSEC(min(m_CurrentAudio.dts, m_CurrentVideo.dts) + m_offset_pts); + const int64_t clock = m_omxplayer_mode ? GetTime() : DVD_TIME_TO_MSEC(min(m_CurrentAudio.dts, m_CurrentVideo.dts) + m_offset_pts); CEdl::Cut cut; if(!m_Edl.InCut(clock, &cut)) @@ -1949,15 +2153,15 @@ void CDVDPlayer::SynchronizePlayers(unsigned int sources) CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, sources); if (m_CurrentAudio.id >= 0) - m_dvdPlayerAudio.SendMessage(message->Acquire()); + m_dvdPlayerAudio->SendMessage(message->Acquire()); if (m_CurrentVideo.id >= 0) - m_dvdPlayerVideo.SendMessage(message->Acquire()); + m_dvdPlayerVideo->SendMessage(message->Acquire()); /* TODO - we have to rewrite the sync class, to not require all other players waiting for subtitle, should only be the oposite way if (m_CurrentSubtitle.id >= 0) - m_dvdPlayerSubtitle.SendMessage(message->Acquire()); + m_dvdPlayerSubtitle->SendMessage(message->Acquire()); */ message->Release(); } @@ -1965,13 +2169,13 @@ void CDVDPlayer::SynchronizePlayers(unsigned int sources) IDVDStreamPlayer* CDVDPlayer::GetStreamPlayer(unsigned int target) { if(target == DVDPLAYER_AUDIO) - return &m_dvdPlayerAudio; + return m_dvdPlayerAudio; if(target == DVDPLAYER_VIDEO) - return &m_dvdPlayerVideo; + return m_dvdPlayerVideo; if(target == DVDPLAYER_SUBTITLE) - return &m_dvdPlayerSubtitle; + return m_dvdPlayerSubtitle; if(target == DVDPLAYER_TELETEXT) - return &m_dvdPlayerTeletext; + return m_dvdPlayerTeletext; return NULL; } @@ -2006,6 +2210,13 @@ void CDVDPlayer::OnExit() m_messenger.End(); + if (m_omxplayer_mode) + { + m_OmxPlayerState.av_clock.OMXStop(); + m_OmxPlayerState.av_clock.OMXStateIdle(); + m_OmxPlayerState.av_clock.OMXDeinitialize(); + } + m_bStop = true; // if we didn't stop playing, advance to the next item in xbmc's playlist if(m_PlayerOptions.identify == false) @@ -2228,8 +2439,8 @@ void CDVDPlayer::HandleMessages() m_playSpeed = speed; m_caching = CACHESTATE_DONE; m_clock.SetSpeed(speed); - m_dvdPlayerAudio.SetSpeed(speed); - m_dvdPlayerVideo.SetSpeed(speed); + m_dvdPlayerAudio->SetSpeed(speed); + m_dvdPlayerVideo->SetSpeed(speed); // We can't pause demuxer until our buffers are full. Doing so will result in continued // calls to Read() which may then block indefinitely (CDVDInputStreamRTMP for example). @@ -2239,6 +2450,23 @@ void CDVDPlayer::HandleMessages() if (!m_DemuxerPausePending) m_pDemuxer->SetSpeed(speed); } + + if (m_omxplayer_mode) + { + int old_speed = m_playSpeed; + // when switching from trickplay to normal, we may not have a full set of reference frames + // in decoder and we may get corrupt frames out. Seeking to current time will avoid this. + if ( (speed != DVD_PLAYSPEED_PAUSE && speed != DVD_PLAYSPEED_NORMAL) || + (old_speed != DVD_PLAYSPEED_PAUSE && old_speed != DVD_PLAYSPEED_NORMAL) ) + { + m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), (speed < 0), true, true, false, true)); + } + else + m_OmxPlayerState.av_clock.OMXPause(); + + m_OmxPlayerState.av_clock.OMXSetSpeed(speed); + CLog::Log(LOGDEBUG, "%s::%s CDVDMsg::PLAYER_SETSPEED speed : %d (%d)", "CDVDPlayer", __FUNCTION__, speed, old_speed); + } } else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) == 0) { @@ -2327,6 +2555,18 @@ void CDVDPlayer::HandleMessages() if(player == DVDPLAYER_VIDEO) m_CurrentVideo.started = true; CLog::Log(LOGDEBUG, "CDVDPlayer::HandleMessages - player started %d", player); + + if (m_omxplayer_mode) + { + if ((player == DVDPLAYER_AUDIO || player == DVDPLAYER_VIDEO) && + ((m_playSpeed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_NORMAL) || !m_HasAudio || m_CurrentAudio.started) && + (!m_HasVideo || m_CurrentVideo.started)) + { + CLog::Log(LOGDEBUG, "%s::%s player started RESET", "CDVDPlayer", __FUNCTION__); + m_OmxPlayerState.av_clock.OMXReset(m_HasVideo, m_playSpeed != DVD_PLAYSPEED_NORMAL && m_playSpeed != DVD_PLAYSPEED_PAUSE ? false:m_HasAudio); + } + CLog::Log(LOGDEBUG, "%s::%s player started %d (s:%d a:%d v:%d)", "CDVDPlayer", __FUNCTION__, player, m_playSpeed, m_CurrentAudio.started, m_CurrentVideo.started); + } } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { @@ -2335,7 +2575,7 @@ void CDVDPlayer::HandleMessages() CSingleLock lock(m_StateSection); /* prioritize data from video player, but only accept data * * after it has been started to avoid race conditions after seeks */ - if(m_CurrentVideo.started) + if(m_CurrentVideo.started && !m_dvdPlayerVideo->SubmittedEOS()) { if(state.player == DVDPLAYER_VIDEO) m_State = state; @@ -2372,10 +2612,14 @@ void CDVDPlayer::SetCaching(ECacheState state) || state == CACHESTATE_PVR) { m_clock.SetSpeed(DVD_PLAYSPEED_PAUSE); - m_dvdPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE); - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); - m_dvdPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE); - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); + + if (m_omxplayer_mode) + m_OmxPlayerState.av_clock.OMXPause(); + + m_dvdPlayerAudio->SetSpeed(DVD_PLAYSPEED_PAUSE); + m_dvdPlayerAudio->SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); + m_dvdPlayerVideo->SetSpeed(DVD_PLAYSPEED_PAUSE); + m_dvdPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); if (state == CACHESTATE_PVR) m_pInputStream->ResetScanTimeout((unsigned int) CSettings::Get().GetInt("pvrplayback.scantime") * 1000); @@ -2385,8 +2629,8 @@ void CDVDPlayer::SetCaching(ECacheState state) ||(state == CACHESTATE_DONE && m_caching != CACHESTATE_PLAY)) { m_clock.SetSpeed(m_playSpeed); - m_dvdPlayerAudio.SetSpeed(m_playSpeed); - m_dvdPlayerVideo.SetSpeed(m_playSpeed); + m_dvdPlayerAudio->SetSpeed(m_playSpeed); + m_dvdPlayerVideo->SetSpeed(m_playSpeed); m_pInputStream->ResetScanTimeout(0); } m_caching = state; @@ -2399,8 +2643,8 @@ void CDVDPlayer::SetPlaySpeed(int speed) else m_playSpeed = speed; - m_dvdPlayerAudio.SetSpeed(speed); - m_dvdPlayerVideo.SetSpeed(speed); + m_dvdPlayerAudio->SetSpeed(speed); + m_dvdPlayerVideo->SetSpeed(speed); SynchronizeDemuxer(100); } @@ -2453,7 +2697,7 @@ bool CDVDPlayer::HasAudio() const bool CDVDPlayer::IsPassthrough() const { - return m_dvdPlayerAudio.IsPassthrough(); + return m_dvdPlayerAudio->IsPassthrough(); } bool CDVDPlayer::CanSeek() @@ -2466,7 +2710,7 @@ void CDVDPlayer::Seek(bool bPlus, bool bLargeStep, bool bChapterOverride) { if( m_playSpeed == DVD_PLAYSPEED_PAUSE && bPlus && !bLargeStep) { - if (m_dvdPlayerVideo.StepFrame()) + if (m_dvdPlayerVideo->StepFrame()) return; } if (!m_State.canseek) @@ -2601,7 +2845,7 @@ void CDVDPlayer::GetAudioInfo(std::string& strAudioInfo) { CSingleLock lock(m_StateSection); strAudioInfo = StringUtils::Format("D(%s)", m_StateInput.demux_audio.c_str()); } - strAudioInfo += StringUtils::Format("\nP(%s)", m_dvdPlayerAudio.GetPlayerInfo().c_str()); + strAudioInfo += StringUtils::Format("\nP(%s)", m_dvdPlayerAudio->GetPlayerInfo().c_str()); } void CDVDPlayer::GetVideoInfo(std::string& strVideoInfo) @@ -2609,44 +2853,83 @@ void CDVDPlayer::GetVideoInfo(std::string& strVideoInfo) { CSingleLock lock(m_StateSection); strVideoInfo = StringUtils::Format("D(%s)", m_StateInput.demux_video.c_str()); } - strVideoInfo += StringUtils::Format("\nP(%s)", m_dvdPlayerVideo.GetPlayerInfo().c_str()); + strVideoInfo += StringUtils::Format("\nP(%s)", m_dvdPlayerVideo->GetPlayerInfo().c_str()); } void CDVDPlayer::GetGeneralInfo(std::string& strGeneralInfo) { if (!m_bStop) { - double dDelay = m_dvdPlayerVideo.GetDelay() / DVD_TIME_BASE - g_renderManager.GetDisplayLatency(); + if (m_omxplayer_mode) + { + double dDelay = m_dvdPlayerAudio->GetDelay(); - double apts = m_dvdPlayerAudio.GetCurrentPts(); - double vpts = m_dvdPlayerVideo.GetCurrentPts(); - double dDiff = 0; + double apts = m_dvdPlayerAudio->GetCurrentPts(); + double vpts = m_dvdPlayerVideo->GetCurrentPts(); + double dDiff = 0; - if( apts != DVD_NOPTS_VALUE && vpts != DVD_NOPTS_VALUE ) - dDiff = (apts - vpts) / DVD_TIME_BASE; + if( apts != DVD_NOPTS_VALUE && vpts != DVD_NOPTS_VALUE ) + dDiff = (apts - vpts) / DVD_TIME_BASE; - std::string strEDL = StringUtils::Format(", edl:%s", m_Edl.GetInfo().c_str()); + CStdString strEDL; + strEDL += StringUtils::Format(", edl:%s", m_Edl.GetInfo().c_str()); - std::string strBuf; - CSingleLock lock(m_StateSection); - if(m_StateInput.cache_bytes >= 0) - { - strBuf += StringUtils::Format(" cache:%s %2.0f%%" - , StringUtils::SizeToString(m_State.cache_bytes).c_str() - , m_State.cache_level * 100); - if(m_playSpeed == 0 || m_caching == CACHESTATE_FULL) - strBuf += StringUtils::Format(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay)); + CStdString strBuf; + CSingleLock lock(m_StateSection); + if(m_StateInput.cache_bytes >= 0) + { + strBuf += StringUtils::Format(" cache:%s %2.0f%%" + , StringUtils::SizeToString(m_State.cache_bytes).c_str() + , m_State.cache_level * 100); + if(m_playSpeed == 0 || m_caching == CACHESTATE_FULL) + strBuf += StringUtils::Format(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay)); + } + + strGeneralInfo = StringUtils::Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s af:%d%% vf:%d%% amp:% 5.2f )" + , dDelay + , dDiff + , strEDL.c_str() + , (int)(CThread::GetRelativeUsage()*100) + , (int)(m_dvdPlayerAudio->GetRelativeUsage()*100) + , (int)(m_dvdPlayerVideo->GetRelativeUsage()*100) + , strBuf.c_str() + , m_OmxPlayerState.audio_fifo + , m_OmxPlayerState.video_fifo + , m_dvdPlayerAudio->GetDynamicRangeAmplification()); } + else + { + double dDelay = m_dvdPlayerVideo->GetDelay() / DVD_TIME_BASE - g_renderManager.GetDisplayLatency(); - strGeneralInfo = StringUtils::Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s )" - , dDelay - , dDiff - , strEDL.c_str() - , (int)(CThread::GetRelativeUsage()*100) - , (int)(m_dvdPlayerAudio.GetRelativeUsage()*100) - , (int)(m_dvdPlayerVideo.GetRelativeUsage()*100) - , strBuf.c_str()); + double apts = m_dvdPlayerAudio->GetCurrentPts(); + double vpts = m_dvdPlayerVideo->GetCurrentPts(); + double dDiff = 0; + if( apts != DVD_NOPTS_VALUE && vpts != DVD_NOPTS_VALUE ) + dDiff = (apts - vpts) / DVD_TIME_BASE; + + std::string strEDL = StringUtils::Format(", edl:%s", m_Edl.GetInfo().c_str()); + + std::string strBuf; + CSingleLock lock(m_StateSection); + if(m_StateInput.cache_bytes >= 0) + { + strBuf += StringUtils::Format(" cache:%s %2.0f%%" + , StringUtils::SizeToString(m_State.cache_bytes).c_str() + , m_State.cache_level * 100); + if(m_playSpeed == 0 || m_caching == CACHESTATE_FULL) + strBuf += StringUtils::Format(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay)); + } + + strGeneralInfo = StringUtils::Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s )" + , dDelay + , dDiff + , strEDL.c_str() + , (int)(CThread::GetRelativeUsage()*100) + , (int)(m_dvdPlayerAudio->GetRelativeUsage()*100) + , (int)(m_dvdPlayerVideo->GetRelativeUsage()*100) + , strBuf.c_str()); + } } } @@ -2678,22 +2961,22 @@ float CDVDPlayer::GetCachePercentage() void CDVDPlayer::SetAVDelay(float fValue) { - m_dvdPlayerVideo.SetDelay( (fValue * DVD_TIME_BASE) ) ; + m_dvdPlayerVideo->SetDelay( (fValue * DVD_TIME_BASE) ) ; } float CDVDPlayer::GetAVDelay() { - return (float) m_dvdPlayerVideo.GetDelay() / (float)DVD_TIME_BASE; + return (float) m_dvdPlayerVideo->GetDelay() / (float)DVD_TIME_BASE; } void CDVDPlayer::SetSubTitleDelay(float fValue) { - m_dvdPlayerVideo.SetSubtitleDelay(-fValue * DVD_TIME_BASE); + m_dvdPlayerVideo->SetSubtitleDelay(-fValue * DVD_TIME_BASE); } float CDVDPlayer::GetSubTitleDelay() { - return (float) -m_dvdPlayerVideo.GetSubtitleDelay() / DVD_TIME_BASE; + return (float) -m_dvdPlayerVideo->GetSubtitleDelay() / DVD_TIME_BASE; } // priority: 1: libdvdnav, 2: external subtitles, 3: muxed subtitles @@ -2735,7 +3018,7 @@ bool CDVDPlayer::GetSubtitleVisible() return pStream->IsSubtitleStreamEnabled(); } - return m_dvdPlayerVideo.IsSubtitleEnabled(); + return m_dvdPlayerVideo->IsSubtitleEnabled(); } void CDVDPlayer::SetSubtitleVisible(bool bVisible) @@ -2745,7 +3028,7 @@ void CDVDPlayer::SetSubtitleVisible(bool bVisible) void CDVDPlayer::SetSubtitleVisibleInternal(bool bVisible) { - m_dvdPlayerVideo.EnableSubtitle(bVisible); + m_dvdPlayerVideo->EnableSubtitle(bVisible); if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->EnableSubtitleStream(bVisible); @@ -2772,7 +3055,7 @@ TextCacheStruct_t* CDVDPlayer::GetTeletextCache() if (m_CurrentTeletext.id < 0) return 0; - return m_dvdPlayerTeletext.GetTeletextCache(); + return m_dvdPlayerTeletext->GetTeletextCache(); } void CDVDPlayer::LoadPage(int p, int sp, unsigned char* buffer) @@ -2780,7 +3063,7 @@ void CDVDPlayer::LoadPage(int p, int sp, unsigned char* buffer) if (m_CurrentTeletext.id < 0) return; - return m_dvdPlayerTeletext.LoadPage(p, sp, buffer); + return m_dvdPlayerTeletext->LoadPage(p, sp, buffer); } void CDVDPlayer::SeekTime(int64_t iTime) @@ -2851,7 +3134,7 @@ bool CDVDPlayer::OpenStream(CCurrentStream& current, int iStream, int source, bo m_pSubtitleDemuxer = demux.release(); } - double pts = m_dvdPlayerVideo.GetCurrentPts(); + double pts = m_dvdPlayerVideo->GetCurrentPts(); if(pts == DVD_NOPTS_VALUE) pts = m_CurrentVideo.dts; if(pts == DVD_NOPTS_VALUE) @@ -2964,10 +3247,10 @@ bool CDVDPlayer::OpenAudioStream(CDVDStreamInfo& hint, bool reset) m_HasAudio = true; /* we are potentially going to be waiting on this */ - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); + m_dvdPlayerAudio->SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); /* audio normally won't consume full cpu, so let it have prio */ - m_dvdPlayerAudio.SetPriority(GetPriority()+1); + m_dvdPlayerAudio->SetPriority(GetPriority()+1); return true; } @@ -3001,7 +3284,7 @@ bool CDVDPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) m_HasVideo = true; /* we are potentially going to be waiting on this */ - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); + m_dvdPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); #if defined(TARGET_DARWIN) // Apple thread scheduler works a little different than Linux. It @@ -3011,11 +3294,11 @@ bool CDVDPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) // the CoreAudio audio device handler thread. We do the same for // the DVDPlayerVideo thread so it can run to sleep without getting // swapped out by a busy OS. - m_dvdPlayerVideo.SetPriority(GetSchedRRPriority()); + m_dvdPlayerVideo->SetPriority(GetSchedRRPriority()); #else /* use same priority for video thread as demuxing thread, as */ /* otherwise demuxer will starve if video consumes the full cpu */ - m_dvdPlayerVideo.SetPriority(GetPriority()); + m_dvdPlayerVideo->SetPriority(GetPriority()); #endif return true; @@ -3060,7 +3343,7 @@ bool CDVDPlayer::AdaptForcedSubtitles() bool CDVDPlayer::OpenTeletextStream(CDVDStreamInfo& hint) { - if (!m_dvdPlayerTeletext.CheckStream(hint)) + if (!m_dvdPlayerTeletext->CheckStream(hint)) return false; if(!OpenStreamPlayer(m_CurrentTeletext, hint, true)) @@ -3144,19 +3427,19 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) if(queued) { - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); - m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); + m_dvdPlayerAudio->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); + m_dvdPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); + m_dvdPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); + m_dvdPlayerSubtitle->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); + m_dvdPlayerTeletext->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); SynchronizePlayers(SYNCSOURCE_ALL); } else { - m_dvdPlayerAudio.Flush(); - m_dvdPlayerVideo.Flush(); - m_dvdPlayerSubtitle.Flush(); - m_dvdPlayerTeletext.Flush(); + m_dvdPlayerAudio->Flush(); + m_dvdPlayerVideo->Flush(); + m_dvdPlayerSubtitle->Flush(); + m_dvdPlayerTeletext->Flush(); // clear subtitle and menu overlays m_overlayContainer.Clear(); @@ -3166,8 +3449,8 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) { // make sure players are properly flushed, should put them in stalled state CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(1000, 0); - m_dvdPlayerAudio.SendMessage(msg->Acquire(), 1); - m_dvdPlayerVideo.SendMessage(msg->Acquire(), 1); + m_dvdPlayerAudio->SendMessage(msg->Acquire(), 1); + m_dvdPlayerVideo->SendMessage(msg->Acquire(), 1); msg->Wait(&m_bStop, 0); msg->Release(); @@ -3191,6 +3474,15 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) CSingleLock lock(m_StateSection); m_State = m_StateInput; } + + if (m_omxplayer_mode) + { + m_OmxPlayerState.av_clock.OMXFlush(); + if (!queued) + m_OmxPlayerState.av_clock.OMXStop(); + m_OmxPlayerState.av_clock.OMXPause(); + m_OmxPlayerState.av_clock.OMXMediaTime(0.0); + } } // since we call ffmpeg functions to decode, this is being called in the same thread as ::Process() is @@ -3207,7 +3499,7 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) else if(iMessage == 3) m_dvd.iSelectedSPUStream = *(int*)pData; else if(iMessage == 4) - m_dvdPlayerVideo.EnableSubtitle(*(int*)pData ? true: false); + m_dvdPlayerVideo->EnableSubtitle(*(int*)pData ? true: false); else if(iMessage == 5) { if (m_dvd.state != DVDSTATE_STILL) @@ -3221,7 +3513,7 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) unsigned int time = 0; if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 ) { - time = (unsigned int)(m_dvdPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 )); + time = (unsigned int)(m_dvdPlayerVideo->GetOutputDelay() / ( DVD_TIME_BASE / 1000 )); if( time < 10000 && time > 0 ) m_dvd.iDVDStillTime += time; } @@ -3270,7 +3562,7 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) unsigned int time = 0; if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 ) { - time = (unsigned int)(m_dvdPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 )); + time = (unsigned int)(m_dvdPlayerVideo->GetOutputDelay() / ( DVD_TIME_BASE / 1000 )); if( time < 10000 && time > 0 ) m_dvd.iDVDStillTime += time; } @@ -3284,7 +3576,7 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) break; case DVDNAV_SPU_CLUT_CHANGE: { - m_dvdPlayerSubtitle.SendMessage(new CDVDMsgSubtitleClutChange((uint8_t*)pData)); + m_dvdPlayerSubtitle->SendMessage(new CDVDMsgSubtitleClutChange((uint8_t*)pData)); } break; case DVDNAV_SPU_STREAM_CHANGE: @@ -3324,7 +3616,7 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) //dvdnav_highlight_event_t* pInfo = (dvdnav_highlight_event_t*)pData; int iButton = pStream->GetCurrentButton(); CLog::Log(LOGDEBUG, "DVDNAV_HIGHLIGHT: Highlight button %d\n", iButton); - m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL); + m_dvdPlayerSubtitle->UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL); } break; case DVDNAV_VTS_CHANGE: @@ -3337,8 +3629,8 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) //Force an aspect ratio that is set in the dvdheaders if available m_CurrentVideo.hint.aspect = pStream->GetVideoAspectRatio(); - if( m_dvdPlayerVideo.IsInited() ) - m_dvdPlayerVideo.SendMessage(new CDVDMsgDouble(CDVDMsg::VIDEO_SET_ASPECT, m_CurrentVideo.hint.aspect)); + if( m_dvdPlayerVideo->IsInited() ) + m_dvdPlayerVideo->SendMessage(new CDVDMsgDouble(CDVDMsg::VIDEO_SET_ASPECT, m_CurrentVideo.hint.aspect)); m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV); m_SelectionStreams.Update(m_pInputStream, m_pDemuxer); @@ -3353,8 +3645,8 @@ int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) m_dvd.state = DVDSTATE_NORMAL; - if( m_dvdPlayerVideo.IsInited() ) - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); + if( m_dvdPlayerVideo->IsInited() ) + m_dvdPlayerVideo->SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); } break; case DVDNAV_NAV_PACKET: @@ -3543,7 +3835,7 @@ bool CDVDPlayer::OnAction(const CAction &action) case ACTION_MOUSE_LEFT_CLICK: { CRect rs, rd; - m_dvdPlayerVideo.GetVideoRect(rs, rd); + m_dvdPlayerVideo->GetVideoRect(rs, rd); CPoint pt(action.GetAmount(), action.GetAmount(1)); if (!rd.PtInRect(pt)) return false; // out of bounds @@ -3572,7 +3864,7 @@ bool CDVDPlayer::OnAction(const CAction &action) CLog::Log(LOGDEBUG, " - button select"); // show button pushed overlay if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_CLICKED); + m_dvdPlayerSubtitle->UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_CLICKED); pMenus->ActivateButton(); } @@ -3746,14 +4038,14 @@ int CDVDPlayer::GetCacheLevel() const double CDVDPlayer::GetQueueTime() { - int a = m_dvdPlayerAudio.GetLevel(); - int v = m_dvdPlayerVideo.GetLevel(); + int a = m_dvdPlayerAudio->GetLevel(); + int v = m_dvdPlayerVideo->GetLevel(); return max(a, v) * 8000.0 / 100; } void CDVDPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info) { - info.bitrate = m_dvdPlayerVideo.GetVideoBitrate(); + info.bitrate = m_dvdPlayerVideo->GetVideoBitrate(); std::string retVal; if (m_pDemuxer && (m_CurrentVideo.id != -1)) @@ -3767,9 +4059,9 @@ void CDVDPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info) } } info.videoCodecName = retVal; - info.videoAspectRatio = m_dvdPlayerVideo.GetAspectRatio(); - m_dvdPlayerVideo.GetVideoRect(info.SrcRect, info.DestRect); - info.stereoMode = m_dvdPlayerVideo.GetStereoMode(); + info.videoAspectRatio = m_dvdPlayerVideo->GetAspectRatio(); + m_dvdPlayerVideo->GetVideoRect(info.SrcRect, info.DestRect); + info.stereoMode = m_dvdPlayerVideo->GetStereoMode(); if (info.stereoMode == "mono") info.stereoMode = ""; } @@ -3789,8 +4081,8 @@ void CDVDPlayer::GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info) if (index == GetAudioStream()) { - info.bitrate = m_dvdPlayerAudio.GetAudioBitrate(); - info.channels = m_dvdPlayerAudio.GetAudioChannels(); + info.bitrate = m_dvdPlayerAudio->GetAudioBitrate(); + info.channels = m_dvdPlayerAudio->GetAudioChannels(); } else if (m_pDemuxer) { @@ -4083,7 +4375,7 @@ bool CDVDPlayer::GetStreamDetails(CStreamDetails &details) * and UpdatePlayState() has been called at least once. In this case dvdplayer duration/AR will * return 0 and we'll have to fallback to the (less accurate) info from the demuxer. */ - float aspect = m_dvdPlayerVideo.GetAspectRatio(); + float aspect = m_dvdPlayerVideo->GetAspectRatio(); if (aspect > 0.0f) ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_fAspect = aspect; @@ -4100,7 +4392,7 @@ bool CDVDPlayer::GetStreamDetails(CStreamDetails &details) std::string CDVDPlayer::GetPlayingTitle() { /* Currently we support only Title Name from Teletext line 30 */ - TextCacheStruct_t* ttcache = m_dvdPlayerTeletext.GetTeletextCache(); + TextCacheStruct_t* ttcache = m_dvdPlayerTeletext->GetTeletextCache(); if (ttcache && !ttcache->line30.empty()) return ttcache->line30; @@ -4131,3 +4423,32 @@ bool CDVDPlayer::CachePVRStream(void) const !g_PVRManager.IsPlayingRecording() && g_advancedSettings.m_bPVRCacheInDvdPlayer; } + +void CDVDPlayer::OMXGetRenderFeatures(std::vector<int> &renderFeatures) +{ + if (m_omxplayer_mode) + { + renderFeatures.push_back(RENDERFEATURE_STRETCH); + renderFeatures.push_back(RENDERFEATURE_CROP); + renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO); + renderFeatures.push_back(RENDERFEATURE_ZOOM); + } +} + +void CDVDPlayer::OMXGetDeinterlaceMethods(std::vector<int> &deinterlaceMethods) +{ + if (m_omxplayer_mode) + { + deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE); + } +} + +void CDVDPlayer::OMXGetDeinterlaceModes(std::vector<int> &deinterlaceModes) +{ + if (m_omxplayer_mode) + { + deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO); + deinterlaceModes.push_back(VS_DEINTERLACEMODE_OFF); + deinterlaceModes.push_back(VS_DEINTERLACEMODE_FORCE); + } +} diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h index b811003e05..951382c2f7 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.h +++ b/xbmc/cores/dvdplayer/DVDPlayer.h @@ -42,6 +42,34 @@ #include "utils/StreamDetails.h" #include "threads/SystemClock.h" +#ifdef HAS_OMXPLAYER +#include "OMXCore.h" +#include "OMXClock.h" +#include "linux/RBP.h" +#else + +// dummy class to avoid ifdefs where calls are made +class OMXClock +{ +public: + bool OMXInitialize(CDVDClock *clock) { return false; } + void OMXDeinitialize() {} + bool OMXIsPaused() { return false; } + bool OMXStop(bool lock = true) { return false; } + bool OMXStep(int steps = 1, bool lock = true) { return false; } + bool OMXReset(bool has_video, bool has_audio, bool lock = true) { return false; } + double OMXMediaTime(bool lock = true) { return 0.0; } + double OMXClockAdjustment(bool lock = true) { return 0.0; } + bool OMXMediaTime(double pts, bool lock = true) { return false; } + bool OMXPause(bool lock = true) { return false; } + bool OMXResume(bool lock = true) { return false; } + bool OMXSetSpeed(int speed, bool lock = true, bool pause_resume = false) { return false; } + bool OMXFlush(bool lock = true) { return false; } + bool OMXStateExecute(bool lock = true) { return false; } + void OMXStateIdle(bool lock = true) {} + bool HDMIClockSync(bool lock = true) { return false; } +}; +#endif class CDVDInputStream; @@ -189,11 +217,9 @@ public: virtual float GetPercentage(); virtual float GetCachePercentage(); - virtual void RegisterAudioCallback(IAudioCallback* pCallback) { m_dvdPlayerAudio.RegisterAudioCallback(pCallback); } - virtual void UnRegisterAudioCallback() { m_dvdPlayerAudio.UnRegisterAudioCallback(); } - virtual void SetVolume(float nVolume) { m_dvdPlayerAudio.SetVolume(nVolume); } - virtual void SetMute(bool bOnOff) { m_dvdPlayerAudio.SetMute(bOnOff); } - virtual void SetDynamicRangeCompression(long drc) { m_dvdPlayerAudio.SetDynamicRangeCompression(drc); } + virtual void SetVolume(float nVolume) { m_dvdPlayerAudio->SetVolume(nVolume); } + virtual void SetMute(bool bOnOff) { m_dvdPlayerAudio->SetMute(bOnOff); } + virtual void SetDynamicRangeCompression(long drc) { m_dvdPlayerAudio->SetDynamicRangeCompression(drc); } virtual void GetAudioInfo(std::string& strAudioInfo); virtual void GetVideoInfo(std::string& strVideoInfo); virtual void GetGeneralInfo(std::string& strVideoInfo); @@ -259,6 +285,15 @@ public: virtual int GetCacheLevel() const ; virtual int OnDVDNavResult(void* pData, int iMessage); + + // Note: the following "OMX" methods are deprecated and will be removed in the future + // They should be handled by the video renderer, not the player + virtual void OMXGetRenderFeatures(std::vector<int> &renderFeatures); + virtual void OMXGetDeinterlaceMethods(std::vector<int> &deinterlaceMethods); + virtual void OMXGetDeinterlaceModes(std::vector<int> &deinterlaceModes); + + virtual bool ControlsVolume() {return m_omxplayer_mode;} + protected: friend class CSelectionStreams; @@ -266,6 +301,11 @@ protected: virtual void OnExit(); virtual void Process(); + void CreatePlayers(); + void DestroyPlayers(); + void OMXDoProcessing(); + bool OMXStillPlaying(); + bool OpenStream(CCurrentStream& current, int iStream, int source, bool reset = true); bool OpenStreamPlayer(CCurrentStream& current, CDVDStreamInfo& hint, bool reset); bool OpenAudioStream(CDVDStreamInfo& hint, bool reset = true); @@ -339,6 +379,7 @@ protected: void UpdateClockMaster(); double m_UpdateApplication; + bool m_players_created; bool m_bAbortRequest; std::string m_filename; // holds the actual filename @@ -367,10 +408,10 @@ protected: CDVDMessageQueue m_messenger; // thread messenger - CDVDPlayerVideo m_dvdPlayerVideo; // video part - CDVDPlayerAudio m_dvdPlayerAudio; // audio part - CDVDPlayerSubtitle m_dvdPlayerSubtitle; // subtitle part - CDVDTeletextData m_dvdPlayerTeletext; // teletext part + IDVDStreamPlayerVideo *m_dvdPlayerVideo; // video part + IDVDStreamPlayerAudio *m_dvdPlayerAudio; // audio part + CDVDPlayerSubtitle *m_dvdPlayerSubtitle; // subtitle part + CDVDTeletextData *m_dvdPlayerTeletext; // teletext part CDVDClock m_clock; // master clock CDVDOverlayContainer m_overlayContainer; @@ -406,6 +447,10 @@ protected: friend class CDVDPlayerVideo; friend class CDVDPlayerAudio; +#ifdef HAS_OMXPLAYER + friend class OMXPlayerVideo; + friend class OMXPlayerAudio; +#endif struct SPlayerState { @@ -496,4 +541,20 @@ protected: bool m_HasAudio; bool m_DemuxerPausePending; + + // omxplayer variables + struct SOmxPlayerState + { + OMXClock av_clock; // openmax clock component + EDEINTERLACEMODE current_deinterlace; // whether deinterlace is currently enabled + bool bOmxWaitVideo; // whether we need to wait for video to play out on EOS + bool bOmxWaitAudio; // whether we need to wait for audio to play out on EOS + bool bOmxSentEOFs; // flag if we've send EOFs to audio/video players + float threshold; // current fifo threshold required to come out of buffering + int video_fifo; // video fifo to gpu level + int audio_fifo; // audio fifo to gpu level + double last_check_time; // we periodically check for gpu underrun + double stamp; // last media timestamp + } m_OmxPlayerState; + bool m_omxplayer_mode; // using omxplayer acceleration }; diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.h b/xbmc/cores/dvdplayer/DVDPlayerAudio.h index 3761912a5d..e8b2ab6086 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerAudio.h +++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.h @@ -36,7 +36,6 @@ class CDVDPlayer; class CDVDAudioCodec; -class IAudioCallback; class CDVDAudioCodec; #define DECODE_FLAG_DROP 1 @@ -102,7 +101,7 @@ public: XbmcThreads::EndTime m_timer; }; -class CDVDPlayerAudio : public CThread, public IDVDStreamPlayer +class CDVDPlayerAudio : public CThread, public IDVDStreamPlayerAudio { public: CDVDPlayerAudio(CDVDClock* pClock, CDVDMessageQueue& parent); @@ -111,9 +110,6 @@ public: bool OpenStream(CDVDStreamInfo &hints); void CloseStream(bool bWaitForBuffers); - void RegisterAudioCallback(IAudioCallback* pCallback) { m_dvdAudio.RegisterAudioCallback(pCallback); } - void UnRegisterAudioCallback() { m_dvdAudio.UnRegisterAudioCallback(); } - void SetSpeed(int speed); void Flush(); @@ -146,6 +142,8 @@ public: bool IsStalled() const { return m_stalled; } bool IsEOS() { return false; } bool IsPassthrough() const; + double GetDelay() { return 0.0; } + double GetCacheTotal() { return 0.0; } protected: virtual void OnStartup(); diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h index 37a37c46b0..dcd0ffda00 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h @@ -37,7 +37,7 @@ class CDVDOverlayCodecCC; #define VIDEO_PICTURE_QUEUE_SIZE 1 -class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer +class CDVDPlayerVideo : public CThread, public IDVDStreamPlayerVideo { public: CDVDPlayerVideo( CDVDClock* pClock @@ -78,10 +78,12 @@ public: bool IsStalled() const { return m_stalled; } bool IsEOS() { return false; } + bool SubmittedEOS() const { return false; } double GetCurrentPts() { return m_iCurrentPts; } double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */ + int GetDecoderFreeSpace() { return 0; } std::string GetPlayerInfo(); int GetVideoBitrate(); std::string GetStereoMode(); diff --git a/xbmc/cores/dvdplayer/IDVDPlayer.h b/xbmc/cores/dvdplayer/IDVDPlayer.h index d99ec49813..cd8abfdc78 100644 --- a/xbmc/cores/dvdplayer/IDVDPlayer.h +++ b/xbmc/cores/dvdplayer/IDVDPlayer.h @@ -23,6 +23,9 @@ #include "DVDStreamInfo.h" #include "DVDMessageQueue.h" +template <typename T> class CRectGen; +typedef CRectGen<float> CRect; + class DVDNavResult; class IDVDPlayer @@ -35,10 +38,85 @@ public: class IDVDStreamPlayer { public: + virtual ~IDVDStreamPlayer() {} virtual bool OpenStream(CDVDStreamInfo &hint) = 0; virtual void CloseStream(bool bWaitForBuffers) = 0; - virtual void SendMessage(CDVDMsg* pMsg, int priority) = 0; + virtual void SendMessage(CDVDMsg* pMsg, int priority = 0) = 0; virtual bool IsInited() const = 0; virtual bool AcceptsData() const = 0; virtual bool IsStalled() const = 0; }; + +class CDVDVideoCodec; + +class IDVDStreamPlayerVideo : public IDVDStreamPlayer +{ +public: + ~IDVDStreamPlayerVideo() {} + float GetRelativeUsage() { return 0.0f; } + bool SetPriority(const int iPriority) { return true; } + virtual bool OpenStream(CDVDStreamInfo &hint) = 0; + virtual void CloseStream(bool bWaitForBuffers) = 0; + virtual bool StepFrame() = 0; + virtual void Flush() = 0; + virtual void WaitForBuffers() = 0; + virtual bool AcceptsData() const = 0; + virtual bool HasData() const = 0; + virtual int GetLevel() const = 0; + virtual bool IsInited() const = 0; + virtual void SendMessage(CDVDMsg* pMsg, int priority = 0) = 0; + virtual void EnableSubtitle(bool bEnable) = 0; + virtual bool IsSubtitleEnabled() = 0; + virtual void EnableFullscreen(bool bEnable) = 0; +#ifdef HAS_VIDEO_PLAYBACK + virtual void GetVideoRect(CRect& SrcRect, CRect& DestRect) const = 0; + virtual float GetAspectRatio() = 0; +#endif + virtual double GetDelay() = 0; + virtual void SetDelay(double delay) = 0; + virtual double GetSubtitleDelay() = 0; + virtual void SetSubtitleDelay(double delay) = 0; + virtual bool IsStalled() const = 0; + virtual double GetCurrentPts() = 0; + virtual double GetOutputDelay() = 0; + virtual std::string GetPlayerInfo() = 0; + virtual int GetVideoBitrate() = 0; + virtual std::string GetStereoMode() = 0; + virtual void SetSpeed(int iSpeed) = 0; + virtual int GetDecoderBufferSize() { return 0; } + virtual int GetDecoderFreeSpace() = 0; + virtual bool IsEOS() = 0; + virtual bool SubmittedEOS() const = 0; +}; + +class CDVDAudioCodec; +class IDVDStreamPlayerAudio : public IDVDStreamPlayer +{ +public: + ~IDVDStreamPlayerAudio() {} + float GetRelativeUsage() { return 0.0f; } + bool SetPriority(const int iPriority) { return true; } + virtual bool OpenStream(CDVDStreamInfo &hints) = 0; + virtual void CloseStream(bool bWaitForBuffers) = 0; + virtual void SetSpeed(int speed) = 0; + virtual void Flush() = 0; + virtual void WaitForBuffers() = 0; + virtual bool AcceptsData() const = 0; + virtual bool HasData() const = 0; + virtual int GetLevel() const = 0; + virtual bool IsInited() const = 0; + virtual void SendMessage(CDVDMsg* pMsg, int priority = 0) = 0; + virtual void SetVolume(float fVolume) = 0; + virtual void SetMute(bool bOnOff) = 0; + virtual void SetDynamicRangeCompression(long drc) = 0; + virtual std::string GetPlayerInfo() = 0; + virtual int GetAudioBitrate() = 0; + virtual int GetAudioChannels() = 0; + virtual double GetCurrentPts() = 0; + virtual bool IsStalled() const = 0; + virtual bool IsPassthrough() const = 0; + virtual double GetDelay() = 0; + virtual double GetCacheTotal() = 0; + virtual float GetDynamicRangeAmplification() const = 0; + virtual bool IsEOS() = 0; +}; diff --git a/xbmc/cores/omxplayer/Makefile.in b/xbmc/cores/omxplayer/Makefile.in index e5cad70f2f..77c25aa212 100644 --- a/xbmc/cores/omxplayer/Makefile.in +++ b/xbmc/cores/omxplayer/Makefile.in @@ -1,7 +1,6 @@ CXXFLAGS += -D__STDC_FORMAT_MACROS -SRCS = OMXPlayer.cpp -SRCS += OMXAudio.cpp +SRCS = OMXAudio.cpp SRCS += OMXVideo.cpp SRCS += OMXAudioCodecOMX.cpp SRCS += OMXPlayerAudio.cpp diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp index a2f9b0cffa..7e854410eb 100644 --- a/xbmc/cores/omxplayer/OMXAudio.cpp +++ b/xbmc/cores/omxplayer/OMXAudio.cpp @@ -65,7 +65,6 @@ static const uint16_t DTSFSCod [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050 ////////////////////////////////////////////////////////////////////// //*********************************************************************************************** COMXAudio::COMXAudio() : - m_pCallback (NULL ), m_Initialized (false ), m_CurrentVolume (0 ), m_Mute (false ), @@ -1393,25 +1392,6 @@ int COMXAudio::SetPlaySpeed(int iSpeed) return 0; } -void COMXAudio::RegisterAudioCallback(IAudioCallback *pCallback) -{ - CSingleLock lock (m_critSection); - if(!m_Passthrough && !m_HWDecode) - { - m_pCallback = pCallback; - if (m_pCallback) - m_pCallback->OnInitialize(2, m_SampleRate, 32); - } - else - m_pCallback = NULL; -} - -void COMXAudio::UnRegisterAudioCallback() -{ - CSingleLock lock (m_critSection); - m_pCallback = NULL; -} - unsigned int COMXAudio::GetAudioRenderingLatency() const { CSingleLock lock (m_critSection); diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h index c86c1d1c8d..85a0b98d19 100644 --- a/xbmc/cores/omxplayer/OMXAudio.h +++ b/xbmc/cores/omxplayer/OMXAudio.h @@ -29,7 +29,6 @@ #include "cores/AudioEngine/Utils/AEAudioFormat.h" #include "cores/AudioEngine/Utils/AEUtil.h" -#include "cores/IAudioCallback.h" #include "linux/PlatformDefs.h" #include "DVDStreamInfo.h" @@ -55,8 +54,6 @@ extern "C" { class COMXAudio { public: - void UnRegisterAudioCallback(); - void RegisterAudioCallback(IAudioCallback* pCallback); unsigned int GetChunkLen(); float GetDelay(); float GetCacheTime(); @@ -101,7 +98,6 @@ public: float GetMaxLevel(double &pts); private: - IAudioCallback* m_pCallback; bool m_Initialized; float m_CurrentVolume; bool m_Mute; diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp deleted file mode 100644 index 53fe37daae..0000000000 --- a/xbmc/cores/omxplayer/OMXPlayer.cpp +++ /dev/null @@ -1,4432 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" - -#if defined (HAS_OMXPLAYER) - -#include <sstream> -#include <iomanip> - -#include "OMXPlayerAudio.h" -#include "OMXPlayerVideo.h" -#include "OMXPlayer.h" -#include "Application.h" -#include "ApplicationMessenger.h" -#include "GUIInfoManager.h" -#include "cores/VideoRenderers/RenderManager.h" -#include "cores/VideoRenderers/RenderFlags.h" -#include "FileItem.h" -#include "filesystem/File.h" -#include "filesystem/SpecialProtocol.h" -#include "guilib/GUIWindowManager.h" -#include "settings/AdvancedSettings.h" -#include "settings/MediaSettings.h" -#include "settings/Settings.h" -#include "threads/SingleLock.h" -#include "windowing/WindowingFactory.h" - -#include "utils/log.h" -#include "utils/TimeUtils.h" -#include "utils/URIUtils.h" -#include "utils/Variant.h" -#include "utils/StreamDetails.h" -#include "xbmc/playlists/PlayListM3U.h" - -#include "utils/LangCodeExpander.h" -#include "video/VideoReferenceClock.h" -#include "guilib/LocalizeStrings.h" -#include "guilib/Key.h" - -#include "storage/MediaManager.h" -#include "GUIUserMessages.h" -#include "utils/StreamUtils.h" - -#include "DVDInputStreams/DVDFactoryInputStream.h" -#include "DVDInputStreams/DVDInputStreamNavigator.h" -#include "DVDInputStreams/DVDInputStreamTV.h" -#include "DVDInputStreams/DVDInputStreamPVRManager.h" - -#include "DVDDemuxers/DVDDemux.h" -#include "DVDDemuxers/DVDDemuxUtils.h" -#include "DVDDemuxers/DVDDemuxVobsub.h" -#include "DVDDemuxers/DVDFactoryDemuxer.h" -#include "DVDDemuxers/DVDDemuxFFmpeg.h" - -#include "DVDCodecs/DVDCodecs.h" -#include "DVDCodecs/DVDFactoryCodec.h" - -#include "DVDFileInfo.h" - -#include "utils/LangCodeExpander.h" -#include "guilib/Key.h" -#include "guilib/LocalizeStrings.h" - -#include "utils/URIUtils.h" -#include "GUIInfoManager.h" -#include "guilib/GUIWindowManager.h" -#include "guilib/StereoscopicsManager.h" -#include "Application.h" -#include "ApplicationMessenger.h" -#include "filesystem/File.h" -#include "pictures/Picture.h" -#include "libswscale/swscale.h" -#ifdef HAS_VIDEO_PLAYBACK -#include "cores/VideoRenderers/RenderManager.h" -#endif -#ifdef HAS_PERFORMANCE_SAMPLE -#include "xbmc/utils/PerformanceSample.h" -#else -#define MEASURE_FUNCTION -#endif -#include "settings/AdvancedSettings.h" -#include "FileItem.h" -#include "GUIUserMessages.h" -#include "settings/Settings.h" -#include "settings/MediaSettings.h" -#include "utils/log.h" -#include "utils/TimeUtils.h" -#include "utils/StreamDetails.h" -#include "pvr/PVRManager.h" -#include "pvr/channels/PVRChannel.h" -#include "pvr/addons/PVRClients.h" -#include "filesystem/PVRFile.h" -#include "video/dialogs/GUIDialogFullScreenInfo.h" -#include "utils/StreamUtils.h" -#include "utils/Variant.h" -#include "storage/MediaManager.h" -#include "dialogs/GUIDialogBusy.h" -#include "dialogs/GUIDialogKaiToast.h" -#include "xbmc/playlists/PlayListM3U.h" -#include "utils/StringUtils.h" -#include "Util.h" -#include "LangInfo.h" -#include "URL.h" -#include "utils/LangCodeExpander.h" - -// video not playing from clock, but stepped -#define TP(speed) ((speed) < 0 || (speed) > 4*DVD_PLAYSPEED_NORMAL) -// audio not playing -#define TPA(speed) ((speed) != DVD_PLAYSPEED_PAUSE && (speed) != DVD_PLAYSPEED_NORMAL) - -using namespace std; -using namespace PVR; - -#define CSelectionStreams COMXSelectionStreams -#define SelectionStreams OMXSelectionStreams -#define SelectionStream OMXSelectionStream -#define CDVDPlayer COMXPlayer -#define m_dvdPlayerVideo m_omxPlayerVideo -#define m_dvdPlayerAudio m_omxPlayerAudio -#define CCurrentStream COMXCurrentStream - -void CSelectionStreams::Clear(StreamType type, StreamSource source) -{ - CSingleLock lock(m_section); - for(int i=m_Streams.size()-1;i>=0;i--) - { - if(type && m_Streams[i].type != type) - continue; - - if(source && m_Streams[i].source != source) - continue; - - m_Streams.erase(m_Streams.begin() + i); - } -} - -SelectionStream& CSelectionStreams::Get(StreamType type, int index) -{ - CSingleLock lock(m_section); - int count = -1; - for(int i=0;i<(int)m_Streams.size();i++) - { - if(m_Streams[i].type != type) - continue; - count++; - if(count == index) - return m_Streams[i]; - } - CLog::Log(LOGERROR, "%s - failed to get stream", __FUNCTION__); - return m_invalid; -} - -std::vector<SelectionStream> CSelectionStreams::Get(StreamType type) -{ - std::vector<SelectionStream> streams; - int count = Count(type); - for(int index = 0; index < count; ++index){ - streams.push_back(Get(type, index)); - } - return streams; -} - -#define PREDICATE_RETURN(lh, rh) \ - do { \ - if((lh) != (rh)) \ - return (lh) > (rh); \ - } while(0) - -class PredicateSubtitleFilter -{ -private: - std::string audiolang; - bool original; -public: - /** \brief The class' operator() decides if the given (subtitle) SelectionStream is relevant wrt. - * preferred subtitle language and audio language. If the subtitle is relevant <B>false</B> false is returned. - * - * A subtitle is relevant if - * - it was previously selected, or - * - it's an external sub, or - * - it's a forced sub and "original stream's language" was selected, or - * - it's a forced sub and its language matches the audio's language, or - * - it's a default sub, or - * - its language matches the preferred subtitle's language (unequal to "original stream's language") - */ - PredicateSubtitleFilter(std::string& lang) - : audiolang(lang), - original(StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.subtitlelanguage"), "original")) - { - }; - - bool operator()(const SelectionStream& ss) const - { - if (ss.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream) - return false; - - if(STREAM_SOURCE_MASK(ss.source) == STREAM_SOURCE_DEMUX_SUB || STREAM_SOURCE_MASK(ss.source) == STREAM_SOURCE_TEXT) - return false; - - if ((ss.flags & CDemuxStream::FLAG_FORCED) && (original || g_LangCodeExpander.CompareLangCodes(ss.language, audiolang))) - return false; - - if ((ss.flags & CDemuxStream::FLAG_DEFAULT)) - return false; - - if(!original) - { - std::string subtitle_language = g_langInfo.GetSubtitleLanguage(); - if (g_LangCodeExpander.CompareLangCodes(subtitle_language, ss.language)) - return false; - } - - return true; - } -}; - -static bool PredicateAudioPriority(const SelectionStream& lh, const SelectionStream& rh) -{ - PREDICATE_RETURN(lh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream - , rh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream); - - // TrueHD never has enough cpu to decode on Pi, so prefer to avoid that - PREDICATE_RETURN(lh.codec != "truehd" - , rh.codec != "truehd"); - - if(!StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.audiolanguage"), "original")) - { - std::string audio_language = g_langInfo.GetAudioLanguage(); - PREDICATE_RETURN(g_LangCodeExpander.CompareLangCodes(audio_language, lh.language) - , g_LangCodeExpander.CompareLangCodes(audio_language, rh.language)); - } - - PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT - , rh.flags & CDemuxStream::FLAG_DEFAULT); - - PREDICATE_RETURN(lh.channels - , rh.channels); - - PREDICATE_RETURN(StreamUtils::GetCodecPriority(lh.codec) - , StreamUtils::GetCodecPriority(rh.codec)); - return false; -} - -/** \brief The class' operator() decides if the given (subtitle) SelectionStream lh is 'better than' the given (subtitle) SelectionStream rh. -* If lh is 'better than' rh the return value is true, false otherwise. -* -* A subtitle lh is 'better than' a subtitle rh (in evaluation order) if -* - lh was previously selected, or -* - lh is an external sub and rh not, or -* - lh is a forced sub and ("original stream's language" was selected or subtitles are off) and rh not, or -* - lh is an external sub and its language matches the preferred subtitle's language (unequal to "original stream's language") and rh not, or -* - lh is language matches the preferred subtitle's language (unequal to "original stream's language") and rh not, or -* - lh is a default sub and rh not -*/ -class PredicateSubtitlePriority -{ -private: - std::string audiolang; - bool original; - bool subson; - PredicateSubtitleFilter filter; -public: - PredicateSubtitlePriority(std::string& lang) - : audiolang(lang), - original(StringUtils::EqualsNoCase(CSettings::Get().GetString("locale.subtitlelanguage"), "original")), - subson(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn), - filter(lang) - { - }; - - bool relevant(const SelectionStream& ss) const - { - return !filter(ss); - } - - bool operator()(const SelectionStream& lh, const SelectionStream& rh) const - { - PREDICATE_RETURN(relevant(lh) - , relevant(rh)); - - PREDICATE_RETURN(lh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream - , rh.type_index == CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream); - - // prefer external subs - PREDICATE_RETURN(STREAM_SOURCE_MASK(lh.source) == STREAM_SOURCE_DEMUX_SUB - , STREAM_SOURCE_MASK(rh.source) == STREAM_SOURCE_DEMUX_SUB); - - PREDICATE_RETURN(STREAM_SOURCE_MASK(lh.source) == STREAM_SOURCE_TEXT - , STREAM_SOURCE_MASK(rh.source) == STREAM_SOURCE_TEXT); - - if(!subson || original) - { - PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_FORCED && g_LangCodeExpander.CompareLangCodes(lh.language, audiolang) - , rh.flags & CDemuxStream::FLAG_FORCED && g_LangCodeExpander.CompareLangCodes(rh.language, audiolang)); - - PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_FORCED - , rh.flags & CDemuxStream::FLAG_FORCED); - } - - std::string subtitle_language = g_langInfo.GetSubtitleLanguage(); - if(!original) - { - PREDICATE_RETURN((STREAM_SOURCE_MASK(lh.source) == STREAM_SOURCE_DEMUX_SUB || STREAM_SOURCE_MASK(lh.source) == STREAM_SOURCE_TEXT) && g_LangCodeExpander.CompareLangCodes(subtitle_language, lh.language) - , (STREAM_SOURCE_MASK(rh.source) == STREAM_SOURCE_DEMUX_SUB || STREAM_SOURCE_MASK(rh.source) == STREAM_SOURCE_TEXT) && g_LangCodeExpander.CompareLangCodes(subtitle_language, rh.language)); - } - - if(!original) - { - PREDICATE_RETURN(g_LangCodeExpander.CompareLangCodes(subtitle_language, lh.language) - , g_LangCodeExpander.CompareLangCodes(subtitle_language, rh.language)); - } - - PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT - , rh.flags & CDemuxStream::FLAG_DEFAULT); - - return false; - } -}; - -static bool PredicateVideoPriority(const SelectionStream& lh, const SelectionStream& rh) -{ - PREDICATE_RETURN(lh.flags & CDemuxStream::FLAG_DEFAULT - , rh.flags & CDemuxStream::FLAG_DEFAULT); - return false; -} - -bool CSelectionStreams::Get(StreamType type, CDemuxStream::EFlags flag, SelectionStream& out) -{ - CSingleLock lock(m_section); - for(int i=0;i<(int)m_Streams.size();i++) - { - if(m_Streams[i].type != type) - continue; - if((m_Streams[i].flags & flag) != flag) - continue; - out = m_Streams[i]; - return true; - } - return false; -} - -int CSelectionStreams::IndexOf(StreamType type, int source, int id) const -{ - CSingleLock lock(m_section); - int count = -1; - for(int i=0;i<(int)m_Streams.size();i++) - { - if(type && m_Streams[i].type != type) - continue; - count++; - if(source && m_Streams[i].source != source) - continue; - if(id < 0) - continue; - if(m_Streams[i].id == id) - return count; - } - if(id < 0) - return count; - else - return -1; -} - -int CSelectionStreams::IndexOf(StreamType type, CDVDPlayer& p) const -{ - if (p.m_pInputStream && p.m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - int id = -1; - if(type == STREAM_AUDIO) - id = ((CDVDInputStreamNavigator*)p.m_pInputStream)->GetActiveAudioStream(); - else if(type == STREAM_VIDEO) - id = p.m_CurrentVideo.id; - else if(type == STREAM_SUBTITLE) - id = ((CDVDInputStreamNavigator*)p.m_pInputStream)->GetActiveSubtitleStream(); - - return IndexOf(type, STREAM_SOURCE_NAV, id); - } - - if(type == STREAM_AUDIO) - return IndexOf(type, p.m_CurrentAudio.source, p.m_CurrentAudio.id); - else if(type == STREAM_VIDEO) - return IndexOf(type, p.m_CurrentVideo.source, p.m_CurrentVideo.id); - else if(type == STREAM_SUBTITLE) - return IndexOf(type, p.m_CurrentSubtitle.source, p.m_CurrentSubtitle.id); - else if(type == STREAM_TELETEXT) - return IndexOf(type, p.m_CurrentTeletext.source, p.m_CurrentTeletext.id); - - return -1; -} - -int CSelectionStreams::Source(StreamSource source, std::string filename) -{ - CSingleLock lock(m_section); - int index = source - 1; - for(int i=0;i<(int)m_Streams.size();i++) - { - SelectionStream &s = m_Streams[i]; - if(STREAM_SOURCE_MASK(s.source) != source) - continue; - // if it already exists, return same - if(s.filename == filename) - return s.source; - if(index < s.source) - index = s.source; - } - // return next index - return index + 1; -} - -void CSelectionStreams::Update(SelectionStream& s) -{ - CSingleLock lock(m_section); - int index = IndexOf(s.type, s.source, s.id); - if(index >= 0) - { - SelectionStream& o = Get(s.type, index); - s.type_index = o.type_index; - o = s; - } - else - { - s.type_index = Count(s.type); - m_Streams.push_back(s); - } -} - -void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer) -{ - if(input && input->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - CDVDInputStreamNavigator* nav = (CDVDInputStreamNavigator*)input; - string filename = nav->GetFileName(); - int source = Source(STREAM_SOURCE_NAV, filename); - - int count; - count = nav->GetAudioStreamCount(); - for(int i=0;i<count;i++) - { - SelectionStream s; - s.source = source; - s.type = STREAM_AUDIO; - s.id = i; - s.flags = CDemuxStream::FLAG_NONE; - s.filename = filename; - - DVDNavStreamInfo info; - nav->GetAudioStreamInfo(i, info); - s.name = info.name; - s.language = g_LangCodeExpander.ConvertToISO6392T(info.language); - s.channels = info.channels; - Update(s); - } - - count = nav->GetSubTitleStreamCount(); - for(int i=0;i<count;i++) - { - SelectionStream s; - s.source = source; - s.type = STREAM_SUBTITLE; - s.id = i; - s.flags = CDemuxStream::FLAG_NONE; - s.filename = filename; - s.channels = 0; - - DVDNavStreamInfo info; - nav->GetSubtitleStreamInfo(i, info); - s.name = info.name; - s.language = g_LangCodeExpander.ConvertToISO6392T(info.language); - Update(s); - } - } - else if(demuxer) - { - string filename = demuxer->GetFileName(); - int count = demuxer->GetNrOfStreams(); - int source; - if(input) /* hack to know this is sub decoder */ - source = Source(STREAM_SOURCE_DEMUX, filename); - else - source = Source(STREAM_SOURCE_DEMUX_SUB, filename); - - - for(int i=0;i<count;i++) - { - CDemuxStream* stream = demuxer->GetStream(i); - /* skip streams with no type */ - if (stream->type == STREAM_NONE) - continue; - /* make sure stream is marked with right source */ - stream->source = source; - - SelectionStream s; - s.source = source; - s.type = stream->type; - s.id = stream->iId; - s.language = g_LangCodeExpander.ConvertToISO6392T(stream->language); - s.flags = stream->flags; - s.filename = demuxer->GetFileName(); - stream->GetStreamName(s.name); - std::string codec; - demuxer->GetStreamCodecName(stream->iId, codec); - s.codec = codec; - s.channels = 0; // Default to 0. Overwrite if STREAM_AUDIO below. - if(stream->type == STREAM_AUDIO) - { - std::string type; - ((CDemuxStreamAudio*)stream)->GetStreamType(type); - if(type.length() > 0) - { - if(s.name.length() > 0) - s.name += " - "; - s.name += type; - } - s.channels = ((CDemuxStreamAudio*)stream)->iChannels; - } - Update(s); - } - } -} - -CDVDPlayer::CDVDPlayer(IPlayerCallback& callback) - : IPlayer(callback), - CThread("OMXPlayer"), - m_CurrentAudio(STREAM_AUDIO, DVDPLAYER_AUDIO), - m_CurrentVideo(STREAM_VIDEO, DVDPLAYER_VIDEO), - m_CurrentSubtitle(STREAM_SUBTITLE, DVDPLAYER_SUBTITLE), - m_CurrentTeletext(STREAM_TELETEXT, DVDPLAYER_TELETEXT), - m_messenger("player"), - m_dvdPlayerVideo(&m_av_clock, &m_overlayContainer, m_messenger), - m_dvdPlayerAudio(&m_av_clock, m_messenger), - m_dvdPlayerSubtitle(&m_overlayContainer), - m_dvdPlayerTeletext(), - m_ready(true), - m_DemuxerPausePending(false) -{ - m_pDemuxer = NULL; - m_pSubtitleDemuxer = NULL; - m_pInputStream = NULL; - - m_dvd.Clear(); - m_State.Clear(); - m_EdlAutoSkipMarkers.Clear(); - m_UpdateApplication = 0; - - m_bAbortRequest = false; - m_errorCount = 0; - m_offset_pts = 0.0; - m_playSpeed = DVD_PLAYSPEED_NORMAL; - m_caching = CACHESTATE_DONE; - m_HasVideo = false; - m_HasAudio = false; - m_stepped = false; - m_video_fifo = 0; - m_audio_fifo = 0; - m_last_check_time = 0.0; - m_stamp = 0.0; - - memset(&m_SpeedState, 0, sizeof(m_SpeedState)); -} - -CDVDPlayer::~CDVDPlayer() -{ - CloseFile(); -} - -bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) -{ - CLog::Log(LOGNOTICE, "DVDPlayer: Opening: %s", CURL::GetRedacted(file.GetPath()).c_str()); - - // if playing a file close it first - // this has to be changed so we won't have to close it. - if(IsRunning()) - CloseFile(); - - m_bAbortRequest = false; - SetPlaySpeed(DVD_PLAYSPEED_NORMAL); - - m_State.Clear(); - m_UpdateApplication = 0; - m_offset_pts = 0; - - m_PlayerOptions = options; - m_item = file; - m_mimetype = file.GetMimeType(); - m_filename = file.GetPath(); - - m_ready.Reset(); - -#if defined(HAS_VIDEO_PLAYBACK) - g_renderManager.PreInit(); -#endif - - Create(); - - // wait for the ready event - CGUIDialogBusy::WaitOnEvent(m_ready, g_advancedSettings.m_videoBusyDialogDelay_ms, false); - - // Playback might have been stopped due to some error - if (m_bStop || m_bAbortRequest) - return false; - - return true; -} - -bool CDVDPlayer::CloseFile(bool reopen) -{ - CLog::Log(LOGNOTICE, "CDVDPlayer::CloseFile()"); - - // set the abort request so that other threads can finish up - m_bAbortRequest = true; - - // tell demuxer to abort - if(m_pDemuxer) - m_pDemuxer->Abort(); - - if(m_pSubtitleDemuxer) - m_pSubtitleDemuxer->Abort(); - - if(m_pInputStream) - m_pInputStream->Abort(); - - CLog::Log(LOGNOTICE, "DVDPlayer: waiting for threads to exit"); - - // wait for the main thread to finish up - // since this main thread cleans up all other resources and threads - // we are done after the StopThread call - StopThread(); - - m_Edl.Clear(); - m_EdlAutoSkipMarkers.Clear(); - - m_HasVideo = false; - m_HasAudio = false; - - CLog::Log(LOGNOTICE, "DVDPlayer: finished waiting"); -#if defined(HAS_VIDEO_PLAYBACK) - g_renderManager.UnInit(); -#endif - return true; -} - -bool CDVDPlayer::IsPlaying() const -{ - return !m_bStop; -} - -void CDVDPlayer::OnStartup() -{ - m_CurrentVideo.Clear(); - m_CurrentAudio.Clear(); - m_CurrentSubtitle.Clear(); - m_CurrentTeletext.Clear(); - - m_messenger.Init(); - - CUtil::ClearTempFonts(); -} - -bool CDVDPlayer::OpenInputStream() -{ - if(m_pInputStream) - SAFE_DELETE(m_pInputStream); - - CLog::Log(LOGNOTICE, "Creating InputStream"); - - // correct the filename if needed - std::string filename(m_filename); - if (URIUtils::IsProtocol(filename, "dvd") - || StringUtils::EqualsNoCase(filename, "iso9660://video_ts/video_ts.ifo")) - { - m_filename = g_mediaManager.TranslateDevicePath(""); - } - - m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_filename, m_mimetype); - if(m_pInputStream == NULL) - { - CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - unable to create input stream for [%s]", m_filename.c_str()); - return false; - } - else - m_pInputStream->SetFileItem(m_item); - - if (!m_pInputStream->Open(m_filename.c_str(), m_mimetype)) - { - CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - error opening [%s]", m_filename.c_str()); - return false; - } - - if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) - || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY)) - { - CLog::Log(LOGINFO, "CDVDPlayer::OpenInputStream - DVD/BD not supported - Will try..."); - } - - // find any available external subtitles for non dvd files - if (!m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) - && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) - && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV) - && !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP)) - { - // find any available external subtitles - std::vector<std::string> filenames; - CUtil::ScanForExternalSubtitles( m_filename, filenames ); - - // load any subtitles from file item - std::string key("subtitle:1"); - for(unsigned s = 1; m_item.HasProperty(key); key = StringUtils::Format("subtitle:%u", ++s)) - filenames.push_back(m_item.GetProperty(key).asString()); - - for(unsigned int i=0;i<filenames.size();i++) - { - // if vobsub subtitle: - if (URIUtils::HasExtension(filenames[i], ".idx")) - { - std::string strSubFile; - if ( CUtil::FindVobSubPair( filenames, filenames[i], strSubFile ) ) - AddSubtitleFile(filenames[i], strSubFile); - } - else - { - if ( !CUtil::IsVobSub(filenames, filenames[i] ) ) - { - AddSubtitleFile(filenames[i]); - } - } - } // end loop over all subtitle files - - CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true; - } - - SetAVDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay); - SetSubTitleDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay); - m_clock.Reset(); - m_dvd.Clear(); - m_errorCount = 0; - m_ChannelEntryTimeOut.SetInfinite(); - - return true; -} - -bool CDVDPlayer::OpenDemuxStream() -{ - if(m_pDemuxer) - SAFE_DELETE(m_pDemuxer); - - CLog::Log(LOGNOTICE, "Creating Demuxer"); - - int attempts = 10; - while(!m_bStop && attempts-- > 0) - { - m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream); - if(!m_pDemuxer && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) - { - continue; - } - else if(!m_pDemuxer && m_pInputStream->NextStream() != CDVDInputStream::NEXTSTREAM_NONE) - { - CLog::Log(LOGDEBUG, "%s - New stream available from input, retry open", __FUNCTION__); - continue; - } - break; - } - - if(!m_pDemuxer) - { - CLog::Log(LOGERROR, "%s - Error creating demuxer", __FUNCTION__); - return false; - } - - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX); - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV); - m_SelectionStreams.Update(m_pInputStream, m_pDemuxer); - - int64_t len = m_pInputStream->GetLength(); - int64_t tim = m_pDemuxer->GetStreamLength(); - if(len > 0 && tim > 0) - m_pInputStream->SetReadRate(g_advancedSettings.m_readBufferFactor * len * 1000 / tim); - - return true; -} - -void CDVDPlayer::OpenDefaultStreams(bool reset) -{ - // if input stream dictate, we will open later - if(m_dvd.iSelectedAudioStream >= 0 - || m_dvd.iSelectedSPUStream >= 0) - return; - - SelectionStreams streams; - bool valid; - - // open video stream - streams = m_SelectionStreams.Get(STREAM_VIDEO, PredicateVideoPriority); - valid = false; - for(SelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it) - { - if(OpenStream(m_CurrentVideo, it->id, it->source, reset)) - valid = true; - } - if(!valid) - CloseStream(m_CurrentVideo, true); - - // open audio stream - if(m_PlayerOptions.video_only) - streams.clear(); - else - streams = m_SelectionStreams.Get(STREAM_AUDIO, PredicateAudioPriority); - valid = false; - - for(SelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it) - { - if(OpenStream(m_CurrentAudio, it->id, it->source, reset)) - valid = true; - } - if(!valid) - CloseStream(m_CurrentAudio, true); - - // enable or disable subtitles - bool visible = CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn; - - // open subtitle stream - SelectionStream as = m_SelectionStreams.Get(STREAM_AUDIO, GetAudioStream()); - PredicateSubtitlePriority psp(as.language); - streams = m_SelectionStreams.Get(STREAM_SUBTITLE, psp); - valid = false; - for(SelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it) - { - if(OpenStream(m_CurrentSubtitle, it->id, it->source)) - { - valid = true; - if(!psp.relevant(*it)) - visible = false; - else if(it->flags & CDemuxStream::FLAG_FORCED) - visible = true; - } - } - if(!valid) - CloseStream(m_CurrentSubtitle, true); - - SetSubtitleVisibleInternal(visible); - - // open teletext stream - streams = m_SelectionStreams.Get(STREAM_TELETEXT); - valid = false; - for(SelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it) - { - if(OpenStream(m_CurrentTeletext, it->id, it->source)) - valid = true; - } - if(!valid) - CloseStream(m_CurrentTeletext, true); -} - -bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream) -{ - - // check if we should read from subtitle demuxer - if( m_pSubtitleDemuxer && m_dvdPlayerSubtitle.AcceptsData() ) - { - packet = m_pSubtitleDemuxer->Read(); - - if(packet) - { - UpdateCorrection(packet, m_offset_pts); - if(packet->iStreamId < 0) - return true; - - stream = m_pSubtitleDemuxer->GetStream(packet->iStreamId); - if (!stream) - { - CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__); - return false; - } - if(stream->source == STREAM_SOURCE_NONE) - { - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX_SUB); - m_SelectionStreams.Update(NULL, m_pSubtitleDemuxer); - } - return true; - } - } - - // read a data frame from stream. - if(m_pDemuxer) - packet = m_pDemuxer->Read(); - - if(packet) - { - // stream changed, update and open defaults - if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE) - { - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX); - m_SelectionStreams.Update(m_pInputStream, m_pDemuxer); - OpenDefaultStreams(false); - - // reevaluate HasVideo/Audio, we may have switched from/to a radio channel - if(m_CurrentVideo.id < 0) - m_HasVideo = false; - if(m_CurrentAudio.id < 0) - m_HasAudio = false; - - return true; - } - - UpdateCorrection(packet, m_offset_pts); - - if(packet->iStreamId < 0) - return true; - - if(m_pDemuxer) - { - stream = m_pDemuxer->GetStream(packet->iStreamId); - if (!stream) - { - CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__); - return false; - } - if(stream->source == STREAM_SOURCE_NONE) - { - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX); - m_SelectionStreams.Update(m_pInputStream, m_pDemuxer); - } - } - return true; - } - return false; -} - -bool CDVDPlayer::IsValidStream(CCurrentStream& stream) -{ - if(stream.id<0) - return true; // we consider non selected as valid - - int source = STREAM_SOURCE_MASK(stream.source); - if(source == STREAM_SOURCE_TEXT) - return true; - if(source == STREAM_SOURCE_DEMUX_SUB) - { - CDemuxStream* st = m_pSubtitleDemuxer->GetStream(stream.id); - if(st == NULL || st->disabled) - return false; - if(st->type != stream.type) - return false; - return true; - } - if(source == STREAM_SOURCE_DEMUX) - { - CDemuxStream* st = m_pDemuxer->GetStream(stream.id); - if(st == NULL || st->disabled) - return false; - if(st->type != stream.type) - return false; - - if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - if(stream.type == STREAM_AUDIO && st->iPhysicalId != m_dvd.iSelectedAudioStream) - return false; - if(stream.type == STREAM_SUBTITLE && st->iPhysicalId != m_dvd.iSelectedSPUStream) - return false; - } - - return true; - } - - return false; -} - -bool CDVDPlayer::IsBetterStream(CCurrentStream& current, CDemuxStream* stream) -{ - // Do not reopen non-video streams if we're in video-only mode - if(m_PlayerOptions.video_only && current.type != STREAM_VIDEO) - return false; - - if(stream->disabled) - return false; - - if (m_pInputStream && ( m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) - || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY) ) ) - { - int source_type; - - source_type = STREAM_SOURCE_MASK(current.source); - if(source_type != STREAM_SOURCE_DEMUX - && source_type != STREAM_SOURCE_NONE) - return false; - - source_type = STREAM_SOURCE_MASK(stream->source); - if(source_type != STREAM_SOURCE_DEMUX - || stream->type != current.type - || stream->iId == current.id) - return false; - - if(current.type == STREAM_AUDIO && stream->iPhysicalId == m_dvd.iSelectedAudioStream) - return true; - if(current.type == STREAM_SUBTITLE && stream->iPhysicalId == m_dvd.iSelectedSPUStream) - return true; - if(current.type == STREAM_VIDEO && current.id < 0) - return true; - } - else - { - if(stream->source == current.source - && stream->iId == current.id) - return false; - - if(stream->type != current.type) - return false; - - if(current.type == STREAM_SUBTITLE) - return false; - - if(current.id < 0) - return true; - } - return false; -} - -void CDVDPlayer::CheckBetterStream(CCurrentStream& current, CDemuxStream* stream) -{ - IDVDStreamPlayer* player = GetStreamPlayer(current.player); - if (!IsValidStream(current) && (player == NULL || player->IsStalled())) - CloseStream(current, true); - - if (IsBetterStream(current, stream)) - OpenStream(current, stream->iId, stream->source); -} - -void CDVDPlayer::Process() -{ - bool bOmxWaitVideo = false; - bool bOmxWaitAudio = false; - bool bOmxSentEOFs = false; - float m_threshold = 0.2f; - - if (!OpenInputStream()) - { - m_bAbortRequest = true; - return; - } - - if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) - { - CLog::Log(LOGNOTICE, "DVDPlayer: playing a file with menu's"); - if(dynamic_cast<CDVDInputStreamNavigator*>(m_pInputStream)) - m_PlayerOptions.starttime = 0; - - if(m_PlayerOptions.state.size() > 0) - ptr->SetState(m_PlayerOptions.state); - else if(CDVDInputStreamNavigator* nav = dynamic_cast<CDVDInputStreamNavigator*>(m_pInputStream)) - nav->EnableSubtitleStream(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn); - - CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true; - } - - if(!OpenDemuxStream()) - { - m_bAbortRequest = true; - return; - } - - // allow renderer to switch to fullscreen if requested - m_dvdPlayerVideo.EnableFullscreen(m_PlayerOptions.fullscreen); - - if(!m_av_clock.OMXInitialize(&m_clock)) - { - m_bAbortRequest = true; - return; - } - if(CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF) - m_av_clock.HDMIClockSync(); - m_av_clock.OMXStateIdle(); - m_av_clock.OMXStop(); - m_av_clock.OMXPause(); - - OpenDefaultStreams(); - - // look for any EDL files - m_Edl.Clear(); - m_EdlAutoSkipMarkers.Clear(); - if (m_CurrentVideo.id >= 0 && m_CurrentVideo.hint.fpsrate > 0 && m_CurrentVideo.hint.fpsscale > 0) - { - float fFramesPerSecond = (float)m_CurrentVideo.hint.fpsrate / (float)m_CurrentVideo.hint.fpsscale; - m_Edl.ReadEditDecisionLists(m_filename, fFramesPerSecond, m_CurrentVideo.hint.height); - } - - /* - * Check to see if the demuxer should start at something other than time 0. This will be the case - * if there was a start time specified as part of the "Start from where last stopped" (aka - * auto-resume) feature or if there is an EDL cut or commercial break that starts at time 0. - */ - CEdl::Cut cut; - int starttime = 0; - if(m_PlayerOptions.starttime > 0 || m_PlayerOptions.startpercent > 0) - { - if (m_PlayerOptions.startpercent > 0 && m_pDemuxer) - { - int64_t playerStartTime = (int64_t) ( ( (float) m_pDemuxer->GetStreamLength() ) * ( m_PlayerOptions.startpercent/(float)100 ) ); - starttime = m_Edl.RestoreCutTime(playerStartTime); - } - else - { - starttime = m_Edl.RestoreCutTime((int64_t)m_PlayerOptions.starttime * 1000); // s to ms - } - CLog::Log(LOGDEBUG, "%s - Start position set to last stopped position: %d", __FUNCTION__, starttime); - } - else if(m_Edl.InCut(0, &cut) - && (cut.action == CEdl::CUT || cut.action == CEdl::COMM_BREAK)) - { - starttime = cut.end; - CLog::Log(LOGDEBUG, "%s - Start position set to end of first cut or commercial break: %d", __FUNCTION__, starttime); - if(cut.action == CEdl::COMM_BREAK) - { - /* - * Setup auto skip markers as if the commercial break had been skipped using standard - * detection. - */ - m_EdlAutoSkipMarkers.commbreak_start = cut.start; - m_EdlAutoSkipMarkers.commbreak_end = cut.end; - m_EdlAutoSkipMarkers.seek_to_start = true; - } - } - if(starttime > 0) - { - double startpts = DVD_NOPTS_VALUE; - if(m_pDemuxer) - { - if (m_pDemuxer->SeekTime(starttime, false, &startpts)) - CLog::Log(LOGDEBUG, "%s - starting demuxer from: %d", __FUNCTION__, starttime); - else - CLog::Log(LOGDEBUG, "%s - failed to start demuxing from: %d", __FUNCTION__, starttime); - } - - if(m_pSubtitleDemuxer) - { - if(m_pSubtitleDemuxer->SeekTime(starttime, false, &startpts)) - CLog::Log(LOGDEBUG, "%s - starting subtitle demuxer from: %d", __FUNCTION__, starttime); - else - CLog::Log(LOGDEBUG, "%s - failed to start subtitle demuxing from: %d", __FUNCTION__, starttime); - } - } - - // make sure all selected stream have data on startup - if (CachePVRStream()) - SetCaching(CACHESTATE_PVR); - - // make sure application know our info - UpdateApplication(0); - UpdatePlayState(0); - - if(m_PlayerOptions.identify == false) - m_callback.OnPlayBackStarted(); - - // we are done initializing now, set the readyevent - m_ready.Set(); - - if (!CachePVRStream()) - SetCaching(CACHESTATE_FLUSH); - - EDEINTERLACEMODE current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; - - while (!m_bAbortRequest) - { - double now = CDVDClock::GetAbsoluteClock(); - if (m_last_check_time == 0.0 || m_last_check_time + DVD_MSEC_TO_TIME(20) <= now) - { - m_last_check_time = now; - m_stamp = m_av_clock.OMXMediaTime(); - const bool m_Pause = m_playSpeed == DVD_PLAYSPEED_PAUSE; - const bool not_accepts_data = (!m_dvdPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) || - (!m_dvdPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0); - /* when the video/audio fifos are low, we pause clock, when high we resume */ - double audio_pts = floor(m_dvdPlayerAudio.GetCurrentPts()); - double video_pts = floor(m_dvdPlayerVideo.GetCurrentPts()); - - float audio_fifo = audio_pts / DVD_TIME_BASE - m_stamp * 1e-6; - float video_fifo = video_pts / DVD_TIME_BASE - m_stamp * 1e-6; - float threshold = 0.1f; - bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false; - - // if deinterlace setting has changed, we should close and open video - if (current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode) - { - CloseStream(m_CurrentVideo, false); - OpenStream(m_CurrentVideo, m_CurrentVideo.id, m_CurrentVideo.source); - if (m_State.canseek) - m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true)); - current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; - } - - m_video_fifo = (int)(100.0*(m_dvdPlayerVideo.GetDecoderBufferSize()-m_dvdPlayerVideo.GetDecoderFreeSpace())/m_dvdPlayerVideo.GetDecoderBufferSize()); - m_audio_fifo = (int)(100.0*audio_fifo/m_dvdPlayerAudio.GetCacheTotal()); - - #ifdef _DEBUG - static unsigned count; - if ((count++ & 7) == 0) - { - char response[80]; - if (m_dvdPlayerVideo.GetDecoderBufferSize() && m_dvdPlayerAudio.GetCacheTotal()) - vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d", - m_video_fifo, - (int)(100.0*video_fifo/m_dvdPlayerAudio.GetCacheTotal()), - 0, 100); - if (m_dvdPlayerAudio.GetCacheTotal()) - vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d", - m_audio_fifo, - (int)(100.0*m_dvdPlayerAudio.GetDelay()/m_dvdPlayerAudio.GetCacheTotal()), - 0, 100); - vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d", - m_dvdPlayerVideo.GetLevel(), 0, 0, 100); - vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d", - m_dvdPlayerAudio.GetLevel(), 0, 0, 100); - } - #endif - if (audio_pts != DVD_NOPTS_VALUE) - { - audio_fifo_low = m_HasAudio && audio_fifo < threshold; - audio_fifo_high = audio_pts != DVD_NOPTS_VALUE && audio_fifo >= m_threshold; - } - if (video_pts != DVD_NOPTS_VALUE) - { - video_fifo_low = m_HasVideo && video_fifo < threshold; - video_fifo_high = video_pts != DVD_NOPTS_VALUE && video_fifo >= m_threshold; - } - if (!m_HasAudio && m_HasVideo) - audio_fifo_high = true; - if (!m_HasVideo && m_HasAudio) - video_fifo_high = true; - - #ifdef _DEBUG - CLog::Log(LOGDEBUG, "%s - M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", __FUNCTION__, - m_stamp*1e-6, m_av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6, m_av_clock.OMXIsPaused(), bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL), - audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_threshold, - audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, - m_dvdPlayerAudio.GetLevel(), m_dvdPlayerVideo.GetLevel(), m_dvdPlayerAudio.GetDelay(), (float)m_dvdPlayerAudio.GetCacheTotal()); - #endif - - if (TP(m_playSpeed)) - { - if (m_CurrentVideo.started) - { - if (m_stamp == 0.0 && (!m_stepped || m_playSpeed > 0)) - { - /* trickplay modes progress by stepping */ - CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking step speed:%.2f last:%.2f v:%.2f", (double)m_playSpeed / DVD_PLAYSPEED_NORMAL, m_SpeedState.lastpts*1e-6, video_pts*1e-6); - m_av_clock.OMXStep(); - } - else - { - m_av_clock.OMXMediaTime(0.0); - m_last_check_time = 0.0; - m_stepped = true; - } - } - } - else if(!m_Pause && (bOmxSentEOFs || not_accepts_data || (audio_fifo_high && video_fifo_high))) - { - if (m_av_clock.OMXIsPaused()) - { - CLog::Log(LOGDEBUG, "Resume %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f\n", audio_fifo, video_fifo, - audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, bOmxSentEOFs, not_accepts_data, m_threshold); - m_av_clock.OMXStateExecute(); - m_av_clock.OMXResume(); - } - } - else if (m_Pause || audio_fifo_low || video_fifo_low) - { - if (!m_av_clock.OMXIsPaused() && !TPA(m_playSpeed)) - { - if (!m_Pause) - m_threshold = std::min(2.0f*m_threshold, 16.0f); - CLog::Log(LOGDEBUG, "Pause %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f\n", audio_fifo, video_fifo, - audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, bOmxSentEOFs, not_accepts_data, m_threshold); - m_av_clock.OMXPause(); - } - } - } - HandleMessages(); - - if(m_bAbortRequest) - break; - - // should we open a new input stream? - if(!m_pInputStream) - { - if (OpenInputStream() == false) - { - CLog::Log(LOGERROR, "%s - Closing stream due to OpenInputStream()", __FUNCTION__); - m_bAbortRequest = true; - break; - } - } - - // should we open a new demuxer? - if(!m_pDemuxer) - { - if (m_pInputStream->NextStream() == CDVDInputStream::NEXTSTREAM_NONE) - break; - - if (m_pInputStream->IsEOF()) - break; - - if (OpenDemuxStream() == false) - { - CLog::Log(LOGERROR, "%s - Closing stream due to OpenDemuxStream()", __FUNCTION__); - m_bAbortRequest = true; - break; - } - - OpenDefaultStreams(); - - // never allow first frames after open to be skipped - if( m_dvdPlayerVideo.IsInited() ) - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); - - if (CachePVRStream()) - SetCaching(CACHESTATE_PVR); - - UpdateApplication(0); - UpdatePlayState(0); - } - - // handle eventual seeks due to playspeed - HandlePlaySpeed(); - - // update player state - UpdatePlayState(200); - - // update application with our state - UpdateApplication(1000); - - // make sure we run subtitle process here - m_dvdPlayerSubtitle.Process(m_clock.GetClock() + m_State.time_offset - m_dvdPlayerVideo.GetSubtitleDelay(), m_State.time_offset); - - // OMX emergency exit - if(HasAudio() && m_dvdPlayerAudio.BadState()) - { - CLog::Log(LOGERROR, "%s - Closing stream due to m_dvdPlayerAudio.BadState()", __FUNCTION__); - m_bAbortRequest = true; - break; - } - - if (CheckDelayedChannelEntry()) - continue; - - // if the queues are full, no need to read more - if ((!m_dvdPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) || - (!m_dvdPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0)) - { - if(m_pDemuxer && m_DemuxerPausePending) - { - m_DemuxerPausePending = false; - m_pDemuxer->SetSpeed(DVD_PLAYSPEED_PAUSE); - } - - Sleep(10); - continue; - } - - // always yield to players if they have data levels > 50 percent - if((m_dvdPlayerAudio.GetLevel() > 50 || m_CurrentAudio.id < 0) - && (m_dvdPlayerVideo.GetLevel() > 50 || m_CurrentVideo.id < 0)) - Sleep(0); - - DemuxPacket* pPacket = NULL; - CDemuxStream *pStream = NULL; - ReadPacket(pPacket, pStream); - if (pPacket && !pStream) - { - /* probably a empty packet, just free it and move on */ - CDVDDemuxUtils::FreeDemuxPacket(pPacket); - continue; - } - if (pPacket) - { - // reset eos state when we get a packet (e.g. for case of seek after eos) - bOmxWaitVideo = false; - bOmxWaitAudio = false; - bOmxSentEOFs = false; - } - if (!pPacket) - { - // when paused, demuxer could be be returning empty - if (m_playSpeed == DVD_PLAYSPEED_PAUSE) - continue; - - // check for a still frame state - if (CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) - { - // stills will be skipped - if(m_dvd.state == DVDSTATE_STILL) - { - if (m_dvd.iDVDStillTime > 0) - { - if ((XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime) >= m_dvd.iDVDStillTime) - { - m_dvd.iDVDStillTime = 0; - m_dvd.iDVDStillStartTime = 0; - m_dvd.state = DVDSTATE_NORMAL; - pStream->SkipStill(); - continue; - } - } - } - } - - // if there is another stream available, reopen demuxer - CDVDInputStream::ENextStream next = m_pInputStream->NextStream(); - if(next == CDVDInputStream::NEXTSTREAM_OPEN) - { - SAFE_DELETE(m_pDemuxer); - m_CurrentAudio.stream = NULL; - m_CurrentVideo.stream = NULL; - m_CurrentSubtitle.stream = NULL; - continue; - } - - // input stream asked us to just retry - if(next == CDVDInputStream::NEXTSTREAM_RETRY) - { - Sleep(100); - continue; - } - - // make sure we tell all players to finish it's data - if (!bOmxSentEOFs) - { - if(m_CurrentAudio.inited) - { - m_dvdPlayerAudio.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF)); - bOmxWaitAudio = true; - } - if(m_CurrentVideo.inited) - { - m_dvdPlayerVideo.SendMessage (new CDVDMsg(CDVDMsg::GENERAL_EOF)); - bOmxWaitVideo = true; - } - if(m_CurrentSubtitle.inited) - m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); - if(m_CurrentTeletext.inited) - m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_EOF)); - m_CurrentAudio.inited = false; - m_CurrentVideo.inited = false; - m_CurrentSubtitle.inited = false; - m_CurrentTeletext.inited = false; - bOmxSentEOFs = true; - } - - // if we are caching, start playing it again - SetCaching(CACHESTATE_DONE); - - // while players are still playing, keep going to allow seekbacks - if(m_dvdPlayerAudio.HasData() - || m_dvdPlayerVideo.HasData()) - { - Sleep(100); - continue; - } - - // wait for omx components to finish - if(bOmxWaitVideo && !m_dvdPlayerVideo.IsEOS()) - { - Sleep(100); - continue; - } - if(bOmxWaitAudio && !m_dvdPlayerAudio.IsEOS()) - { - Sleep(100); - continue; - } - - if (!m_pInputStream->IsEOF()) - CLog::Log(LOGINFO, "%s - eof reading from demuxer", __FUNCTION__); - - m_CurrentAudio.started = false; - m_CurrentVideo.started = false; - m_CurrentSubtitle.started = false; - m_CurrentTeletext.started = false; - - break; - } - - // it's a valid data packet, reset error counter - m_errorCount = 0; - - // see if we can find something better to play - CheckBetterStream(m_CurrentAudio, pStream); - CheckBetterStream(m_CurrentVideo, pStream); - CheckBetterStream(m_CurrentSubtitle, pStream); - CheckBetterStream(m_CurrentTeletext, pStream); - - // process the packet - ProcessPacket(pStream, pPacket); - - // check if in a cut or commercial break that should be automatically skipped - CheckAutoSceneSkip(); - } -} - -bool CDVDPlayer::CheckDelayedChannelEntry(void) -{ - bool bReturn(false); - - if (m_ChannelEntryTimeOut.IsTimePast()) - { - CFileItem currentFile(g_application.CurrentFileItem()); - CPVRChannel *currentChannel = currentFile.GetPVRChannelInfoTag(); - SwitchChannel(*currentChannel); - - bReturn = true; - m_ChannelEntryTimeOut.SetInfinite(); - } - - return bReturn; -} - -bool CDVDPlayer::CheckIsCurrent(CCurrentStream& current, CDemuxStream* stream, DemuxPacket* pkg) -{ - if(current.id == pkg->iStreamId - && current.source == stream->source - && current.type == stream->type) - return true; - else - return false; -} - -void CDVDPlayer::ProcessPacket(CDemuxStream* pStream, DemuxPacket* pPacket) -{ - /* process packet if it belongs to selected stream. for dvd's don't allow automatic opening of streams*/ - - if (CheckIsCurrent(m_CurrentAudio, pStream, pPacket)) - ProcessAudioData(pStream, pPacket); - else if (CheckIsCurrent(m_CurrentVideo, pStream, pPacket)) - ProcessVideoData(pStream, pPacket); - else if (CheckIsCurrent(m_CurrentSubtitle, pStream, pPacket)) - ProcessSubData(pStream, pPacket); - else if (CheckIsCurrent(m_CurrentTeletext, pStream, pPacket)) - ProcessTeletextData(pStream, pPacket); - else - { - pStream->SetDiscard(AVDISCARD_ALL); - CDVDDemuxUtils::FreeDemuxPacket(pPacket); // free it since we won't do anything with it - } -} - -void CDVDPlayer::CheckStreamChanges(CCurrentStream& current, CDemuxStream* stream) -{ - if (current.stream != (void*)stream - || current.changes != stream->changes) - { - /* check so that dmuxer hints or extra data hasn't changed */ - /* if they have, reopen stream */ - - if (current.hint != CDVDStreamInfo(*stream, true)) - OpenStream(current, stream->iId, stream->source ); - - current.stream = (void*)stream; - current.changes = stream->changes; - } -} - -void CDVDPlayer::ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket) -{ - CheckStreamChanges(m_CurrentAudio, pStream); - - // check if we are too slow and need to recache - CheckStartCaching(m_CurrentAudio); - - CheckContinuity(m_CurrentAudio, pPacket); - UpdateTimestamps(m_CurrentAudio, pPacket); - - bool drop = false; - if (CheckPlayerInit(m_CurrentAudio)) - drop = true; - - /* - * If CheckSceneSkip() returns true then demux point is inside an EDL cut and the packets are dropped. - * If not inside a hard cut, but the demux point has reached an EDL mute section then trigger the - * AUDIO_SILENCE state. The AUDIO_SILENCE state is reverted as soon as the demux point is outside - * of any EDL section while EDL mute is still active. - */ - CEdl::Cut cut; - if (CheckSceneSkip(m_CurrentAudio)) - drop = true; - else if (m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) && cut.action == CEdl::MUTE // Inside EDL mute - && !m_EdlAutoSkipMarkers.mute) // Mute not already triggered - { - m_dvdPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, true)); - m_EdlAutoSkipMarkers.mute = true; - } - else if (!m_Edl.InCut(DVD_TIME_TO_MSEC(m_CurrentAudio.dts + m_offset_pts), &cut) // Outside of any EDL - && m_EdlAutoSkipMarkers.mute) // But the mute hasn't been removed yet - { - m_dvdPlayerAudio.SendMessage(new CDVDMsgBool(CDVDMsg::AUDIO_SILENCE, false)); - m_EdlAutoSkipMarkers.mute = false; - } - - m_dvdPlayerAudio.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); -} - -void CDVDPlayer::ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket) -{ - CheckStreamChanges(m_CurrentVideo, pStream); - - // check if we are too slow and need to recache - CheckStartCaching(m_CurrentVideo); - - if( pPacket->iSize != 4) //don't check the EOF_SEQUENCE of stillframes - { - CheckContinuity(m_CurrentVideo, pPacket); - UpdateTimestamps(m_CurrentVideo, pPacket); - } - - bool drop = false; - if (CheckPlayerInit(m_CurrentVideo)) - drop = true; - - if (CheckSceneSkip(m_CurrentVideo)) - drop = true; - - m_dvdPlayerVideo.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); -} - -void CDVDPlayer::ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket) -{ - CheckStreamChanges(m_CurrentSubtitle, pStream); - - UpdateTimestamps(m_CurrentSubtitle, pPacket); - - bool drop = false; - if (CheckPlayerInit(m_CurrentSubtitle)) - drop = true; - - if (CheckSceneSkip(m_CurrentSubtitle)) - drop = true; - - m_dvdPlayerSubtitle.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); - - if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL); -} - -void CDVDPlayer::ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket) -{ - CheckStreamChanges(m_CurrentTeletext, pStream); - - UpdateTimestamps(m_CurrentTeletext, pPacket); - - bool drop = false; - if (CheckPlayerInit(m_CurrentTeletext)) - drop = true; - - if (CheckSceneSkip(m_CurrentTeletext)) - drop = true; - - m_dvdPlayerTeletext.SendMessage(new CDVDMsgDemuxerPacket(pPacket, drop)); -} - -bool CDVDPlayer::GetCachingTimes(double& level, double& delay, double& offset) -{ - if(!m_pInputStream || !m_pDemuxer) - return false; - - XFILE::SCacheStatus status; - if (!m_pInputStream->GetCacheStatus(&status)) - return false; - - int64_t cached = status.forward; - unsigned currate = status.currate; - unsigned maxrate = status.maxrate; - bool full = status.full; - - int64_t length = m_pInputStream->GetLength(); - int64_t remain = length - m_pInputStream->Seek(0, SEEK_CUR); - - if(cached < 0 || length <= 0 || remain < 0) - return false; - - double play_sbp = DVD_MSEC_TO_TIME(m_pDemuxer->GetStreamLength()) / length; - double queued = 1000.0 * GetQueueTime() / play_sbp; - - delay = 0.0; - level = 0.0; - offset = (double)(cached + queued) / length; - - if (currate == 0) - return true; - - double cache_sbp = 1.1 * (double)DVD_TIME_BASE / currate; /* underestimate by 10 % */ - double play_left = play_sbp * (remain + queued); /* time to play out all remaining bytes */ - double cache_left = cache_sbp * (remain - cached); /* time to cache the remaining bytes */ - double cache_need = std::max(0.0, remain - play_left / cache_sbp); /* bytes needed until play_left == cache_left */ - - delay = cache_left - play_left; - - if (full && (currate < maxrate) ) - level = -1.0; /* buffer is full & our read rate is too low */ - else - level = (cached + queued) / (cache_need + queued); - - return true; -} - -void CDVDPlayer::HandlePlaySpeed() -{ - ECacheState caching = m_caching; - - if(IsInMenu() && caching != CACHESTATE_DONE) - caching = CACHESTATE_DONE; - - if(caching == CACHESTATE_FULL) - { - double level, delay, offset; - if(GetCachingTimes(level, delay, offset)) - { - if(level < 0.0) - { - CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(21454), g_localizeStrings.Get(21455)); - caching = CACHESTATE_INIT; - } - if(level >= 1.0) - caching = CACHESTATE_INIT; - } - else - { - if ((!m_dvdPlayerAudio.AcceptsData() && m_CurrentAudio.id >= 0) - || (!m_dvdPlayerVideo.AcceptsData() && m_CurrentVideo.id >= 0)) - caching = CACHESTATE_INIT; - } - } - - if(caching == CACHESTATE_INIT) - { - // if all enabled streams have been inited we are done - if((m_CurrentVideo.id < 0 || m_CurrentVideo.started) - && (m_CurrentAudio.id < 0 || m_CurrentAudio.started)) - caching = CACHESTATE_PLAY; - - // handle situation that we get no data on one stream - if(m_CurrentAudio.id >= 0 && m_CurrentVideo.id >= 0) - { - if ((!m_dvdPlayerAudio.AcceptsData() && !m_CurrentVideo.started) - || (!m_dvdPlayerVideo.AcceptsData() && !m_CurrentAudio.started)) - { - caching = CACHESTATE_DONE; - } - } - } - - if (caching == CACHESTATE_PVR) - { - bool bGotAudio(m_pDemuxer->GetNrOfAudioStreams() > 0); - bool bGotVideo(m_pDemuxer->GetNrOfVideoStreams() > 0); - bool bAudioLevelOk(m_dvdPlayerAudio.GetLevel() > g_advancedSettings.m_iPVRMinAudioCacheLevel); - bool bVideoLevelOk(m_dvdPlayerVideo.GetLevel() > g_advancedSettings.m_iPVRMinVideoCacheLevel); - bool bAudioFull(!m_dvdPlayerAudio.AcceptsData()); - bool bVideoFull(!m_dvdPlayerVideo.AcceptsData()); - - if (/* if all streams got at least g_advancedSettings.m_iPVRMinCacheLevel in their buffers, we're done */ - ((bGotVideo || bGotAudio) && (!bGotAudio || bAudioLevelOk) && (!bGotVideo || bVideoLevelOk)) || - /* or if one of the buffers is full */ - (bAudioFull || bVideoFull)) - { - CLog::Log(LOGDEBUG, "set caching from pvr to done. audio (%d) = %d. video (%d) = %d", - bGotAudio, m_dvdPlayerAudio.GetLevel(), - bGotVideo, m_dvdPlayerVideo.GetLevel()); - - caching = CACHESTATE_DONE; - } - else - { - /* ensure that automatically started players are stopped while caching */ - if (m_CurrentAudio.started) - m_dvdPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE); - if (m_CurrentVideo.started) - m_dvdPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE); - } - } - - if(caching == CACHESTATE_PLAY) - { - // if all enabled streams have started playing we are done - if((m_CurrentVideo.id < 0 || !m_dvdPlayerVideo.IsStalled()) - && (m_CurrentAudio.id < 0 || !m_dvdPlayerAudio.IsStalled())) - caching = CACHESTATE_DONE; - } - - if(m_caching != caching) - SetCaching(caching); - - - if(GetPlaySpeed() != DVD_PLAYSPEED_NORMAL && GetPlaySpeed() != DVD_PLAYSPEED_PAUSE) - { - if (IsInMenu()) - { - // this can't be done in menu - SetPlaySpeed(DVD_PLAYSPEED_NORMAL); - - } - else if (m_CurrentVideo.id >= 0 - && m_CurrentVideo.inited == true - && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() - && m_SpeedState.lasttime != GetTime() - && m_stepped) - { - m_SpeedState.lastpts = m_dvdPlayerVideo.GetCurrentPts(); - m_SpeedState.lasttime = GetTime(); - // check how much off clock video is when ff/rw:ing - // a problem here is that seeking isn't very accurate - // and since the clock will be resynced after seek - // we might actually not really be playing at the wanted - // speed. we'd need to have some way to not resync the clock - // after a seek to remember timing. still need to handle - // discontinuities somehow - - // when seeking, give the player a headstart to make sure - // the time it takes to seek doesn't make a difference. - double error; - error = m_clock.GetClock() - m_SpeedState.lastpts; - error *= m_playSpeed / abs(m_playSpeed); - - if(error > DVD_MSEC_TO_TIME(1000)) - { - CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking to catch up"); - int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL); - m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true)); - } - } - } -} - -bool CDVDPlayer::CheckStartCaching(CCurrentStream& current) -{ - if(m_caching != CACHESTATE_DONE - || m_playSpeed != DVD_PLAYSPEED_NORMAL) - return false; - - if(IsInMenu()) - return false; - - if((current.type == STREAM_AUDIO && m_dvdPlayerAudio.IsStalled()) - || (current.type == STREAM_VIDEO && m_dvdPlayerVideo.IsStalled())) - { - if (CachePVRStream()) - { - if ((current.type == STREAM_AUDIO && current.started && m_dvdPlayerAudio.GetLevel() == 0) || - (current.type == STREAM_VIDEO && current.started && m_dvdPlayerVideo.GetLevel() == 0)) - { - CLog::Log(LOGDEBUG, "%s stream stalled. start buffering", current.type == STREAM_AUDIO ? "audio" : "video"); - SetCaching(CACHESTATE_PVR); - } - return true; - } - - // don't start caching if it's only a single stream that has run dry - if(m_dvdPlayerAudio.GetLevel() > 50 - || m_dvdPlayerVideo.GetLevel() > 50) - return false; - - if(current.inited) - SetCaching(CACHESTATE_FULL); - else - SetCaching(CACHESTATE_INIT); - return true; - } - return false; -} - -bool CDVDPlayer::CheckPlayerInit(CCurrentStream& current) -{ - if(current.inited) - return false; - - if(current.startpts != DVD_NOPTS_VALUE) - { - if(current.dts == DVD_NOPTS_VALUE) - { - CLog::Log(LOGDEBUG, "%s - dropping packet type:%d dts:%f to get to start point at %f", __FUNCTION__, current.player, current.dts, current.startpts); - return true; - } - - if((current.startpts - current.dts) > DVD_SEC_TO_TIME(20)) - { - CLog::Log(LOGDEBUG, "%s - too far to decode before finishing seek", __FUNCTION__); - if(m_CurrentAudio.startpts != DVD_NOPTS_VALUE) - m_CurrentAudio.startpts = current.dts; - if(m_CurrentVideo.startpts != DVD_NOPTS_VALUE) - m_CurrentVideo.startpts = current.dts; - if(m_CurrentSubtitle.startpts != DVD_NOPTS_VALUE) - m_CurrentSubtitle.startpts = current.dts; - if(m_CurrentTeletext.startpts != DVD_NOPTS_VALUE) - m_CurrentTeletext.startpts = current.dts; - } - - if(current.dts < current.startpts) - { - CLog::Log(LOGDEBUG, "%s - dropping packet type:%d dts:%f to get to start point at %f", __FUNCTION__, current.player, current.dts, current.startpts); - return true; - } - } - - //If this is the first packet after a discontinuity, send it as a resync - if (current.dts != DVD_NOPTS_VALUE) - { - current.inited = true; - current.startpts = current.dts; - - bool setclock = false; - if(m_playSpeed == DVD_PLAYSPEED_NORMAL) - { - if( current.player == DVDPLAYER_AUDIO) - setclock = m_clock.GetMaster() == MASTER_CLOCK_AUDIO - || m_clock.GetMaster() == MASTER_CLOCK_AUDIO_VIDEOREF; - else if(current.player == DVDPLAYER_VIDEO) - setclock = m_clock.GetMaster() == MASTER_CLOCK_VIDEO; - } - else - { - if(current.player == DVDPLAYER_VIDEO) - setclock = true; - } - - double starttime = current.startpts; - if(m_CurrentAudio.inited - && m_CurrentAudio.startpts != DVD_NOPTS_VALUE - && m_CurrentAudio.startpts < starttime) - starttime = m_CurrentAudio.startpts; - if(m_CurrentVideo.inited - && m_CurrentVideo.startpts != DVD_NOPTS_VALUE - && m_CurrentVideo.startpts < starttime) - starttime = m_CurrentVideo.startpts; - - starttime = current.startpts - starttime; - if(starttime > 0 && setclock) - { - if(starttime > DVD_SEC_TO_TIME(2)) - CLog::Log(LOGWARNING, "CDVDPlayer::CheckPlayerInit(%d) - Ignoring too large delay of %f", current.player, starttime); - else - SendPlayerMessage(new CDVDMsgDouble(CDVDMsg::GENERAL_DELAY, starttime), current.player); - } - - SendPlayerMessage(new CDVDMsgGeneralResync(current.dts, setclock), current.player); - } - return false; -} - -void CDVDPlayer::UpdateCorrection(DemuxPacket* pkt, double correction) -{ - //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); - if(pkt->dts != DVD_NOPTS_VALUE) pkt->dts -= correction; - if(pkt->pts != DVD_NOPTS_VALUE) pkt->pts -= correction; -} - -void CDVDPlayer::UpdateTimestamps(CCurrentStream& current, DemuxPacket* pPacket) -{ - double dts = current.dts; - /* update stored values */ - if(pPacket->dts != DVD_NOPTS_VALUE) - dts = pPacket->dts; - else if(pPacket->pts != DVD_NOPTS_VALUE) - dts = pPacket->pts; - - /* calculate some average duration */ - if(pPacket->duration != DVD_NOPTS_VALUE) - current.dur = pPacket->duration; - else if(dts != DVD_NOPTS_VALUE && current.dts != DVD_NOPTS_VALUE) - current.dur = 0.1 * (current.dur * 9 + (dts - current.dts)); - - current.dts = dts; - - /* send a playback state structure periodically */ - if(current.dts_state == DVD_NOPTS_VALUE - || abs(current.dts - current.dts_state) > DVD_MSEC_TO_TIME(200)) - { - current.dts_state = current.dts; - if (current.inited) - { - // make sure we send no outdated state to a/v players - UpdatePlayState(0); - SendPlayerMessage(new CDVDMsgType<SPlayerState>(CDVDMsg::PLAYER_DISPLAYTIME, m_StateInput), current.player); - } - else - { - CSingleLock lock(m_StateSection); - m_State = m_StateInput; - } - } -} - -static void UpdateLimits(double& minimum, double& maximum, double dts) -{ - if(dts == DVD_NOPTS_VALUE) - return; - if(minimum == DVD_NOPTS_VALUE || minimum > dts) minimum = dts; - if(maximum == DVD_NOPTS_VALUE || maximum < dts) maximum = dts; -} - -void CDVDPlayer::CheckContinuity(CCurrentStream& current, DemuxPacket* pPacket) -{ - if (m_playSpeed < DVD_PLAYSPEED_PAUSE) - return; - - if( pPacket->dts == DVD_NOPTS_VALUE || current.dts == DVD_NOPTS_VALUE) - return; - - double mindts = DVD_NOPTS_VALUE, maxdts = DVD_NOPTS_VALUE; - UpdateLimits(mindts, maxdts, m_CurrentAudio.dts); - UpdateLimits(mindts, maxdts, m_CurrentVideo.dts); - UpdateLimits(mindts, maxdts, m_CurrentAudio.dts_end()); - UpdateLimits(mindts, maxdts, m_CurrentVideo.dts_end()); - - /* if we don't have max and min, we can't do anything more */ - if( mindts == DVD_NOPTS_VALUE || maxdts == DVD_NOPTS_VALUE ) - return; - - double correction = 0.0; - if( pPacket->dts > maxdts + DVD_MSEC_TO_TIME(1000)) - { - CLog::Log(LOGDEBUG, "CDVDPlayer::CheckContinuity - resync forward :%d, prev:%f, curr:%f, diff:%f" - , current.type, current.dts, pPacket->dts, pPacket->dts - maxdts); - correction = pPacket->dts - maxdts; - } - - /* if it's large scale jump, correct for it */ - if(pPacket->dts + DVD_MSEC_TO_TIME(100) < current.dts_end()) - { - CLog::Log(LOGDEBUG, "CDVDPlayer::CheckContinuity - resync backward :%d, prev:%f, curr:%f, diff:%f" - , current.type, current.dts, pPacket->dts, pPacket->dts - current.dts); - correction = pPacket->dts - current.dts_end(); - } - else if(pPacket->dts < current.dts) - { - CLog::Log(LOGDEBUG, "CDVDPlayer::CheckContinuity - wrapback :%d, prev:%f, curr:%f, diff:%f" - , current.type, current.dts, pPacket->dts, pPacket->dts - current.dts); - } - - if(correction != 0.0) - { - /* disable detection on next packet on other stream to avoid ping pong-ing */ - if(m_CurrentAudio.player != current.player) m_CurrentAudio.dts = DVD_NOPTS_VALUE; - if(m_CurrentVideo.player != current.player) m_CurrentVideo.dts = DVD_NOPTS_VALUE; - - m_offset_pts += correction; - UpdateCorrection(pPacket, correction); - } -} - -bool CDVDPlayer::CheckSceneSkip(CCurrentStream& current) -{ - if(!m_Edl.HasCut()) - return false; - - if(current.dts == DVD_NOPTS_VALUE) - return false; - - if(current.inited == false) - return false; - - CEdl::Cut cut; - return m_Edl.InCut(DVD_TIME_TO_MSEC(current.dts + m_offset_pts), &cut) && cut.action == CEdl::CUT; -} - -void CDVDPlayer::CheckAutoSceneSkip() -{ - if(!m_Edl.HasCut()) - return; - - /* - * Check that there is an audio and video stream. - */ - if(m_CurrentAudio.id < 0 - || m_CurrentVideo.id < 0) - return; - - /* - * If there is a startpts defined for either the audio or video stream then dvdplayer is still - * still decoding frames to get to the previously requested seek point. - */ - if(m_CurrentAudio.inited == false - || m_CurrentVideo.inited == false) - return; - - if(m_CurrentAudio.dts == DVD_NOPTS_VALUE - || m_CurrentVideo.dts == DVD_NOPTS_VALUE) - return; - - const int64_t clock = GetTime(); - - CEdl::Cut cut; - if(!m_Edl.InCut(clock, &cut)) - return; - - if(cut.action == CEdl::CUT - && !(cut.end == m_EdlAutoSkipMarkers.cut || cut.start == m_EdlAutoSkipMarkers.cut)) // To prevent looping if same cut again - { - CLog::Log(LOGDEBUG, "%s - Clock in EDL cut [%s - %s]: %s. Automatically skipping over.", - __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), - CEdl::MillisecondsToTimeString(cut.end).c_str(), CEdl::MillisecondsToTimeString(clock).c_str()); - /* - * Seeking either goes to the start or the end of the cut depending on the play direction. - */ - int64_t seek = GetPlaySpeed() >= 0 ? cut.end : cut.start; - /* - * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards. - */ - m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, true, true, false, true)); - /* - * Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping - * if there was an error with seeking and it landed somewhere unexpected, perhaps back in the - * cut. The cut automatic skip marker is reset every 500ms allowing another attempt at the seek. - */ - m_EdlAutoSkipMarkers.cut = GetPlaySpeed() >= 0 ? cut.end : cut.start; - } - else if(cut.action == CEdl::COMM_BREAK - && GetPlaySpeed() >= 0 - && cut.start > m_EdlAutoSkipMarkers.commbreak_end) - { - CLog::Log(LOGDEBUG, "%s - Clock in commercial break [%s - %s]: %s. Automatically skipping to end of commercial break (only done once per break)", - __FUNCTION__, CEdl::MillisecondsToTimeString(cut.start).c_str(), CEdl::MillisecondsToTimeString(cut.end).c_str(), - CEdl::MillisecondsToTimeString(clock).c_str()); - /* - * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards. - */ - m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, true, true, false, true)); - /* - * Each commercial break is only skipped once so poorly detected commercial breaks can be - * manually re-entered. Start and end are recorded to prevent looping and to allow seeking back - * to the start of the commercial break if incorrectly flagged. - */ - m_EdlAutoSkipMarkers.commbreak_start = cut.start; - m_EdlAutoSkipMarkers.commbreak_end = cut.end; - m_EdlAutoSkipMarkers.seek_to_start = true; // Allow backwards Seek() to go directly to the start - } -} - - -void CDVDPlayer::SynchronizeDemuxer(unsigned int timeout) -{ - if(IsCurrentThread()) - return; - if(!m_messenger.IsInited()) - return; - - CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, 0); - m_messenger.Put(message->Acquire()); - message->Wait(&m_bStop, 0); - message->Release(); -} - -void CDVDPlayer::SynchronizePlayers(unsigned int sources) -{ - /* we need a big timeout as audio queue is about 8seconds for 2ch ac3 */ - const int timeout = 10*1000; // in milliseconds - - CDVDMsgGeneralSynchronize* message = new CDVDMsgGeneralSynchronize(timeout, sources); - if (m_CurrentAudio.id >= 0) - m_dvdPlayerAudio.SendMessage(message->Acquire()); - - if (m_CurrentVideo.id >= 0) - m_dvdPlayerVideo.SendMessage(message->Acquire()); -/* TODO - we have to rewrite the sync class, to not require - all other players waiting for subtitle, should only - be the oposite way - if (m_CurrentSubtitle.id >= 0) - m_dvdPlayerSubtitle.SendMessage(message->Acquire()); -*/ - message->Release(); -} - -IDVDStreamPlayer* CDVDPlayer::GetStreamPlayer(unsigned int target) -{ - if(target == DVDPLAYER_AUDIO) - return &m_dvdPlayerAudio; - if(target == DVDPLAYER_VIDEO) - return &m_dvdPlayerVideo; - if(target == DVDPLAYER_SUBTITLE) - return &m_dvdPlayerSubtitle; - if(target == DVDPLAYER_TELETEXT) - return &m_dvdPlayerTeletext; - return NULL; -} - -void CDVDPlayer::SendPlayerMessage(CDVDMsg* pMsg, unsigned int target) -{ - IDVDStreamPlayer* player = GetStreamPlayer(target); - if(player) - player->SendMessage(pMsg, 0); -} - -void CDVDPlayer::OnExit() -{ - CLog::Log(LOGNOTICE, "CDVDPlayer::OnExit()"); - - // set event to inform openfile something went wrong in case openfile is still waiting for this event - SetCaching(CACHESTATE_DONE); - - // close each stream - if (!m_bAbortRequest) CLog::Log(LOGNOTICE, "DVDPlayer: eof, waiting for queues to empty"); - CloseStream(m_CurrentAudio, !m_bAbortRequest); - CloseStream(m_CurrentVideo, !m_bAbortRequest); - CloseStream(m_CurrentSubtitle, !m_bAbortRequest); - CloseStream(m_CurrentTeletext, !m_bAbortRequest); - - // destroy objects - SAFE_DELETE(m_pDemuxer); - SAFE_DELETE(m_pSubtitleDemuxer); - SAFE_DELETE(m_pInputStream); - - // clean up all selection streams - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NONE); - - m_messenger.End(); - - m_av_clock.OMXStop(); - m_av_clock.OMXStateIdle(); - - m_av_clock.OMXDeinitialize(); - - m_bStop = true; - // if we didn't stop playing, advance to the next item in xbmc's playlist - if(m_PlayerOptions.identify == false) - { - if (m_bAbortRequest) - m_callback.OnPlayBackStopped(); - else - m_callback.OnPlayBackEnded(); - } - - // set event to inform openfile something went wrong in case openfile is still waiting for this event - m_ready.Set(); -} - -void CDVDPlayer::HandleMessages() -{ - CDVDMsg* pMsg; - - while (m_messenger.Get(&pMsg, 0) == MSGQ_OK) - { - - if (pMsg->IsType(CDVDMsg::PLAYER_SEEK) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK) == 0 - && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK_CHAPTER) == 0) - { - CDVDMsgPlayerSeek &msg(*((CDVDMsgPlayerSeek*)pMsg)); - - if (!m_State.canseek) - { - pMsg->Release(); - continue; - } - - if(!msg.GetTrickPlay()) - { - g_infoManager.SetDisplayAfterSeek(100000); - } - if(msg.GetFlush()) - SetCaching(CACHESTATE_FLUSH); - - double start = DVD_NOPTS_VALUE; - - int time = msg.GetRestore() ? (int)m_Edl.RestoreCutTime(msg.GetTime()) : msg.GetTime(); - - // if input streams doesn't support seektime we must convert back to clock - if(dynamic_cast<CDVDInputStream::ISeekTime*>(m_pInputStream) == NULL) - time -= DVD_TIME_TO_MSEC(m_State.time_offset - m_offset_pts); - - CLog::Log(LOGDEBUG, "demuxer seek to: %d", time); - if (m_pDemuxer && m_pDemuxer->SeekTime(time, msg.GetBackward(), &start)) - { - CLog::Log(LOGDEBUG, "demuxer seek to: %.0f, success", start); - if(m_pSubtitleDemuxer) - { - if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward())) - CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time); - } - // dts after successful seek - if (m_StateInput.time_src == ETIMESOURCE_CLOCK && start == DVD_NOPTS_VALUE) - m_StateInput.dts = DVD_MSEC_TO_TIME(time); - else - m_StateInput.dts = start; - - FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate()); - // mark mediatime as invalid - m_av_clock.OMXMediaTime(0.0); - m_last_check_time = 0.0; - } - else - CLog::Log(LOGWARNING, "error while seeking"); - - // set flag to indicate we have finished a seeking request - if(!msg.GetTrickPlay()) - g_infoManager.SetDisplayAfterSeek(); - - // dvd's will issue a HOP_CHANNEL that we need to skip - if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - m_dvd.state = DVDSTATE_SEEK; - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SEEK_CHAPTER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK) == 0 - && m_messenger.GetPacketCount(CDVDMsg::PLAYER_SEEK_CHAPTER) == 0) - { - g_infoManager.SetDisplayAfterSeek(100000); - SetCaching(CACHESTATE_FLUSH); - - CDVDMsgPlayerSeekChapter &msg(*((CDVDMsgPlayerSeekChapter*)pMsg)); - double start = DVD_NOPTS_VALUE; - - // This should always be the case. - if(m_pDemuxer && m_pDemuxer->SeekChapter(msg.GetChapter(), &start)) - { - FlushBuffers(false, start, true); - // mark mediatime as invalid - m_av_clock.OMXMediaTime(0.0); - - m_callback.OnPlayBackSeekChapter(msg.GetChapter()); - } - - g_infoManager.SetDisplayAfterSeek(); - } - else if (pMsg->IsType(CDVDMsg::DEMUXER_RESET)) - { - m_CurrentAudio.stream = NULL; - m_CurrentVideo.stream = NULL; - m_CurrentSubtitle.stream = NULL; - - // we need to reset the demuxer, probably because the streams have changed - if(m_pDemuxer) - m_pDemuxer->Reset(); - if(m_pSubtitleDemuxer) - m_pSubtitleDemuxer->Reset(); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SET_AUDIOSTREAM)) - { - CDVDMsgPlayerSetAudioStream* pMsg2 = (CDVDMsgPlayerSetAudioStream*)pMsg; - - SelectionStream& st = m_SelectionStreams.Get(STREAM_AUDIO, pMsg2->GetStreamId()); - if(st.source != STREAM_SOURCE_NONE) - { - if(st.source == STREAM_SOURCE_NAV && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream; - if(pStream->SetActiveAudioStream(st.id)) - { - m_dvd.iSelectedAudioStream = -1; - CloseStream(m_CurrentAudio, false); - m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true)); - } - } - else - { - CloseStream(m_CurrentAudio, false); - OpenStream(m_CurrentAudio, st.id, st.source); - AdaptForcedSubtitles(); - m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true)); - } - } - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SET_SUBTITLESTREAM)) - { - CDVDMsgPlayerSetSubtitleStream* pMsg2 = (CDVDMsgPlayerSetSubtitleStream*)pMsg; - - SelectionStream& st = m_SelectionStreams.Get(STREAM_SUBTITLE, pMsg2->GetStreamId()); - if(st.source != STREAM_SOURCE_NONE) - { - if(st.source == STREAM_SOURCE_NAV && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream; - if(pStream->SetActiveSubtitleStream(st.id)) - { - m_dvd.iSelectedSPUStream = -1; - CloseStream(m_CurrentSubtitle, false); - } - } - else - { - CloseStream(m_CurrentSubtitle, false); - OpenStream(m_CurrentSubtitle, st.id, st.source); - } - } - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SET_SUBTITLESTREAM_VISIBLE)) - { - CDVDMsgBool* pValue = (CDVDMsgBool*)pMsg; - SetSubtitleVisibleInternal(pValue->m_value); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SET_STATE)) - { - g_infoManager.SetDisplayAfterSeek(100000); - SetCaching(CACHESTATE_FLUSH); - - CDVDMsgPlayerSetState* pMsgPlayerSetState = (CDVDMsgPlayerSetState*)pMsg; - - if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) - { - if(ptr->SetState(pMsgPlayerSetState->GetState())) - { - m_dvd.state = DVDSTATE_NORMAL; - m_dvd.iDVDStillStartTime = 0; - m_dvd.iDVDStillTime = 0; - } - } - - g_infoManager.SetDisplayAfterSeek(); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SET_RECORD)) - { - CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream); - if(input) - input->Record(*(CDVDMsgBool*)pMsg); - } - else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) - { - FlushBuffers(false); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) - { - int speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; - - // correct our current clock, as it would start going wrong otherwise - if(m_State.timestamp > 0) - { - double offset; - offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; - offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; - if(offset > 1000) offset = 1000; - if(offset < -1000) offset = -1000; - m_State.time += DVD_TIME_TO_MSEC(offset); - m_State.timestamp = CDVDClock::GetAbsoluteClock(); - } - - if (speed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_PAUSE && speed != m_playSpeed) - m_callback.OnPlayBackSpeedChanged(speed / DVD_PLAYSPEED_NORMAL); - - if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && speed != m_playSpeed) - { - CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream); - pvrinputstream->Pause( speed == 0 ); - } - - // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE - // audioplayer, stops outputing audio to audiorendere, but still tries to - // sleep an correct amount for each packet - // videoplayer just plays faster after the clock speed has been increased - // 1. disable audio - // 2. skip frames and adjust their pts or the clock - - // when switching from trickplay to normal, we may not have a full set of reference frames - // in decoder and we may get corrupt frames out. Seeking to current time will avoid this. - if ( TP(speed) || TP(m_playSpeed) || - ( (speed == DVD_PLAYSPEED_PAUSE || speed == DVD_PLAYSPEED_NORMAL) && - (m_playSpeed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_NORMAL) ) ) - m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), (speed < 0), true, false, false, true)); - - m_playSpeed = speed; - m_caching = CACHESTATE_DONE; - m_clock.SetSpeed(speed); - m_av_clock.OMXSetSpeed(speed); - m_av_clock.OMXPause(); - m_dvdPlayerAudio.SetSpeed(speed); - m_dvdPlayerVideo.SetSpeed(speed); - - // We can't pause demuxer until our buffers are full. Doing so will result in continued - // calls to Read() which may then block indefinitely (CDVDInputStreamRTMP for example). - if(m_pDemuxer) - { - m_DemuxerPausePending = (speed == DVD_PLAYSPEED_PAUSE); - if (!m_DemuxerPausePending) - m_pDemuxer->SetSpeed(speed); - } - CLog::Log(LOGDEBUG, "CDVDPlayer - CDVDMsg::PLAYER_SETSPEED speed : %d", speed); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) == 0) - { - FlushBuffers(false); - CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream); - if(input && input->SelectChannelByNumber(static_cast<CDVDMsgInt*>(pMsg)->m_value)) - { - SAFE_DELETE(m_pDemuxer); - }else - { - CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__); - CApplicationMessenger::Get().MediaStop(false); - } - } - else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT) == 0) - { - FlushBuffers(false); - CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream); - if(input && input->SelectChannel(static_cast<CDVDMsgType <CPVRChannel> *>(pMsg)->m_value)) - { - SAFE_DELETE(m_pDemuxer); - }else - { - CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__); - CApplicationMessenger::Get().MediaStop(false); - } - } - else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT) || pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_PREV)) - { - CDVDInputStream::IChannel* input = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream); - if(input) - { - bool bSwitchSuccessful(false); - bool bShowPreview(CSettings::Get().GetInt("pvrplayback.channelentrytimeout") > 0); - - if (!bShowPreview) - { - g_infoManager.SetDisplayAfterSeek(100000); - FlushBuffers(false); - } - - if(pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT)) - bSwitchSuccessful = input->NextChannel(bShowPreview); - else - bSwitchSuccessful = input->PrevChannel(bShowPreview); - - if(bSwitchSuccessful) - { - if (bShowPreview) - { - UpdateApplication(0); - m_ChannelEntryTimeOut.Set(CSettings::Get().GetInt("pvrplayback.channelentrytimeout")); - } - else - { - m_ChannelEntryTimeOut.SetInfinite(); - SAFE_DELETE(m_pDemuxer); - - g_infoManager.SetDisplayAfterSeek(); - } - } - else - { - CLog::Log(LOGWARNING, "%s - failed to switch channel. playback stopped", __FUNCTION__); - CApplicationMessenger::Get().MediaStop(false); - } - } - } - else if (pMsg->IsType(CDVDMsg::GENERAL_GUI_ACTION)) - OnAction(((CDVDMsgType<CAction>*)pMsg)->m_value); - else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) - { - int player = ((CDVDMsgInt*)pMsg)->m_value; - if(player == DVDPLAYER_AUDIO) - m_CurrentAudio.started = true; - if(player == DVDPLAYER_VIDEO) - m_CurrentVideo.started = true; - - if ((player == DVDPLAYER_AUDIO || player == DVDPLAYER_VIDEO) && - (TPA(m_playSpeed) || !m_HasAudio || m_CurrentAudio.started) && - (!m_HasVideo || m_CurrentVideo.started)) - { - CLog::Log(LOGDEBUG, "CDVDPlayer::HandleMessages - player started RESET"); - m_av_clock.OMXReset(m_HasVideo, m_playSpeed != DVD_PLAYSPEED_NORMAL && m_playSpeed != DVD_PLAYSPEED_PAUSE ? false:m_HasAudio); - } - - CLog::Log(LOGDEBUG, "CDVDPlayer::HandleMessages - player started %d (tpa:%d,a:%d,v:%d)", player, TPA(m_playSpeed), m_CurrentAudio.started, m_CurrentVideo.started); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) - { - CDVDPlayer::SPlayerState& state = ((CDVDMsgType<CDVDPlayer::SPlayerState>*)pMsg)->m_value; - - CSingleLock lock(m_StateSection); - /* prioritize data from video player, but only accept data * - * after it has been started to avoid race conditions after seeks */ - if(m_CurrentVideo.started && !m_dvdPlayerVideo.SubmittedEOS()) - { - if(state.player == DVDPLAYER_VIDEO) - m_State = state; - } - else if(m_CurrentAudio.started) - { - if(state.player == DVDPLAYER_AUDIO) - m_State = state; - } - } - - pMsg->Release(); - } - -} - -void CDVDPlayer::SetCaching(ECacheState state) -{ - if(state == CACHESTATE_FLUSH) - { - double level, delay, offset; - if(GetCachingTimes(level, delay, offset)) - state = CACHESTATE_FULL; - else - state = CACHESTATE_INIT; - } - - if(m_caching == state) - return; - - CLog::Log(LOGDEBUG, "CDVDPlayer::SetCaching - caching state %d", state); - if(state == CACHESTATE_FULL - || state == CACHESTATE_INIT - || state == CACHESTATE_PVR) - { - m_clock.SetSpeed(DVD_PLAYSPEED_PAUSE); - m_av_clock.OMXPause(); - m_dvdPlayerAudio.SetSpeed(DVD_PLAYSPEED_PAUSE); - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); - m_dvdPlayerVideo.SetSpeed(DVD_PLAYSPEED_PAUSE); - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); - - if (state == CACHESTATE_PVR) - m_pInputStream->ResetScanTimeout((unsigned int) CSettings::Get().GetInt("pvrplayback.scantime") * 1000); - } - - if(state == CACHESTATE_PLAY - ||(state == CACHESTATE_DONE && m_caching != CACHESTATE_PLAY)) - { - m_clock.SetSpeed(m_playSpeed); - m_dvdPlayerAudio.SetSpeed(m_playSpeed); - m_dvdPlayerVideo.SetSpeed(m_playSpeed); - m_pInputStream->ResetScanTimeout(0); - } - m_caching = state; -} - -void CDVDPlayer::SetPlaySpeed(int speed) -{ - m_messenger.Put(new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed)); - m_dvdPlayerAudio.SetSpeed(speed); - m_dvdPlayerVideo.SetSpeed(speed); - SynchronizeDemuxer(100); -} - -bool CDVDPlayer::CanPause() -{ - CSingleLock lock(m_StateSection); - return m_State.canpause; -} - -void CDVDPlayer::Pause() -{ - CSingleLock lock(m_StateSection); - if (!m_State.canpause) - return; - lock.Leave(); - - if(m_playSpeed != DVD_PLAYSPEED_PAUSE && IsCaching()) - { - SetCaching(CACHESTATE_DONE); - return; - } - - // return to normal speed if it was paused before, pause otherwise - if (m_playSpeed == DVD_PLAYSPEED_PAUSE) - { - SetPlaySpeed(DVD_PLAYSPEED_NORMAL); - m_callback.OnPlayBackResumed(); - } - else - { - SetPlaySpeed(DVD_PLAYSPEED_PAUSE); - m_callback.OnPlayBackPaused(); - } -} - -bool CDVDPlayer::IsPaused() const -{ - return m_playSpeed == DVD_PLAYSPEED_PAUSE || IsCaching(); -} - -bool CDVDPlayer::HasVideo() const -{ - return m_HasVideo; -} - -bool CDVDPlayer::HasAudio() const -{ - return m_HasAudio; -} - -bool CDVDPlayer::IsPassthrough() const -{ - return m_dvdPlayerAudio.IsPassthrough(); -} - -bool CDVDPlayer::CanSeek() -{ - CSingleLock lock(m_StateSection); - return m_State.canseek; -} - -void CDVDPlayer::Seek(bool bPlus, bool bLargeStep, bool bChapterOverride) -{ - // Single step - if( m_playSpeed == DVD_PLAYSPEED_PAUSE && bPlus && !bLargeStep) - { - m_av_clock.OMXStep(); - return; - } - - if (!m_State.canseek) - return; - - if (bLargeStep && bChapterOverride && GetChapter() > 0) - { - if (!bPlus) - { - SeekChapter(GetChapter() - 1); - return; - } - else if (GetChapter() < GetChapterCount()) - { - SeekChapter(GetChapter() + 1); - return; - } - } - - int64_t seek; - if (g_advancedSettings.m_videoUseTimeSeeking && GetTotalTime() > 2000*g_advancedSettings.m_videoTimeSeekForwardBig) - { - if (bLargeStep) - seek = bPlus ? g_advancedSettings.m_videoTimeSeekForwardBig : g_advancedSettings.m_videoTimeSeekBackwardBig; - else - seek = bPlus ? g_advancedSettings.m_videoTimeSeekForward : g_advancedSettings.m_videoTimeSeekBackward; - seek *= 1000; - seek += GetTime(); - } - else - { - float percent; - if (bLargeStep) - percent = bPlus ? g_advancedSettings.m_videoPercentSeekForwardBig : g_advancedSettings.m_videoPercentSeekBackwardBig; - else - percent = bPlus ? g_advancedSettings.m_videoPercentSeekForward : g_advancedSettings.m_videoPercentSeekBackward; - seek = (int64_t)(GetTotalTimeInMsec()*(GetPercentage()+percent)/100); - } - - bool restore = true; - if (m_Edl.HasCut()) - { - /* - * Alter the standard seek position based on whether any commercial breaks have been - * automatically skipped. - */ - const int clock = DVD_TIME_TO_MSEC(m_clock.GetClock()); - /* - * If a large backwards seek occurs within 10 seconds of the end of the last automated - * commercial skip, then seek back to the start of the commercial break under the assumption - * it was flagged incorrectly. 10 seconds grace period is allowed in case the watcher has to - * fumble around finding the remote. Only happens once per commercial break. - * - * Small skip does not trigger this in case the start of the commercial break was in fact fine - * but it skipped too far into the program. In that case small skip backwards behaves as normal. - */ - if (!bPlus && bLargeStep - && m_EdlAutoSkipMarkers.seek_to_start - && clock >= m_EdlAutoSkipMarkers.commbreak_end - && clock <= m_EdlAutoSkipMarkers.commbreak_end + 10*1000) // Only if within 10 seconds of the end (in msec) - { - 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).", - __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(), - CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str()); - seek = m_EdlAutoSkipMarkers.commbreak_start; - restore = false; - m_EdlAutoSkipMarkers.seek_to_start = false; // So this will only happen within the 10 second grace period once. - } - /* - * If big skip forward within the last "reverted" commercial break, seek to the end of the - * commercial break under the assumption that the break was incorrectly flagged and playback has - * now reached the actual start of the commercial break. Assume that the end is flagged more - * correctly than the landing point for a standard big skip (ends seem to be flagged more - * accurately than the start). - */ - else if (bPlus && bLargeStep - && clock >= m_EdlAutoSkipMarkers.commbreak_start - && clock <= m_EdlAutoSkipMarkers.commbreak_end) - { - CLog::Log(LOGDEBUG, "%s - Seeking to end of previously skipped commercial break [%s - %s] as big forwards skip activated within the break.", - __FUNCTION__, CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_start).c_str(), - CEdl::MillisecondsToTimeString(m_EdlAutoSkipMarkers.commbreak_end).c_str()); - seek = m_EdlAutoSkipMarkers.commbreak_end; - restore = false; - } - } - - int64_t time = GetTime(); - if(g_application.CurrentFileItem().IsStack() - && (seek > GetTotalTimeInMsec() || seek < 0)) - { - g_application.SeekTime((seek - time) * 0.001 + g_application.GetTime()); - // warning, don't access any dvdplayer variables here as - // the dvdplayer object may have been destroyed - return; - } - - m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, !bPlus, true, false, restore)); - SynchronizeDemuxer(100); - if (seek < 0) seek = 0; - m_callback.OnPlayBackSeek((int)seek, (int)(seek - time)); -} - -bool CDVDPlayer::SeekScene(bool bPlus) -{ - if (!m_Edl.HasSceneMarker()) - return false; - - /* - * There is a 5 second grace period applied when seeking for scenes backwards. If there is no - * grace period applied it is impossible to go backwards past a scene marker. - */ - int64_t clock = GetTime(); - if (!bPlus && clock > 5 * 1000) // 5 seconds - clock -= 5 * 1000; - - int iScenemarker; - if (m_Edl.GetNextSceneMarker(bPlus, clock, &iScenemarker)) - { - /* - * Seeking is flushed and inaccurate, just like Seek() - */ - m_messenger.Put(new CDVDMsgPlayerSeek(iScenemarker, !bPlus, true, false, false)); - SynchronizeDemuxer(100); - return true; - } - return false; -} - -void CDVDPlayer::GetAudioInfo(std::string &strAudioInfo) -{ - { CSingleLock lock(m_StateSection); - strAudioInfo = StringUtils::Format("D(%s)", m_StateInput.demux_audio.c_str()); - } - strAudioInfo += StringUtils::Format("\nP(%s)", m_dvdPlayerAudio.GetPlayerInfo().c_str()); -} - -void CDVDPlayer::GetVideoInfo(std::string& strVideoInfo) -{ - { CSingleLock lock(m_StateSection); - strVideoInfo = StringUtils::Format("D(%s)", m_StateInput.demux_video.c_str()); - } - strVideoInfo += StringUtils::Format("\nP(%s)", m_dvdPlayerVideo.GetPlayerInfo().c_str()); -} - -void CDVDPlayer::GetGeneralInfo(std::string& strGeneralInfo) -{ - if (!m_bStop) - { - double dDelay = m_dvdPlayerAudio.GetDelay(); - - double apts = m_dvdPlayerAudio.GetCurrentPts(); - double vpts = m_dvdPlayerVideo.GetCurrentPts(); - double dDiff = 0; - - if( apts != DVD_NOPTS_VALUE && vpts != DVD_NOPTS_VALUE ) - dDiff = (apts - vpts) / DVD_TIME_BASE; - - std::string strEDL = StringUtils::Format(", edl:%s", m_Edl.GetInfo().c_str()); - - std::string strBuf; - CSingleLock lock(m_StateSection); - if(m_StateInput.cache_bytes >= 0) - { - strBuf += StringUtils::Format(" cache:%s %2.0f%%" - , StringUtils::SizeToString(m_State.cache_bytes).c_str() - , m_State.cache_level * 100); - if(m_playSpeed == 0 || m_caching == CACHESTATE_FULL) - strBuf += StringUtils::Format(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay)); - } - - strGeneralInfo = StringUtils::Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s af:%d%% vf:%d%% amp:% 5.2f )" - , dDelay - , dDiff - , strEDL.c_str() - , (int)(CThread::GetRelativeUsage()*100) - , (int)(m_dvdPlayerAudio.GetRelativeUsage()*100) - , (int)(m_dvdPlayerVideo.GetRelativeUsage()*100) - , strBuf.c_str() - , m_audio_fifo - , m_video_fifo - , m_dvdPlayerAudio.GetDynamicRangeAmplification()); - - } -} - -void CDVDPlayer::SeekPercentage(float iPercent) -{ - int64_t iTotalTime = GetTotalTimeInMsec(); - - if (!iTotalTime) - return; - - SeekTime((int64_t)(iTotalTime * iPercent / 100)); -} - -float CDVDPlayer::GetPercentage() -{ - int64_t iTotalTime = GetTotalTimeInMsec(); - - if (!iTotalTime) - return 0.0f; - - return GetTime() * 100 / (float)iTotalTime; -} - -float CDVDPlayer::GetCachePercentage() -{ - CSingleLock lock(m_StateSection); - return m_StateInput.cache_offset * 100; // NOTE: Percentage returned is relative -} - -void CDVDPlayer::SetAVDelay(float fValue) -{ - m_dvdPlayerVideo.SetDelay( (fValue * DVD_TIME_BASE) ) ; -} - -float CDVDPlayer::GetAVDelay() -{ - return m_dvdPlayerVideo.GetDelay() / (float)DVD_TIME_BASE; -} - -void CDVDPlayer::SetSubTitleDelay(float fValue) -{ - m_dvdPlayerVideo.SetSubtitleDelay(-fValue * DVD_TIME_BASE); -} - -float CDVDPlayer::GetSubTitleDelay() -{ - return -m_dvdPlayerVideo.GetSubtitleDelay() / DVD_TIME_BASE; -} - -// priority: 1: libdvdnav, 2: external subtitles, 3: muxed subtitles -int CDVDPlayer::GetSubtitleCount() -{ - return m_SelectionStreams.Count(STREAM_SUBTITLE); -} - -int CDVDPlayer::GetSubtitle() -{ - return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, *this); -} - -void CDVDPlayer::GetSubtitleStreamInfo(int index, SPlayerSubtitleStreamInfo &info) -{ - if (index < 0 || index > (int) GetSubtitleCount() - 1) - return; - - SelectionStream& s = m_SelectionStreams.Get(STREAM_SUBTITLE, index); - if(s.name.length() > 0) - info.name = s.name; - - if(s.type == STREAM_NONE) - info.name += "(Invalid)"; - - info.language = s.language; -} - -void CDVDPlayer::SetSubtitle(int iStream) -{ - CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = iStream; - m_messenger.Put(new CDVDMsgPlayerSetSubtitleStream(iStream)); -} - -bool CDVDPlayer::GetSubtitleVisible() -{ - if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream; - if(pStream->IsInMenu()) - return CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn; - else - return pStream->IsSubtitleStreamEnabled(); - } - - return m_dvdPlayerVideo.IsSubtitleEnabled(); -} - -void CDVDPlayer::SetSubtitleVisible(bool bVisible) -{ - CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn = bVisible; - m_messenger.Put(new CDVDMsgBool(CDVDMsg::PLAYER_SET_SUBTITLESTREAM_VISIBLE, bVisible)); -} - -void CDVDPlayer::SetSubtitleVisibleInternal(bool bVisible) -{ - CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn = bVisible; - m_dvdPlayerVideo.EnableSubtitle(bVisible); - - if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->EnableSubtitleStream(bVisible); -} - -int CDVDPlayer::GetAudioStreamCount() -{ - return m_SelectionStreams.Count(STREAM_AUDIO); -} - -int CDVDPlayer::GetAudioStream() -{ - return m_SelectionStreams.IndexOf(STREAM_AUDIO, *this); -} - -void CDVDPlayer::SetAudioStream(int iStream) -{ - CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = iStream; - m_messenger.Put(new CDVDMsgPlayerSetAudioStream(iStream)); - SynchronizeDemuxer(100); -} - -TextCacheStruct_t* CDVDPlayer::GetTeletextCache() -{ - if (m_CurrentTeletext.id < 0) - return 0; - - return m_dvdPlayerTeletext.GetTeletextCache(); -} - -void CDVDPlayer::LoadPage(int p, int sp, unsigned char* buffer) -{ - if (m_CurrentTeletext.id < 0) - return; - - return m_dvdPlayerTeletext.LoadPage(p, sp, buffer); -} - -void CDVDPlayer::SeekTime(int64_t iTime) -{ - int seekOffset = (int)(iTime - GetTime()); - m_messenger.Put(new CDVDMsgPlayerSeek((int)iTime, true, true, true)); - SynchronizeDemuxer(100); - m_callback.OnPlayBackSeek((int)iTime, seekOffset); -} - -// return the time in milliseconds -int64_t CDVDPlayer::GetTime() -{ - CSingleLock lock(m_StateSection); - double offset = 0; - const double limit = DVD_MSEC_TO_TIME(200); - if(m_State.timestamp > 0) - { - offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; - offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; - if(offset > limit) offset = limit; - if(offset < -limit) offset = -limit; - } - //{CLog::Log(LOGINFO, "%s: time:%.2f stamp:%.2f dts:%d m:%d (p:%d,c:%d) =%llu", __func__, (double)m_State.time, (double)m_State.timestamp, (int)DVD_TIME_TO_MSEC(m_State.dts + m_offset_pts), (int)DVD_TIME_TO_MSEC(m_stamp), (int)m_playSpeed, (int)m_caching, llrint(m_State.time + DVD_TIME_TO_MSEC(offset)));} - return llrint(m_State.time + DVD_TIME_TO_MSEC(offset)); -} - -// return length in msec -int64_t CDVDPlayer::GetTotalTimeInMsec() -{ - CSingleLock lock(m_StateSection); - return llrint(m_State.time_total); -} - -// return length in seconds.. this should be changed to return in milleseconds throughout xbmc -int64_t CDVDPlayer::GetTotalTime() -{ - return GetTotalTimeInMsec(); -} - -void CDVDPlayer::ToFFRW(int iSpeed) -{ - // can't rewind in menu as seeking isn't possible - // forward is fine - if (iSpeed < 0 && IsInMenu()) return; - SetPlaySpeed(iSpeed * DVD_PLAYSPEED_NORMAL); -} - -bool CDVDPlayer::OpenStream(CCurrentStream& current, int iStream, int source, bool reset) -{ - CDemuxStream* stream = NULL; - CDVDStreamInfo hint; - - CLog::Log(LOGNOTICE, "Opening stream: %i source: %i", iStream, source); - - if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_DEMUX_SUB) - { - int index = m_SelectionStreams.IndexOf(current.type, source, iStream); - if(index < 0) - return false; - SelectionStream st = m_SelectionStreams.Get(current.type, index); - - if(!m_pSubtitleDemuxer || m_pSubtitleDemuxer->GetFileName() != st.filename) - { - CLog::Log(LOGNOTICE, "Opening Subtitle file: %s", st.filename.c_str()); - auto_ptr<CDVDDemuxVobsub> demux(new CDVDDemuxVobsub()); - if(!demux->Open(st.filename, st.filename2)) - return false; - m_pSubtitleDemuxer = demux.release(); - } - - double pts = m_dvdPlayerVideo.GetCurrentPts(); - if(pts == DVD_NOPTS_VALUE) - pts = m_CurrentVideo.dts; - if(pts == DVD_NOPTS_VALUE) - pts = 0; - pts += m_offset_pts; - m_pSubtitleDemuxer->SeekTime((int)(1000.0 * pts / (double)DVD_TIME_BASE)); - - stream = m_pSubtitleDemuxer->GetStream(iStream); - if(!stream || stream->disabled) - return false; - stream->SetDiscard(AVDISCARD_NONE); - - hint.Assign(*stream, true); - } - else if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_TEXT) - { - int index = m_SelectionStreams.IndexOf(current.type, source, iStream); - if(index < 0) - return false; - - hint.Clear(); - hint.filename = m_SelectionStreams.Get(current.type, index).filename; - hint.fpsscale = m_CurrentVideo.hint.fpsscale; - hint.fpsrate = m_CurrentVideo.hint.fpsrate; - } - else if(STREAM_SOURCE_MASK(source) == STREAM_SOURCE_DEMUX) - { - if(!m_pDemuxer) - return false; - - stream = m_pDemuxer->GetStream(iStream); - if(!stream || stream->disabled) - return false; - stream->SetDiscard(AVDISCARD_NONE); - - hint.Assign(*stream, true); - - if(m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - hint.filename = "dvd"; - } - - bool res; - switch(current.type) - { - case STREAM_AUDIO: - res = OpenAudioStream(hint, reset); - break; - case STREAM_VIDEO: - res = OpenVideoStream(hint, reset); - break; - case STREAM_SUBTITLE: - res = OpenSubtitleStream(hint); - break; - case STREAM_TELETEXT: - res = OpenTeletextStream(hint); - break; - default: - res = false; - break; - } - - if (res) - { - current.id = iStream; - current.source = source; - current.hint = hint; - current.stream = (void*)stream; - current.started = false; - if(stream) - current.changes = stream->changes; - - UpdateClockMaster(); - } - else - { - if(stream) - { - /* mark stream as disabled, to disallaw further attempts*/ - CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, stream->iId); - stream->disabled = true; - stream->SetDiscard(AVDISCARD_ALL); - } - } - - return res; -} - -bool CDVDPlayer::OpenStreamPlayer(CCurrentStream& current, CDVDStreamInfo& hint, bool reset) -{ - IDVDStreamPlayer* player = GetStreamPlayer(current.player); - if(player == NULL) - return false; - - if(current.id < 0 - || current.hint != hint) - { - if (!player->OpenStream( hint )) - return false; - } - else if (reset) - player->SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET), 0); - return true; -} - -bool CDVDPlayer::OpenAudioStream(CDVDStreamInfo& hint, bool reset) -{ - if(!OpenStreamPlayer(m_CurrentAudio, hint, reset)) - return false; - - m_HasAudio = true; - - /* we are potentially going to be waiting on this */ - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); - - /* audio normally won't consume full cpu, so let it have prio */ - m_dvdPlayerAudio.SetPriority(GetPriority()+1); - CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = GetAudioStream(); - return true; -} - -bool CDVDPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) -{ - if( m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) ) - { - /* set aspect ratio as requested by navigator for dvd's */ - float aspect = static_cast<CDVDInputStreamNavigator*>(m_pInputStream)->GetVideoAspectRatio(); - if(aspect != 0.0) - { - hint.aspect = aspect; - hint.forced_aspect = true; - } - hint.software = true; - } - - CDVDInputStream::IMenus* pMenus = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream); - if(pMenus && pMenus->IsInMenu()) - hint.stills = true; - - if (hint.stereo_mode.empty()) - hint.stereo_mode = CStereoscopicsManager::Get().DetectStereoModeByString(m_filename); - - if(hint.flags & AV_DISPOSITION_ATTACHED_PIC) - return false; - - if(!OpenStreamPlayer(m_CurrentVideo, hint, reset)) - return false; - - m_HasVideo = true; - - /* we are potentially going to be waiting on this */ - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); - -#if defined(TARGET_DARWIN) - // Apple thread scheduler works a little different than Linux. It - // will favor OS GUI side and can cause DVDPlayerVideo to miss frame - // updates when the OS gets busy. Apple's recomended method is to - // elevate time critical threads to SCHED_RR and OSX does this for - // the CoreAudio audio device handler thread. We do the same for - // the DVDPlayerVideo thread so it can run to sleep without getting - // swapped out by a busy OS. - m_dvdPlayerVideo.SetPriority(GetSchedRRPriority()); -#else - /* use same priority for video thread as demuxing thread, as */ - /* otherwise demuxer will starve if video consumes the full cpu */ - m_dvdPlayerVideo.SetPriority(GetPriority()); -#endif - return true; - -} - -bool CDVDPlayer::OpenSubtitleStream(CDVDStreamInfo& hint) -{ - if(!OpenStreamPlayer(m_CurrentSubtitle, hint, true)) - return false; - - CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = GetSubtitle(); - return true; -} - -bool CDVDPlayer::AdaptForcedSubtitles() -{ - bool valid = false; - SelectionStream ss = m_SelectionStreams.Get(STREAM_SUBTITLE, GetSubtitle()); - if (ss.flags & CDemuxStream::FLAG_FORCED || !GetSubtitleVisible()) - { - SelectionStream as = m_SelectionStreams.Get(STREAM_AUDIO, GetAudioStream()); - SelectionStreams streams = m_SelectionStreams.Get(STREAM_SUBTITLE); - - for(SelectionStreams::iterator it = streams.begin(); it != streams.end() && !valid; ++it) - { - if (it->flags & CDemuxStream::FLAG_FORCED && g_LangCodeExpander.CompareLangCodes(it->language, as.language)) - { - if(OpenStream(m_CurrentSubtitle, it->id, it->source)) - { - valid = true; - SetSubtitleVisibleInternal(true); - } - } - } - if(!valid) - { - CloseStream(m_CurrentSubtitle, true); - SetSubtitleVisibleInternal(false); - } - } - return valid; -} - -bool CDVDPlayer::OpenTeletextStream(CDVDStreamInfo& hint) -{ - if (!m_dvdPlayerTeletext.CheckStream(hint)) - return false; - - if(!OpenStreamPlayer(m_CurrentTeletext, hint, true)) - return false; - - return true; -} - -bool CDVDPlayer::CloseStream(CCurrentStream& current, bool bWaitForBuffers) -{ - if (current.id < 0) - return false; - - CLog::Log(LOGNOTICE, "Closing stream player %d", current.player); - - if(bWaitForBuffers) - SetCaching(CACHESTATE_DONE); - - IDVDStreamPlayer* player = GetStreamPlayer(current.player); - if(player) - player->CloseStream(bWaitForBuffers); - - current.Clear(); - UpdateClockMaster(); - return true; -} - -void CDVDPlayer::UpdateClockMaster() -{ - EMasterClock clock; - if(m_CurrentAudio.id >= 0) - { - if(m_CurrentVideo.id >= 0 && g_VideoReferenceClock.GetRefreshRate() > 0) - clock = MASTER_CLOCK_AUDIO_VIDEOREF; - else - clock = MASTER_CLOCK_AUDIO; - } - else if(m_CurrentVideo.id >= 0) - clock = MASTER_CLOCK_VIDEO; - else - clock = MASTER_CLOCK_NONE; - - if (m_clock.GetMaster() != clock) - { - /* the new clock should be somewhat in sync with old */ - if (clock == MASTER_CLOCK_AUDIO - || clock == MASTER_CLOCK_AUDIO_VIDEOREF) - SynchronizePlayers(SYNCSOURCE_AUDIO); - - m_clock.SetMaster(clock); - } -} - -void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) -{ - double startpts; - - CLog::Log(LOGNOTICE, "FlushBuffers: q:%d pts:%.0f a:%d", queued, pts, accurate); - - if (!TP(m_playSpeed)) - m_av_clock.OMXStop(); - m_av_clock.OMXPause(); - m_stepped = false; - - /* for now, ignore accurate flag as it discards keyframes and causes corrupt frames */ - if(0 && accurate) - startpts = pts; - else - startpts = DVD_NOPTS_VALUE; - - /* call with demuxer pts */ - if(startpts != DVD_NOPTS_VALUE) - startpts -= m_offset_pts; - - m_CurrentAudio.inited = false; - m_CurrentAudio.dts = DVD_NOPTS_VALUE; - m_CurrentAudio.startpts = startpts; - - m_CurrentVideo.inited = false; - m_CurrentVideo.dts = DVD_NOPTS_VALUE; - m_CurrentVideo.startpts = startpts; - - m_CurrentSubtitle.inited = false; - m_CurrentSubtitle.dts = DVD_NOPTS_VALUE; - m_CurrentSubtitle.startpts = startpts; - - m_CurrentTeletext.inited = false; - m_CurrentTeletext.dts = DVD_NOPTS_VALUE; - m_CurrentTeletext.startpts = startpts; - - if(queued) - { - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); - m_dvdPlayerSubtitle.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - m_dvdPlayerTeletext.SendMessage(new CDVDMsg(CDVDMsg::GENERAL_RESET)); - SynchronizePlayers(SYNCSOURCE_ALL); - } - else - { - m_dvdPlayerAudio.Flush(); - m_dvdPlayerVideo.Flush(); - m_dvdPlayerSubtitle.Flush(); - m_dvdPlayerTeletext.Flush(); - - // clear subtitle and menu overlays - m_overlayContainer.Clear(); - - if(m_playSpeed == DVD_PLAYSPEED_NORMAL - || m_playSpeed == DVD_PLAYSPEED_PAUSE) - { - // make sure players are properly flushed, should put them in stalled state - CDVDMsgGeneralSynchronize* msg = new CDVDMsgGeneralSynchronize(1000, 0); - m_dvdPlayerAudio.SendMessage(msg->Acquire(), 1); - m_dvdPlayerVideo.SendMessage(msg->Acquire(), 1); - msg->Wait(&m_bStop, 0); - msg->Release(); - - // purge any pending PLAYER_STARTED messages - m_messenger.Flush(CDVDMsg::PLAYER_STARTED); - - // we should now wait for init cache - SetCaching(CACHESTATE_FLUSH); - m_CurrentAudio.started = false; - m_CurrentVideo.started = false; - m_CurrentSubtitle.started = false; - m_CurrentTeletext.started = false; - } - - if(pts != DVD_NOPTS_VALUE) - m_clock.Discontinuity(pts); - UpdatePlayState(0); - - // update state, buffers are flushed and it may take some time until - // we get an update from players - CSingleLock lock(m_StateSection); - m_State = m_StateInput; - } -} - -// since we call ffmpeg functions to decode, this is being called in the same thread as ::Process() is -int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage) -{ - if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY)) - { - if(iMessage == 0) - m_overlayContainer.Add((CDVDOverlay*)pData); - else if(iMessage == 1) - m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH)); - else if(iMessage == 2) - m_dvd.iSelectedAudioStream = *(int*)pData; - else if(iMessage == 3) - m_dvd.iSelectedSPUStream = *(int*)pData; - else if(iMessage == 4) - m_dvdPlayerVideo.EnableSubtitle(*(int*)pData ? true: false); - else if(iMessage == 5) - { - if (m_dvd.state != DVDSTATE_STILL) - { - // else notify the player we have received a still frame - - m_dvd.iDVDStillTime = *(int*)pData; - m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis(); - - /* adjust for the output delay in the video queue */ - unsigned int time = 0; - if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 ) - { - time = (unsigned int)(m_dvdPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 )); - if( time < 10000 && time > 0 ) - m_dvd.iDVDStillTime += time; - } - m_dvd.state = DVDSTATE_STILL; - CLog::Log(LOGDEBUG, - "DVDNAV_STILL_FRAME - waiting %i sec, with delay of %d sec", - m_dvd.iDVDStillTime, time / 1000); - } - } - else if (iMessage == 6) - { - m_dvd.state = DVDSTATE_NORMAL; - CLog::Log(LOGDEBUG, "CDVDPlayer::OnDVDNavResult - libbluray read error (DVDSTATE_NORMAL)"); - CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(25008), g_localizeStrings.Get(25009)); - } - - return 0; - } - - if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream; - - switch (iMessage) - { - case DVDNAV_STILL_FRAME: - { - //CLog::Log(LOGDEBUG, "DVDNAV_STILL_FRAME"); - - dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)pData; - // should wait the specified time here while we let the player running - // after that call dvdnav_still_skip(m_dvdnav); - - if (m_dvd.state != DVDSTATE_STILL) - { - // else notify the player we have received a still frame - - if(still_event->length < 0xff) - m_dvd.iDVDStillTime = still_event->length * 1000; - else - m_dvd.iDVDStillTime = 0; - - m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis(); - - /* adjust for the output delay in the video queue */ - unsigned int time = 0; - if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 ) - { - time = (unsigned int)(m_dvdPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 )); - if( time < 10000 && time > 0 ) - m_dvd.iDVDStillTime += time; - } - m_dvd.state = DVDSTATE_STILL; - CLog::Log(LOGDEBUG, - "DVDNAV_STILL_FRAME - waiting %i sec, with delay of %d sec", - still_event->length, time / 1000); - } - return NAVRESULT_HOLD; - } - break; - case DVDNAV_SPU_CLUT_CHANGE: - { - m_dvdPlayerSubtitle.SendMessage(new CDVDMsgSubtitleClutChange((uint8_t*)pData)); - } - break; - case DVDNAV_SPU_STREAM_CHANGE: - { - dvdnav_spu_stream_change_event_t* event = (dvdnav_spu_stream_change_event_t*)pData; - - int iStream = event->physical_wide; - bool visible = !(iStream & 0x80); - - SetSubtitleVisibleInternal(visible); - - if (iStream >= 0) - m_dvd.iSelectedSPUStream = (iStream & ~0x80); - else - m_dvd.iSelectedSPUStream = -1; - - m_CurrentSubtitle.stream = NULL; - } - break; - case DVDNAV_AUDIO_STREAM_CHANGE: - { - // This should be the correct way i think, however we don't have any streams right now - // since the demuxer hasn't started so it doesn't change. not sure how to do this. - dvdnav_audio_stream_change_event_t* event = (dvdnav_audio_stream_change_event_t*)pData; - - // Tell system what audiostream should be opened by default - if (event->logical >= 0) - m_dvd.iSelectedAudioStream = event->physical; - else - m_dvd.iSelectedAudioStream = -1; - - m_CurrentAudio.stream = NULL; - } - break; - case DVDNAV_HIGHLIGHT: - { - //dvdnav_highlight_event_t* pInfo = (dvdnav_highlight_event_t*)pData; - int iButton = pStream->GetCurrentButton(); - CLog::Log(LOGDEBUG, "DVDNAV_HIGHLIGHT: Highlight button %d\n", iButton); - m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_NORMAL); - } - break; - case DVDNAV_VTS_CHANGE: - { - //dvdnav_vts_change_event_t* vts_change_event = (dvdnav_vts_change_event_t*)pData; - CLog::Log(LOGDEBUG, "DVDNAV_VTS_CHANGE"); - - //Make sure we clear all the old overlays here, or else old forced items are left. - m_overlayContainer.Clear(); - - //Force an aspect ratio that is set in the dvdheaders if available - m_CurrentVideo.hint.aspect = pStream->GetVideoAspectRatio(); - if( m_dvdPlayerVideo.IsInited() ) - m_dvdPlayerVideo.SendMessage(new CDVDMsgDouble(CDVDMsg::VIDEO_SET_ASPECT, m_CurrentVideo.hint.aspect)); - - m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NAV); - m_SelectionStreams.Update(m_pInputStream, m_pDemuxer); - - return NAVRESULT_HOLD; - } - break; - case DVDNAV_CELL_CHANGE: - { - //dvdnav_cell_change_event_t* cell_change_event = (dvdnav_cell_change_event_t*)pData; - CLog::Log(LOGDEBUG, "DVDNAV_CELL_CHANGE"); - - m_dvd.state = DVDSTATE_NORMAL; - - if( m_dvdPlayerVideo.IsInited() ) - m_dvdPlayerVideo.SendMessage(new CDVDMsg(CDVDMsg::VIDEO_NOSKIP)); - } - break; - case DVDNAV_NAV_PACKET: - { - //pci_t* pci = (pci_t*)pData; - - // this should be possible to use to make sure we get - // seamless transitions over these boundaries - // if we remember the old vobunits boundaries - // when a packet comes out of demuxer that has - // pts values outside that boundary, it belongs - // to the new vobunit, wich has new timestamps - UpdatePlayState(0); - } - break; - case DVDNAV_HOP_CHANNEL: - { - // This event is issued whenever a non-seamless operation has been executed. - // Applications with fifos should drop the fifos content to speed up responsiveness. - CLog::Log(LOGDEBUG, "DVDNAV_HOP_CHANNEL"); - if(m_dvd.state == DVDSTATE_SEEK) - m_dvd.state = DVDSTATE_NORMAL; - else - m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH)); - - return NAVRESULT_ERROR; - } - break; - case DVDNAV_STOP: - { - CLog::Log(LOGDEBUG, "DVDNAV_STOP"); - m_dvd.state = DVDSTATE_NORMAL; - CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(16026), g_localizeStrings.Get(16029)); - } - break; - default: - {} - break; - } - } - return NAVRESULT_NOP; -} - -bool CDVDPlayer::ShowPVRChannelInfo(void) -{ - bool bReturn(false); - - if (CSettings::Get().GetInt("pvrmenu.displaychannelinfo") > 0) - { - g_PVRManager.ShowPlayerInfo(CSettings::Get().GetInt("pvrmenu.displaychannelinfo")); - - bReturn = true; - } - - return bReturn; -} - -bool CDVDPlayer::OnAction(const CAction &action) -{ -#define THREAD_ACTION(action) \ - do { \ - if (!IsCurrentThread()) { \ - m_messenger.Put(new CDVDMsgType<CAction>(CDVDMsg::GENERAL_GUI_ACTION, action)); \ - return true; \ - } \ - } while(false) - - CDVDInputStream::IMenus* pMenus = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream); - if (pMenus) - { - if( m_dvd.state == DVDSTATE_STILL && m_dvd.iDVDStillTime != 0 && pMenus->GetTotalButtons() == 0 ) - { - switch(action.GetID()) - { - case ACTION_NEXT_ITEM: - case ACTION_MOVE_RIGHT: - case ACTION_MOVE_UP: - case ACTION_SELECT_ITEM: - { - THREAD_ACTION(action); - /* this will force us out of the stillframe */ - CLog::Log(LOGDEBUG, "%s - User asked to exit stillframe", __FUNCTION__); - m_dvd.iDVDStillStartTime = 0; - m_dvd.iDVDStillTime = 1; - } - return true; - } - } - - - switch (action.GetID()) - { -/* this code is disabled to allow switching playlist items (dvdimage "stacks") */ -#if 0 - case ACTION_PREV_ITEM: // SKIP-: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - pushed prev"); - pMenus->OnPrevious(); - g_infoManager.SetDisplayAfterSeek(); - return true; - } - break; - case ACTION_NEXT_ITEM: // SKIP+: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - pushed next"); - pMenus->OnNext(); - g_infoManager.SetDisplayAfterSeek(); - return true; - } - break; -#endif - case ACTION_SHOW_VIDEOMENU: // start button - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - go to menu"); - pMenus->OnMenu(); - if (m_playSpeed == DVD_PLAYSPEED_PAUSE) - { - SetPlaySpeed(DVD_PLAYSPEED_NORMAL); - m_callback.OnPlayBackResumed(); - } - // send a message to everyone that we've gone to the menu - CGUIMessage msg(GUI_MSG_VIDEO_MENU_STARTED, 0, 0); - g_windowManager.SendThreadMessage(msg); - return true; - } - break; - } - - if (pMenus->IsInMenu()) - { - switch (action.GetID()) - { - case ACTION_NEXT_ITEM: - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - pushed next in menu, stream will decide"); - pMenus->OnNext(); - g_infoManager.SetDisplayAfterSeek(); - return true; - case ACTION_PREV_ITEM: - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - pushed prev in menu, stream will decide"); - pMenus->OnPrevious(); - g_infoManager.SetDisplayAfterSeek(); - return true; - case ACTION_PREVIOUS_MENU: - case ACTION_NAV_BACK: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - menu back"); - pMenus->OnBack(); - } - break; - case ACTION_MOVE_LEFT: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - move left"); - pMenus->OnLeft(); - } - break; - case ACTION_MOVE_RIGHT: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - move right"); - pMenus->OnRight(); - } - break; - case ACTION_MOVE_UP: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - move up"); - pMenus->OnUp(); - } - break; - case ACTION_MOVE_DOWN: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - move down"); - pMenus->OnDown(); - } - break; - - case ACTION_MOUSE_MOVE: - case ACTION_MOUSE_LEFT_CLICK: - { - CRect rs, rd; - m_dvdPlayerVideo.GetVideoRect(rs, rd); - CPoint pt(action.GetAmount(), action.GetAmount(1)); - if (!rd.PtInRect(pt)) - return false; // out of bounds - THREAD_ACTION(action); - // convert to video coords... - pt -= CPoint(rd.x1, rd.y1); - pt.x *= rs.Width() / rd.Width(); - pt.y *= rs.Height() / rd.Height(); - pt += CPoint(rs.x1, rs.y1); - if (action.GetID() == ACTION_MOUSE_LEFT_CLICK) - { - if (pMenus->OnMouseClick(pt)) - return true; - else - { - CApplicationMessenger::Get().SendAction(CAction(ACTION_TRIGGER_OSD), WINDOW_INVALID, false); // Trigger the osd - return false; - } - } - return pMenus->OnMouseMove(pt); - } - break; - case ACTION_SELECT_ITEM: - { - THREAD_ACTION(action); - CLog::Log(LOGDEBUG, " - button select"); - // show button pushed overlay - if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) - m_dvdPlayerSubtitle.UpdateOverlayInfo((CDVDInputStreamNavigator*)m_pInputStream, LIBDVDNAV_BUTTON_CLICKED); - - pMenus->ActivateButton(); - } - break; - case REMOTE_0: - case REMOTE_1: - case REMOTE_2: - case REMOTE_3: - case REMOTE_4: - case REMOTE_5: - case REMOTE_6: - case REMOTE_7: - case REMOTE_8: - case REMOTE_9: - { - THREAD_ACTION(action); - // Offset from key codes back to button number - int button = action.GetID() - REMOTE_0; - CLog::Log(LOGDEBUG, " - button pressed %d", button); - pMenus->SelectButton(button); - } - break; - default: - return false; - break; - } - return true; // message is handled - } - } - - if (dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream)) - { - switch (action.GetID()) - { - case ACTION_MOVE_UP: - case ACTION_NEXT_ITEM: - case ACTION_CHANNEL_UP: - m_messenger.Put(new CDVDMsg(CDVDMsg::PLAYER_CHANNEL_NEXT)); - g_infoManager.SetDisplayAfterSeek(); - ShowPVRChannelInfo(); - return true; - break; - - case ACTION_MOVE_DOWN: - case ACTION_PREV_ITEM: - case ACTION_CHANNEL_DOWN: - m_messenger.Put(new CDVDMsg(CDVDMsg::PLAYER_CHANNEL_PREV)); - g_infoManager.SetDisplayAfterSeek(); - ShowPVRChannelInfo(); - return true; - break; - - case ACTION_CHANNEL_SWITCH: - { - // Offset from key codes back to button number - int channel = action.GetAmount(); - m_messenger.Put(new CDVDMsgInt(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER, channel)); - g_infoManager.SetDisplayAfterSeek(); - ShowPVRChannelInfo(); - return true; - } - break; - } - } - - switch (action.GetID()) - { - case ACTION_NEXT_ITEM: - if (GetChapter() > 0 && GetChapter() < GetChapterCount()) - { - m_messenger.Put(new CDVDMsgPlayerSeekChapter(GetChapter() + 1)); - g_infoManager.SetDisplayAfterSeek(); - return true; - } - else - break; - case ACTION_PREV_ITEM: - if (GetChapter() > 0) - { - m_messenger.Put(new CDVDMsgPlayerSeekChapter(GetChapter() - 1)); - g_infoManager.SetDisplayAfterSeek(); - return true; - } - else - break; - } - - // return false to inform the caller we didn't handle the message - return false; -} - -bool CDVDPlayer::IsInMenu() const -{ - CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream); - if (pStream) - { - if( m_dvd.state == DVDSTATE_STILL ) - return true; - else - return pStream->IsInMenu(); - } - return false; -} - -bool CDVDPlayer::HasMenu() -{ - CDVDInputStream::IMenus* pStream = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream); - if (pStream) - return pStream->HasMenu(); - else - return false; -} - -std::string CDVDPlayer::GetPlayerState() -{ - CSingleLock lock(m_StateSection); - return m_State.player_state; -} - -bool CDVDPlayer::SetPlayerState(std::string state) -{ - m_messenger.Put(new CDVDMsgPlayerSetState(state)); - return true; -} - -int CDVDPlayer::GetChapterCount() -{ - CSingleLock lock(m_StateSection); - return m_State.chapter_count; -} - -int CDVDPlayer::GetChapter() -{ - CSingleLock lock(m_StateSection); - return m_State.chapter; -} - -void CDVDPlayer::GetChapterName(std::string& strChapterName) -{ - CSingleLock lock(m_StateSection); - strChapterName = m_State.chapter_name; -} - -int CDVDPlayer::SeekChapter(int iChapter) -{ - if (GetChapter() > 0) - { - if (iChapter < 0) - iChapter = 0; - if (iChapter > GetChapterCount()) - return 0; - - // Seek to the chapter. - m_messenger.Put(new CDVDMsgPlayerSeekChapter(iChapter)); - SynchronizeDemuxer(100); - } - - return 0; -} - -int CDVDPlayer::AddSubtitle(const std::string& strSubPath) -{ - return AddSubtitleFile(strSubPath); -} - -int CDVDPlayer::GetCacheLevel() const -{ - CSingleLock lock(m_StateSection); - return (int)(m_StateInput.cache_level * 100); -} - -double CDVDPlayer::GetQueueTime() -{ - int a = m_dvdPlayerAudio.GetLevel(); - int v = m_dvdPlayerVideo.GetLevel(); - return max(a, v) * 8000.0 / 100; -} - -void CDVDPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info) -{ - info.bitrate = m_dvdPlayerVideo.GetVideoBitrate(); - - std::string retVal; - if (m_pDemuxer && (m_CurrentVideo.id != -1)) - { - m_pDemuxer->GetStreamCodecName(m_CurrentVideo.id, retVal); - CDemuxStreamVideo* stream = static_cast<CDemuxStreamVideo*>(m_pDemuxer->GetStream(m_CurrentVideo.id)); - if (stream) - { - info.width = stream->iWidth; - info.height = stream->iHeight; - } - } - info.videoCodecName = retVal; - info.videoAspectRatio = m_dvdPlayerVideo.GetAspectRatio(); - m_dvdPlayerVideo.GetVideoRect(info.SrcRect, info.DestRect); - info.stereoMode = m_dvdPlayerVideo.GetStereoMode(); - if (info.stereoMode == "mono") - info.stereoMode = ""; -} - -int CDVDPlayer::GetSourceBitrate() -{ - if (m_pInputStream) - return (int)m_pInputStream->GetBitstreamStats().GetBitrate(); - - return 0; -} - -void CDVDPlayer::GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info) -{ - if (index < 0 || index > GetAudioStreamCount() - 1 ) - return; - - if (index == GetAudioStream()) - info.bitrate = m_dvdPlayerAudio.GetAudioBitrate(); - else if (m_pDemuxer) - { - CDemuxStreamAudio* stream = m_pDemuxer->GetStreamFromAudioId(index); - if (stream) - info.bitrate = stream->iBitRate; - } - - SelectionStream& s = m_SelectionStreams.Get(STREAM_AUDIO, index); - if(s.language.length() > 0) - info.language = s.language; - - if(s.name.length() > 0) - info.name = s.name; - - if(s.type == STREAM_NONE) - info.name += " (Invalid)"; - - if (m_pDemuxer) - { - CDemuxStreamAudio* stream = static_cast<CDemuxStreamAudio*>(m_pDemuxer->GetStreamFromAudioId(index)); - if (stream) - { - info.channels = stream->iChannels; - std::string codecName; - m_pDemuxer->GetStreamCodecName(stream->iId, codecName); - info.audioCodecName = codecName; - } - } -} - -int CDVDPlayer::AddSubtitleFile(const std::string& filename, const std::string& subfilename, CDemuxStream::EFlags flags) -{ - std::string ext = URIUtils::GetExtension(filename); - std::string vobsubfile = subfilename; - if(ext == ".idx") - { - if (vobsubfile.empty()) { - // find corresponding .sub (e.g. in case of manually selected .idx sub) - vobsubfile = CUtil::GetVobSubSubFromIdx(filename); - if (vobsubfile.empty()) - return -1; - } - - CDVDDemuxVobsub v; - if(!v.Open(filename, vobsubfile)) - return -1; - m_SelectionStreams.Update(NULL, &v); - int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, m_SelectionStreams.Source(STREAM_SOURCE_DEMUX_SUB, filename), 0); - m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags; - m_SelectionStreams.Get(STREAM_SUBTITLE, index).filename2 = vobsubfile; - ExternalStreamInfo info; - CUtil::GetExternalStreamDetailsFromFilename(m_filename, vobsubfile, info); - m_SelectionStreams.Get(STREAM_SUBTITLE, index).name = info.name; - if (m_SelectionStreams.Get(STREAM_SUBTITLE, index).language.empty()) - m_SelectionStreams.Get(STREAM_SUBTITLE, index).language = info.language; - - if (static_cast<CDemuxStream::EFlags>(info.flag) == CDemuxStream::FLAG_NONE) - m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags; - else - m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = static_cast<CDemuxStream::EFlags>(info.flag); - - return index; - } - if(ext == ".sub") - { - // if this looks like vobsub file (i.e. .idx found), add it as such - std::string vobsubidx = CUtil::GetVobSubIdxFromSub(filename); - if (!vobsubidx.empty()) - return AddSubtitleFile(vobsubidx, filename, flags); - } - SelectionStream s; - s.source = m_SelectionStreams.Source(STREAM_SOURCE_TEXT, filename); - s.type = STREAM_SUBTITLE; - s.id = 0; - s.filename = filename; - ExternalStreamInfo info; - CUtil::GetExternalStreamDetailsFromFilename(m_filename, filename, info); - s.name = info.name; - s.language = info.language; - if (static_cast<CDemuxStream::EFlags>(info.flag) == CDemuxStream::FLAG_NONE) - s .flags = flags; - else - s.flags = static_cast<CDemuxStream::EFlags>(info.flag); - - m_SelectionStreams.Update(s); - return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, s.source, s.id); -} - -void CDVDPlayer::UpdatePlayState(double timeout) -{ - if(m_StateInput.timestamp != 0 - && m_StateInput.timestamp + DVD_MSEC_TO_TIME(timeout) > CDVDClock::GetAbsoluteClock()) - return; - - SPlayerState state(m_StateInput); - - if (m_CurrentVideo.dts != DVD_NOPTS_VALUE) - state.dts = m_CurrentVideo.dts; - else if(m_CurrentAudio.dts != DVD_NOPTS_VALUE) - state.dts = m_CurrentAudio.dts; - else if(m_CurrentVideo.startpts != DVD_NOPTS_VALUE) - state.dts = m_CurrentVideo.startpts; - else if(m_CurrentAudio.startpts != DVD_NOPTS_VALUE) - state.dts = m_CurrentAudio.startpts; - - - if(m_pDemuxer) - { - state.chapter = m_pDemuxer->GetChapter(); - state.chapter_count = m_pDemuxer->GetChapterCount(); - m_pDemuxer->GetChapterName(state.chapter_name); - - if(state.dts == DVD_NOPTS_VALUE) - state.time = 0; - else - state.time = DVD_TIME_TO_MSEC(state.dts + m_offset_pts); - state.time_total = m_pDemuxer->GetStreamLength(); - state.time_src = ETIMESOURCE_CLOCK; - } - - state.canpause = true; - state.canseek = true; - - if(m_pInputStream) - { - // override from input stream if needed - CDVDInputStream::IChannel* pChannel = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream); - if (pChannel) - { - state.canrecord = pChannel->CanRecord(); - state.recording = pChannel->IsRecording(); - } - - CDVDInputStream::IDisplayTime* pDisplayTime = dynamic_cast<CDVDInputStream::IDisplayTime*>(m_pInputStream); - if (pDisplayTime && pDisplayTime->GetTotalTime() > 0) - { - state.time = pDisplayTime->GetTime(); - state.time_total = pDisplayTime->GetTotalTime(); - state.time_src = ETIMESOURCE_INPUT; - } - - if (CDVDInputStream::IMenus* ptr = dynamic_cast<CDVDInputStream::IMenus*>(m_pInputStream)) - { - if(!ptr->GetState(state.player_state)) - state.player_state = ""; - - if(m_dvd.state == DVDSTATE_STILL) - { - state.time = XbmcThreads::SystemClockMillis() - m_dvd.iDVDStillStartTime; - state.time_total = m_dvd.iDVDStillTime; - state.time_src = ETIMESOURCE_MENU; - } - } - - if (CDVDInputStream::ISeekable* ptr = dynamic_cast<CDVDInputStream::ISeekable*>(m_pInputStream)) - { - state.canpause = ptr->CanPause(); - state.canseek = ptr->CanSeek(); - } - } - - if (m_Edl.HasCut()) - { - state.time = m_Edl.RemoveCutTime(llrint(state.time)); - state.time_total = m_Edl.RemoveCutTime(llrint(state.time_total)); - } - - if(state.time_total <= 0) - state.canseek = false; - - if (state.time_src == ETIMESOURCE_CLOCK) - state.time_offset = m_offset_pts; - else if (state.dts != DVD_NOPTS_VALUE) - state.time_offset = DVD_MSEC_TO_TIME(state.time) - state.dts; - - if (m_CurrentAudio.id >= 0 && m_pDemuxer) - { - CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentAudio.id); - if (pStream && pStream->type == STREAM_AUDIO) - ((CDemuxStreamAudio*)pStream)->GetStreamInfo(state.demux_audio); - } - else - state.demux_audio = ""; - - if (m_CurrentVideo.id >= 0 && m_pDemuxer) - { - CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentVideo.id); - if (pStream && pStream->type == STREAM_VIDEO) - ((CDemuxStreamVideo*)pStream)->GetStreamInfo(state.demux_video); - } - else - state.demux_video = ""; - - double level, delay, offset; - if(GetCachingTimes(level, delay, offset)) - { - state.cache_delay = max(0.0, delay); - state.cache_level = max(0.0, min(1.0, level)); - state.cache_offset = offset; - } - else - { - state.cache_delay = 0.0; - state.cache_level = min(1.0, GetQueueTime() / 8000.0); - state.cache_offset = GetQueueTime() / state.time_total; - } - - XFILE::SCacheStatus status; - if(m_pInputStream && m_pInputStream->GetCacheStatus(&status)) - { - state.cache_bytes = status.forward; - if(state.time_total) - state.cache_bytes += m_pInputStream->GetLength() * GetQueueTime() / state.time_total; - } - else - state.cache_bytes = 0; - - state.timestamp = CDVDClock::GetAbsoluteClock(); - //{CLog::Log(LOGINFO, "%s: time:%.2f stamp:%.2f dts:%d m:%d (p:%d,c:%d) =%llu", __func__, (double)state.time, (double)state.timestamp, (int)DVD_TIME_TO_MSEC(state.dts + m_offset_pts), (int)DVD_TIME_TO_MSEC(m_stamp), (int)m_playSpeed, (int)m_caching, llrint(state.time + DVD_TIME_TO_MSEC(offset)));} - - CSingleLock lock(m_StateSection); - m_StateInput = state; -} - -void CDVDPlayer::UpdateApplication(double timeout) -{ - if(m_UpdateApplication != 0 - && m_UpdateApplication + DVD_MSEC_TO_TIME(timeout) > CDVDClock::GetAbsoluteClock()) - return; - - CDVDInputStream::IChannel* pStream = dynamic_cast<CDVDInputStream::IChannel*>(m_pInputStream); - if(pStream) - { - CFileItem item(g_application.CurrentFileItem()); - if(pStream->UpdateItem(item)) - { - g_application.CurrentFileItem() = item; - CApplicationMessenger::Get().SetCurrentItem(item); - } - } - m_UpdateApplication = CDVDClock::GetAbsoluteClock(); -} - -bool CDVDPlayer::CanRecord() -{ - CSingleLock lock(m_StateSection); - return m_State.canrecord; -} - -bool CDVDPlayer::IsRecording() -{ - CSingleLock lock(m_StateSection); - return m_State.recording; -} - -bool CDVDPlayer::Record(bool bOnOff) -{ - if (m_pInputStream && (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV) || - m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) ) - { - m_messenger.Put(new CDVDMsgBool(CDVDMsg::PLAYER_SET_RECORD, bOnOff)); - return true; - } - return false; -} - -bool CDVDPlayer::GetStreamDetails(CStreamDetails &details) -{ - if (m_pDemuxer) - { - std::vector<SelectionStream> subs = m_SelectionStreams.Get(STREAM_SUBTITLE); - std::vector<CStreamDetailSubtitle> extSubDetails; - for (unsigned int i = 0; i < subs.size(); i++) - { - if (subs[i].filename == m_filename) - continue; - - CStreamDetailSubtitle p; - p.m_strLanguage = subs[i].language; - extSubDetails.push_back(p); - } - - bool result = CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, extSubDetails, details); - if (result && details.GetStreamCount(CStreamDetail::VIDEO) > 0) // this is more correct (dvds in particular) - { - /* - * We can only obtain the aspect & duration from dvdplayer when the Process() thread is running - * and UpdatePlayState() has been called at least once. In this case dvdplayer duration/AR will - * return 0 and we'll have to fallback to the (less accurate) info from the demuxer. - */ - float aspect = m_dvdPlayerVideo.GetAspectRatio(); - if (aspect > 0.0f) - ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_fAspect = aspect; - - int64_t duration = GetTotalTime() / 1000; - if (duration > 0) - ((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_iDuration = duration; - } - return result; - } - else - return false; -} - -std::string CDVDPlayer::GetPlayingTitle() -{ - /* Currently we support only Title Name from Teletext line 30 */ - TextCacheStruct_t* ttcache = m_dvdPlayerTeletext.GetTeletextCache(); - if (ttcache && !ttcache->line30.empty()) - return ttcache->line30; - - return ""; -} - -bool CDVDPlayer::SwitchChannel(const CPVRChannel &channel) -{ - if (!g_PVRManager.CheckParentalLock(channel)) - return false; - - /* set GUI info */ - if (!g_PVRManager.PerformChannelSwitch(channel, true)) - return false; - - UpdateApplication(0); - UpdatePlayState(0); - - /* select the new channel */ - m_messenger.Put(new CDVDMsgType<CPVRChannel>(CDVDMsg::PLAYER_CHANNEL_SELECT, channel)); - - return true; -} - -bool CDVDPlayer::CachePVRStream(void) const -{ - return m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && - !g_PVRManager.IsPlayingRecording() && - g_advancedSettings.m_bPVRCacheInDvdPlayer; -} - -void CDVDPlayer::GetRenderFeatures(std::vector<int> &renderFeatures) -{ - renderFeatures.push_back(RENDERFEATURE_STRETCH); - renderFeatures.push_back(RENDERFEATURE_CROP); - renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO); - renderFeatures.push_back(RENDERFEATURE_ZOOM); -} - -void CDVDPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods) -{ - deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE); -} - -void CDVDPlayer::GetDeinterlaceModes(std::vector<int> &deinterlaceModes) -{ - deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO); - deinterlaceModes.push_back(VS_DEINTERLACEMODE_OFF); - deinterlaceModes.push_back(VS_DEINTERLACEMODE_FORCE); -} - -void CDVDPlayer::GetScalingMethods(std::vector<int> &scalingMethods) -{ -} - -void CDVDPlayer::GetAudioCapabilities(std::vector<int> &audioCaps) -{ - audioCaps.push_back(IPC_AUD_OFFSET); - audioCaps.push_back(IPC_AUD_SELECT_STREAM); - audioCaps.push_back(IPC_AUD_SELECT_OUTPUT); - audioCaps.push_back(IPC_AUD_AMP); -} - -void CDVDPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps) -{ - subCaps.push_back(IPC_SUBS_ALL); -} - -#endif diff --git a/xbmc/cores/omxplayer/OMXPlayer.h b/xbmc/cores/omxplayer/OMXPlayer.h deleted file mode 100644 index 7c1b34d5ed..0000000000 --- a/xbmc/cores/omxplayer/OMXPlayer.h +++ /dev/null @@ -1,508 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "cores/IPlayer.h" -#include "threads/Thread.h" - -#include "cores/dvdplayer/IDVDPlayer.h" - -#include "DVDMessageQueue.h" -#include "OMXCore.h" -#include "OMXClock.h" -#include "OMXPlayerAudio.h" -#include "OMXPlayerVideo.h" -#include "DVDPlayerSubtitle.h" -#include "DVDPlayerTeletext.h" - -//#include "DVDChapterReader.h" -#include "DVDSubtitles/DVDFactorySubtitle.h" -#include "utils/BitstreamStats.h" - -#include "linux/DllBCM.h" -#include "Edl.h" -#include "FileItem.h" -#include "threads/SingleLock.h" - -class COMXPlayer; -class OMXPlayerVideo; -class OMXPlayerAudio; - -namespace PVR -{ - class CPVRChannel; -} - -#define DVDSTATE_NORMAL 0x00000001 // normal dvd state -#define DVDSTATE_STILL 0x00000002 // currently displaying a still frame -#define DVDSTATE_WAIT 0x00000003 // waiting for demuxer read error -#define DVDSTATE_SEEK 0x00000004 // we are finishing a seek request - -class COMXCurrentStream -{ -public: - int id; // demuxerid of current playing stream - int source; - double dts; // last dts from demuxer, used to find disncontinuities - double dur; // last frame expected duration - double dts_state; // when did we last send a playback state update - CDVDStreamInfo hint; // stream hints, used to notice stream changes - void* stream; // pointer or integer, identifying stream playing. if it changes stream changed - int changes; // remembered counter from stream to track codec changes - bool inited; - bool started; // has the player started - const StreamType type; - const int player; - // stuff to handle starting after seek - double startpts; - - COMXCurrentStream(StreamType t, int i) - : type(t) - , player(i) - { - Clear(); - } - - void Clear() - { - id = -1; - source = STREAM_SOURCE_NONE; - dts = DVD_NOPTS_VALUE; - dts_state = DVD_NOPTS_VALUE; - dur = DVD_NOPTS_VALUE; - hint.Clear(); - stream = NULL; - changes = 0; - inited = false; - started = false; - startpts = DVD_NOPTS_VALUE; - } - - double dts_end() - { - if(dts == DVD_NOPTS_VALUE) - return DVD_NOPTS_VALUE; - if(dur == DVD_NOPTS_VALUE) - return dts; - return dts + dur; - } -}; - -typedef struct -{ - StreamType type; - int type_index; - std::string filename; - std::string filename2; // for vobsub subtitles, 2 files are necessary (idx/sub) - std::string language; - std::string name; - CDemuxStream::EFlags flags; - int source; - int id; - std::string codec; - int channels; -} OMXSelectionStream; - -typedef std::vector<OMXSelectionStream> OMXSelectionStreams; - -class COMXSelectionStreams -{ - CCriticalSection m_section; - OMXSelectionStream m_invalid; -public: - COMXSelectionStreams() - { - m_invalid.id = -1; - m_invalid.source = STREAM_SOURCE_NONE; - m_invalid.type = STREAM_NONE; - } - std::vector<OMXSelectionStream> m_Streams; - - int IndexOf (StreamType type, int source, int id) const; - int IndexOf (StreamType type, COMXPlayer& p) const; - int Count (StreamType type) const { return IndexOf(type, STREAM_SOURCE_NONE, -1) + 1; } - OMXSelectionStream& Get (StreamType type, int index); - bool Get (StreamType type, CDemuxStream::EFlags flag, OMXSelectionStream& out); - - OMXSelectionStreams Get(StreamType type); - template<typename Compare> OMXSelectionStreams Get(StreamType type, Compare compare) - { - OMXSelectionStreams streams = Get(type); - std::stable_sort(streams.begin(), streams.end(), compare); - return streams; - } - - void Clear (StreamType type, StreamSource source); - int Source (StreamSource source, std::string filename); - - void Update (OMXSelectionStream& s); - void Update (CDVDInputStream* input, CDVDDemux* demuxer); -}; - - -#define DVDPLAYER_AUDIO 1 -#define DVDPLAYER_VIDEO 2 -#define DVDPLAYER_SUBTITLE 3 -#define DVDPLAYER_TELETEXT 4 - -class COMXPlayer : public IPlayer, public CThread, public IDVDPlayer -{ -public: - COMXPlayer(IPlayerCallback& callback); - virtual ~COMXPlayer(); - virtual bool OpenFile(const CFileItem& file, const CPlayerOptions &options); - virtual bool CloseFile(bool reopen = false); - virtual bool IsPlaying() const; - virtual void Pause(); - virtual bool IsPaused() const; - virtual bool HasVideo() const; - virtual bool HasAudio() const; - virtual bool IsPassthrough() const; - virtual bool CanSeek(); - virtual void Seek(bool bPlus, bool bLargeStep, bool bChapterOverride); - virtual bool SeekScene(bool bPlus = true); - virtual void SeekPercentage(float iPercent); - virtual float GetPercentage(); - virtual float GetCachePercentage(); - - virtual void RegisterAudioCallback(IAudioCallback* pCallback) { m_omxPlayerAudio.RegisterAudioCallback(pCallback); } - virtual void UnRegisterAudioCallback() { m_omxPlayerAudio.UnRegisterAudioCallback(); } - virtual void SetVolume(float nVolume) { m_omxPlayerAudio.SetVolume(nVolume); } - virtual void SetDynamicRangeCompression(long drc) { m_omxPlayerAudio.SetDynamicRangeCompression(drc); } - virtual void SetMute(bool bOnOff) { m_omxPlayerAudio.SetMute(bOnOff); } - virtual bool ControlsVolume() {return true;} - virtual void GetAudioInfo(std::string &strAudioInfo); - virtual void GetVideoInfo(std::string &strVideoInfo); - virtual void GetGeneralInfo(std::string &strVideoInfo); - virtual bool CanRecord(); - virtual bool IsRecording(); - virtual bool CanPause(); - virtual bool Record(bool bOnOff); - virtual void SetAVDelay(float fValue = 0.0f); - virtual float GetAVDelay(); - - virtual void SetSubTitleDelay(float fValue = 0.0f); - virtual float GetSubTitleDelay(); - virtual int GetSubtitleCount(); - virtual int GetSubtitle(); - virtual void GetSubtitleStreamInfo(int index, SPlayerSubtitleStreamInfo &info); - virtual void SetSubtitle(int iStream); - virtual bool GetSubtitleVisible(); - virtual void SetSubtitleVisible(bool bVisible); - virtual int AddSubtitle(const std::string& strSubPath); - - virtual int GetAudioStreamCount(); - virtual int GetAudioStream(); - virtual void SetAudioStream(int iStream); - - virtual TextCacheStruct_t* GetTeletextCache(); - virtual void LoadPage(int p, int sp, unsigned char* buffer); - - virtual int GetChapterCount(); - virtual int GetChapter(); - virtual void GetChapterName(std::string& strChapterName); - virtual int SeekChapter(int iChapter); - - virtual void SeekTime(int64_t iTime); - virtual int64_t GetTime(); - virtual int64_t GetTotalTime(); - virtual void ToFFRW(int iSpeed); - virtual bool OnAction(const CAction &action); - virtual bool HasMenu(); - - virtual int GetSourceBitrate(); - virtual void GetVideoStreamInfo(SPlayerVideoStreamInfo &info); - virtual bool GetStreamDetails(CStreamDetails &details); - virtual void GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info); - - virtual std::string GetPlayerState(); - virtual bool SetPlayerState(std::string state); - - virtual std::string GetPlayingTitle(); - - virtual bool SwitchChannel(const PVR::CPVRChannel &channel); - virtual bool CachePVRStream(void) const; - - enum ECacheState - { CACHESTATE_DONE = 0 - , CACHESTATE_FULL // player is filling up the demux queue - , CACHESTATE_PVR // player is waiting for some data in each buffer - , CACHESTATE_INIT // player is waiting for first packet of each stream - , CACHESTATE_PLAY // player is waiting for players to not be stalled - , CACHESTATE_FLUSH // temporary state player will choose startup between init or full - }; - - virtual bool IsCaching() const { return m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR; } - virtual int GetCacheLevel() const ; - - virtual int OnDVDNavResult(void* pData, int iMessage); - - virtual void GetRenderFeatures(std::vector<int> &renderFeatures); - virtual void GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods); - virtual void GetDeinterlaceModes(std::vector<int> &deinterlaceModes); - virtual void GetScalingMethods(std::vector<int> &scalingMethods); - virtual void GetAudioCapabilities(std::vector<int> &audioCaps); - virtual void GetSubtitleCapabilities(std::vector<int> &subCaps); -protected: - friend class COMXSelectionStreams; - - virtual void OnStartup(); - virtual void OnExit(); - virtual void Process(); - - bool OpenStream(COMXCurrentStream& current, int iStream, int source, bool reset = true); - bool OpenStreamPlayer(COMXCurrentStream& current, CDVDStreamInfo& hint, bool reset); - bool OpenAudioStream(CDVDStreamInfo& hint, bool reset = true); - bool OpenVideoStream(CDVDStreamInfo& hint, bool reset = true); - bool OpenSubtitleStream(CDVDStreamInfo& hint); - bool OpenTeletextStream(CDVDStreamInfo& hint); - - /** \brief Switches forced subtitles to forced subtitles matching the language of the current audio track. - * If these are not available, subtitles are disabled. - * \return true if the subtitles were changed, false otherwise. - */ - bool AdaptForcedSubtitles(); - bool CloseStream(COMXCurrentStream& current, bool bWaitForBuffers); - - bool CheckIsCurrent(COMXCurrentStream& current, CDemuxStream* stream, DemuxPacket* pkg); - void ProcessPacket(CDemuxStream* pStream, DemuxPacket* pPacket); - void ProcessAudioData(CDemuxStream* pStream, DemuxPacket* pPacket); - void ProcessVideoData(CDemuxStream* pStream, DemuxPacket* pPacket); - void ProcessSubData(CDemuxStream* pStream, DemuxPacket* pPacket); - void ProcessTeletextData(CDemuxStream* pStream, DemuxPacket* pPacket); - - bool ShowPVRChannelInfo(); - - int AddSubtitleFile(const std::string& filename, const std::string& subfilename = "", CDemuxStream::EFlags flags = CDemuxStream::FLAG_NONE); - void SetSubtitleVisibleInternal(bool bVisible); - - /** - * one of the DVD_PLAYSPEED defines - */ - void SetPlaySpeed(int iSpeed); - int GetPlaySpeed() { return m_playSpeed; } - void SetCaching(ECacheState state); - - int64_t GetTotalTimeInMsec(); - - double GetQueueTime(); - bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); - - - void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true); - - void HandleMessages(); - void HandlePlaySpeed(); - bool IsInMenu() const; - - void SynchronizePlayers(unsigned int sources); - void SynchronizeDemuxer(unsigned int timeout); - void CheckAutoSceneSkip(); - void CheckContinuity(COMXCurrentStream& current, DemuxPacket* pPacket); - bool CheckSceneSkip(COMXCurrentStream& current); - bool CheckPlayerInit(COMXCurrentStream& current); - bool CheckStartCaching(COMXCurrentStream& current); - void UpdateCorrection(DemuxPacket* pkt, double correction); - void UpdateTimestamps(COMXCurrentStream& current, DemuxPacket* pPacket); - IDVDStreamPlayer* GetStreamPlayer(unsigned int player); - void SendPlayerMessage(CDVDMsg* pMsg, unsigned int target); - - bool ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream); - bool IsValidStream(COMXCurrentStream& stream); - bool IsBetterStream(COMXCurrentStream& current, CDemuxStream* stream); - void CheckBetterStream(COMXCurrentStream& current, CDemuxStream* stream); - void CheckStreamChanges(COMXCurrentStream& current, CDemuxStream* stream); - bool CheckDelayedChannelEntry(void); - - bool OpenInputStream(); - bool OpenDemuxStream(); - void OpenDefaultStreams(bool reset = true); - - void UpdateApplication(double timeout); - void UpdatePlayState(double timeout); - void UpdateClockMaster(); - double m_UpdateApplication; - - bool m_bAbortRequest; - - std::string m_filename; // holds the actual filename - std::string m_mimetype; // hold a hint to what content file contains (mime type) - ECacheState m_caching; - CFileItem m_item; - XbmcThreads::EndTime m_ChannelEntryTimeOut; - - - COMXCurrentStream m_CurrentAudio; - COMXCurrentStream m_CurrentVideo; - COMXCurrentStream m_CurrentSubtitle; - COMXCurrentStream m_CurrentTeletext; - - COMXSelectionStreams m_SelectionStreams; - - int m_playSpeed; - struct SSpeedState - { - double lastpts; // holds last display pts during ff/rw operations - double lasttime; - } m_SpeedState; - - int m_errorCount; - double m_offset_pts; - - CDVDMessageQueue m_messenger; // thread messenger - - OMXPlayerVideo m_omxPlayerVideo; // video part - OMXPlayerAudio m_omxPlayerAudio; // audio part - CDVDPlayerSubtitle m_dvdPlayerSubtitle; // subtitle part - CDVDTeletextData m_dvdPlayerTeletext; // teletext part - - CDVDClock m_clock; // master clock - OMXClock m_av_clock; - - bool m_stepped; - int m_video_fifo; - int m_audio_fifo; - double m_last_check_time; // we periodically check for gpu underrun - double m_stamp; // last media stamp - - CDVDOverlayContainer m_overlayContainer; - - CDVDInputStream* m_pInputStream; // input stream for current playing file - CDVDDemux* m_pDemuxer; // demuxer for current playing file - CDVDDemux* m_pSubtitleDemuxer; - - struct SDVDInfo - { - void Clear() - { - state = DVDSTATE_NORMAL; - iSelectedSPUStream = -1; - iSelectedAudioStream = -1; - iDVDStillTime = 0; - iDVDStillStartTime = 0; - } - - int state; // current dvdstate - unsigned int iDVDStillTime; // total time in ticks we should display the still before continuing - unsigned int iDVDStillStartTime; // time in ticks when we started the still - int iSelectedSPUStream; // mpeg stream id, or -1 if disabled - int iSelectedAudioStream; // mpeg stream id, or -1 if disabled - } m_dvd; - - enum ETimeSource - { - ETIMESOURCE_CLOCK, - ETIMESOURCE_INPUT, - ETIMESOURCE_MENU, - }; - - friend class OMXPlayerVideo; - friend class OMXPlayerAudio; - - struct SPlayerState - { - SPlayerState() { Clear(); } - void Clear() - { - player = 0; - timestamp = 0; - time = 0; - time_total = 0; - time_offset = 0; - time_src = ETIMESOURCE_CLOCK; - dts = DVD_NOPTS_VALUE; - player_state = ""; - chapter = 0; - chapter_name = ""; - chapter_count = 0; - canrecord = false; - recording = false; - canpause = false; - canseek = false; - demux_video = ""; - demux_audio = ""; - cache_bytes = 0; - cache_level = 0.0; - cache_delay = 0.0; - cache_offset = 0.0; - } - - int player; // source of this data - - double timestamp; // last time of update - double time_offset; // difference between time and pts - - double time; // current playback time - double time_total; // total playback time - ETimeSource time_src; // current time source - double dts; // last known dts - - std::string player_state; // full player state - - int chapter; // current chapter - std::string chapter_name; // name of current chapter - int chapter_count;// number of chapter - - bool canrecord; // can input stream record - bool recording; // are we currently recording - - bool canpause; // pvr: can pause the current playing item - bool canseek; // pvr: can seek in the current playing item - - std::string demux_video; - std::string demux_audio; - - int64_t cache_bytes; // number of bytes current's cached - double cache_level; // current estimated required cache level - double cache_delay; // time until cache is expected to reach estimated level - double cache_offset; // percentage of file ahead of current position - } m_State, m_StateInput; - CCriticalSection m_StateSection; - - CEvent m_ready; - - CEdl m_Edl; - - struct SEdlAutoSkipMarkers { - - void Clear() - { - cut = -1; - commbreak_start = -1; - commbreak_end = -1; - seek_to_start = false; - mute = false; - } - - int cut; // last automatically skipped EDL cut seek position - int commbreak_start; // start time of the last commercial break automatically skipped - int commbreak_end; // end time of the last commercial break automatically skipped - bool seek_to_start; // whether seeking can go back to the start of a previously skipped break - bool mute; // whether EDL mute is on - - } m_EdlAutoSkipMarkers; - - CPlayerOptions m_PlayerOptions; - - bool m_HasVideo; - bool m_HasAudio; - - bool m_DemuxerPausePending; -}; diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp index c1b7a0dcfa..55f8ac779b 100644 --- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp @@ -40,7 +40,7 @@ #include "settings/Settings.h" #include "utils/TimeUtils.h" -#include "OMXPlayer.h" +#include "DVDPlayer.h" #include "linux/RBP.h" #include "cores/AudioEngine/AEFactory.h" @@ -77,7 +77,6 @@ OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent) m_stalled = false; m_audioClock = DVD_NOPTS_VALUE; m_buffer_empty = false; - m_nChannels = 0; m_DecoderOpen = false; m_bad_state = false; m_hints_current.Clear(); @@ -141,7 +140,6 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec) m_silence = false; m_started = false; m_flush = false; - m_nChannels = 0; m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0; m_use_hw_decode = g_advancedSettings.m_omxHWAudioDecode; m_format.m_dataFormat = GetDataFormat(m_hints); @@ -428,15 +426,27 @@ void OMXPlayerAudio::Process() } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { - COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value; - double pts = m_audioClock; - double stamp = m_av_clock->OMXMediaTime(); + CDVDPlayer::SPlayerState& state = ((CDVDMsgType<CDVDPlayer::SPlayerState>*)pMsg)->m_value; - if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK) - state.time = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset); + if (m_speed != DVD_PLAYSPEED_NORMAL && m_speed != DVD_PLAYSPEED_PAUSE) + { + if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) + state.time = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset); + else + state.timestamp = CDVDClock::GetAbsoluteClock(); + } else - state.time = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts); - state.timestamp = m_av_clock->GetAbsoluteClock(); + { + double pts = m_audioClock; + double stamp = m_av_clock->OMXMediaTime(); + if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) + state.time = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset); + else + state.time = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts); + state.timestamp = CDVDClock::GetAbsoluteClock(); + if (stamp == 0.0) // cause message to be ignored + state.player = 0; + } state.player = DVDPLAYER_AUDIO; m_messageParent.Put(pMsg->Acquire()); } @@ -552,7 +562,6 @@ AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints) bool OMXPlayerAudio::OpenDecoder() { - m_nChannels = m_hints.channels; m_passthrough = false; m_hw_decode = false; @@ -587,7 +596,7 @@ bool OMXPlayerAudio::OpenDecoder() else { CLog::Log(LOGINFO, "Audio codec %s channels %d samplerate %d bitspersample %d\n", - m_codec_name.c_str(), m_nChannels, m_hints.samplerate, m_hints.bitspersample); + m_codec_name.c_str(), m_hints.channels, m_hints.samplerate, m_hints.bitspersample); } m_started = false; @@ -640,6 +649,11 @@ int OMXPlayerAudio::GetAudioBitrate() return (int)m_audioStats.GetBitrate(); } +int OMXPlayerAudio::GetAudioChannels() +{ + return m_hints.channels; +} + std::string OMXPlayerAudio::GetPlayerInfo() { std::ostringstream s; diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.h b/xbmc/cores/omxplayer/OMXPlayerAudio.h index 636249e689..2397db4753 100644 --- a/xbmc/cores/omxplayer/OMXPlayerAudio.h +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.h @@ -36,7 +36,7 @@ #include "utils/BitstreamStats.h" #include "xbmc/linux/DllBCM.h" -class OMXPlayerAudio : public CThread, public IDVDStreamPlayer +class OMXPlayerAudio : public CThread, public IDVDStreamPlayerAudio { protected: CDVDMessageQueue m_messageQueue; @@ -63,7 +63,6 @@ protected: bool m_buffer_empty; bool m_flush; - int m_nChannels; bool m_DecoderOpen; bool m_bad_state; @@ -100,14 +99,13 @@ public: double GetCurrentPts() { return m_audioClock; }; void SubmitEOS(); - void RegisterAudioCallback(IAudioCallback* pCallback) { m_omxAudio.RegisterAudioCallback(pCallback); } - void UnRegisterAudioCallback() { m_omxAudio.UnRegisterAudioCallback(); } void SetVolume(float fVolume) { m_omxAudio.SetVolume(fVolume); } void SetMute(bool bOnOff) { m_omxAudio.SetMute(bOnOff); } void SetDynamicRangeCompression(long drc) { m_omxAudio.SetDynamicRangeCompression(drc); } float GetDynamicRangeAmplification() const { return m_omxAudio.GetDynamicRangeAmplification(); } void SetSpeed(int iSpeed); int GetAudioBitrate(); + int GetAudioChannels(); std::string GetPlayerInfo(); bool BadState() { return m_bad_state; } diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp index af7123523d..7a30c6c689 100644 --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp @@ -47,7 +47,7 @@ #include "cores/VideoRenderers/RenderFlags.h" #include "guilib/GraphicContext.h" -#include "OMXPlayer.h" +#include "DVDPlayer.h" #include "linux/RBP.h" using namespace RenderManager; @@ -422,15 +422,27 @@ void OMXPlayerVideo::Process() } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { - COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value; - double pts = m_iCurrentPts; - double stamp = m_av_clock->OMXMediaTime(); + CDVDPlayer::SPlayerState& state = ((CDVDMsgType<CDVDPlayer::SPlayerState>*)pMsg)->m_value; - if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK) - state.time = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset); + if (m_speed != DVD_PLAYSPEED_NORMAL && m_speed != DVD_PLAYSPEED_PAUSE) + { + if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) + state.time = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset); + else + state.timestamp = CDVDClock::GetAbsoluteClock(); + } else - state.time = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts); - state.timestamp = m_av_clock->GetAbsoluteClock(); + { + double pts = m_iCurrentPts; + double stamp = m_av_clock->OMXMediaTime(); + if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) + state.time = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset); + else + state.time = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts); + state.timestamp = CDVDClock::GetAbsoluteClock(); + if (stamp == 0.0) // cause message to be ignored + state.player = 0; + } state.player = DVDPLAYER_VIDEO; m_messageParent.Put(pMsg->Acquire()); } @@ -592,11 +604,6 @@ void OMXPlayerVideo::SubmitEOS() m_omxVideo.SubmitEOS(); } -bool OMXPlayerVideo::SubmittedEOS() -{ - return m_omxVideo.SubmittedEOS(); -} - bool OMXPlayerVideo::IsEOS() { return m_omxVideo.IsEOS(); diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h index 556f9ea892..7908ee57a2 100644 --- a/xbmc/cores/omxplayer/OMXPlayerVideo.h +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h @@ -38,7 +38,7 @@ #include "linux/DllBCM.h" #include "cores/VideoRenderers/RenderManager.h" -class OMXPlayerVideo : public CThread, public IDVDStreamPlayer +class OMXPlayerVideo : public CThread, public IDVDStreamPlayerVideo { protected: CDVDMessageQueue m_messageQueue; @@ -107,7 +107,7 @@ public: double GetCurrentPts() { return m_iCurrentPts; }; double GetFPS() { return m_fFrameRate; }; void SubmitEOS(); - bool SubmittedEOS(); + bool SubmittedEOS() const { return m_omxVideo.SubmittedEOS(); } void SetDelay(double delay) { m_iVideoDelay = delay; } double GetDelay() { return m_iVideoDelay; } void SetSpeed(int iSpeed); diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp index b9256eaf5d..0363aaad3b 100644 --- a/xbmc/cores/omxplayer/OMXVideo.cpp +++ b/xbmc/cores/omxplayer/OMXVideo.cpp @@ -851,9 +851,10 @@ void COMXVideo::Reset(void) return; m_setStartTime = true; - m_omx_decoder.FlushInput(); + m_omx_decoder.FlushAll(); if(m_deinterlace) - m_omx_image_fx.FlushInput(); + m_omx_image_fx.FlushAll(); + m_omx_sched.FlushAll(); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h index 226000e925..c8fd5fbce4 100644 --- a/xbmc/cores/omxplayer/OMXVideo.h +++ b/xbmc/cores/omxplayer/OMXVideo.h @@ -63,7 +63,7 @@ public: int GetInputBufferSize(); void SubmitEOS(); bool IsEOS(); - bool SubmittedEOS() { return m_submitted_eos; } + bool SubmittedEOS() const { return m_submitted_eos; } bool BadState() { return m_omx_decoder.BadState(); }; protected: // Video format diff --git a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml index 77c6a155cd..1d4b72eb1a 100644 --- a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml +++ b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <advancedsettings> <video> - <defaultplayer>omxplayer</defaultplayer> - <defaultdvdplayer>omxplayer</defaultdvdplayer> + <defaultplayer>dvdplayer</defaultplayer> + <defaultdvdplayer>dvdplayer</defaultdvdplayer> </video> </advancedsettings> diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h index c590cca364..696a26c170 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h +++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h @@ -24,9 +24,6 @@ #include "PlayerCoreFactory.h" #include "cores/dvdplayer/DVDPlayer.h" #include "cores/paplayer/PAPlayer.h" -#if defined(HAS_OMXPLAYER) -#include "cores/omxplayer/OMXPlayer.h" -#endif #include "cores/ExternalPlayer/ExternalPlayer.h" #ifdef HAS_UPNP #include "network/upnp/UPnPPlayer.h" @@ -97,20 +94,9 @@ public: switch(m_eCore) { case EPC_MPLAYER: - // TODO: this hack needs removal until we have a better player selection -#if defined(HAS_OMXPLAYER) - case EPC_DVDPLAYER: - pPlayer = new COMXPlayer(callback); - CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as DVDPlayer", "OMXPlayer", m_eCore); - break; -#else case EPC_DVDPLAYER: pPlayer = new CDVDPlayer(callback); break; -#endif case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break; case EPC_EXTPLAYER: pPlayer = new CExternalPlayer(callback); break; -#if defined(HAS_OMXPLAYER) - case EPC_OMXPLAYER: pPlayer = new COMXPlayer(callback); break; -#endif #if defined(HAS_UPNP) case EPC_UPNPPLAYER: pPlayer = new UPNP::CUPnPPlayer(callback, m_id.c_str()); break; #endif diff --git a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp index f0990b0b8f..09d09e643b 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp +++ b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp @@ -342,13 +342,6 @@ bool CPlayerCoreFactory::LoadConfiguration(const std::string &file, bool clear) paplayer->m_bPlaysAudio = true; m_vecCoreConfigs.push_back(paplayer); -#if defined(HAS_OMXPLAYER) - CPlayerCoreConfig* omxplayer = new CPlayerCoreConfig("OMXPlayer", EPC_OMXPLAYER, NULL); - omxplayer->m_bPlaysAudio = true; - omxplayer->m_bPlaysVideo = true; - m_vecCoreConfigs.push_back(omxplayer); -#endif - for(std::vector<CPlayerSelectionRule *>::iterator it = m_vecCoreSelectionRules.begin(); it != m_vecCoreSelectionRules.end(); ++it) delete *it; m_vecCoreSelectionRules.clear(); diff --git a/xbmc/cores/playercorefactory/PlayerCoreFactory.h b/xbmc/cores/playercorefactory/PlayerCoreFactory.h index 70c50e2ce0..3f0e4a4c6b 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreFactory.h +++ b/xbmc/cores/playercorefactory/PlayerCoreFactory.h @@ -44,9 +44,6 @@ enum EPLAYERCORES EPC_DVDPLAYER, EPC_MPLAYER, EPC_PAPLAYER, -#if defined(HAS_OMXPLAYER) - EPC_OMXPLAYER, -#endif EPC_EXTPLAYER, EPC_UPNPPLAYER, }; @@ -57,9 +54,6 @@ const PLAYERCOREID PCID_NONE = EPC_NONE; const PLAYERCOREID PCID_DVDPLAYER = EPC_DVDPLAYER; const PLAYERCOREID PCID_MPLAYER = EPC_MPLAYER; const PLAYERCOREID PCID_PAPLAYER = EPC_PAPLAYER; -#if defined(HAS_OMXPLAYER) -const PLAYERCOREID PCID_OMXPLAYER = EPC_OMXPLAYER; -#endif class CPlayerCoreFactory : public ISettingsHandler { diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp index c631ab670d..80219a0d6d 100644 --- a/xbmc/linux/OMXClock.cpp +++ b/xbmc/linux/OMXClock.cpp @@ -33,7 +33,6 @@ #include "utils/MathUtils.h" #define OMX_PRE_ROLL 200 -#define TP(speed) ((speed) < 0 || (speed) > 4*DVD_PLAYSPEED_NORMAL) OMXClock::OMXClock() { @@ -492,10 +491,7 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume OMX_TIME_CONFIG_SCALETYPE scaleType; OMX_INIT_STRUCTURE(scaleType); - if (TP(speed)) - scaleType.xScale = 0; // for trickplay we just pause, and single step - else - scaleType.xScale = (speed << 16) / DVD_PLAYSPEED_NORMAL; + scaleType.xScale = (speed << 16) / DVD_PLAYSPEED_NORMAL; omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType); if(omx_err != OMX_ErrorNone) { @@ -515,6 +511,24 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume return true; } +bool OMXClock::OMXFlush(bool lock) +{ + if(m_omx_clock.GetComponent() == NULL) + return false; + + if(lock) + Lock(); + + CLog::Log(LOGDEBUG, "OMXClock::OMXFlush"); + + m_omx_clock.FlushAll(); + + if(lock) + UnLock(); + + return true; +} + bool OMXClock::HDMIClockSync(bool lock /* = true */) { if(m_omx_clock.GetComponent() == NULL) diff --git a/xbmc/linux/OMXClock.h b/xbmc/linux/OMXClock.h index 7bb6d4d1cf..8f0613487d 100644 --- a/xbmc/linux/OMXClock.h +++ b/xbmc/linux/OMXClock.h @@ -83,6 +83,7 @@ public: bool OMXResume(bool lock = true); bool OMXSetSpeed(int speed, bool lock = true, bool pause_resume = false); int OMXPlaySpeed() { return m_omx_speed; }; + bool OMXFlush(bool lock = true); COMXCoreComponent *GetOMXClock(); bool OMXStateExecute(bool lock = true); void OMXStateIdle(bool lock = true); diff --git a/xbmc/settings/SettingConditions.cpp b/xbmc/settings/SettingConditions.cpp index 7b615127d1..c1cdfc1c0f 100644 --- a/xbmc/settings/SettingConditions.cpp +++ b/xbmc/settings/SettingConditions.cpp @@ -227,6 +227,9 @@ void CSettingConditions::Initialize() #ifdef HAVE_LIBOPENMAX m_simpleConditions.insert("have_libopenmax"); #endif +#ifdef HAS_OMXPLAYER + m_simpleConditions.insert("has_omxplayer"); +#endif #ifdef HAVE_LIBVA m_simpleConditions.insert("have_libva"); #endif |