From 7b25783f7c1ad9af40972f315b9d3381b40457f6 Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Mon, 9 Sep 2019 10:36:39 +0100 Subject: [PATCH] [videoplayer] fix commercial skip (EDL's) from recordings and library sources --- xbmc/cores/VideoPlayer/Edl.cpp | 66 ++++++++------------------ xbmc/cores/VideoPlayer/Edl.h | 2 +- xbmc/cores/VideoPlayer/VideoPlayer.cpp | 10 ++-- 3 files changed, 26 insertions(+), 52 deletions(-) diff --git a/xbmc/cores/VideoPlayer/Edl.cpp b/xbmc/cores/VideoPlayer/Edl.cpp index 039614edc792b..5e2b0d63189fe 100644 --- a/xbmc/cores/VideoPlayer/Edl.cpp +++ b/xbmc/cores/VideoPlayer/Edl.cpp @@ -39,48 +39,8 @@ void CEdl::Clear() m_lastCutTime = 0; } -bool CEdl::ReadEditDecisionLists(const CFileItem& fileItem, const float fFrameRate, const int iHeight) +bool CEdl::ReadEditDecisionLists(const CFileItem& fileItem, const float fFramesPerSecond) { - /* - * The frame rate hints returned from ffmpeg for the video stream do not appear to take into - * account whether the content is interlaced. This affects the calculation to time offsets based - * on frames per second as most commercial detection programs use full frames, which need two - * interlaced fields to calculate a single frame so the actual frame rate is half. - * - * Adjust the frame rate using the detected frame rate or height to determine typical interlaced - * content (obtained from http://en.wikipedia.org/wiki/Frame_rate) - * - * Note that this is a HACK and we should be able to get the frame rate from the source sending - * back frame markers. However, this doesn't seem possible for MythTV. - */ - float fFramesPerSecond; - if (iHeight <= 480 && int(fFrameRate * 100) == 5994) // 59.940 fps = NTSC or 60i content except for 1280x720/60 - { - fFramesPerSecond = fFrameRate / 2; // ~29.97f - division used to retain accuracy of original. - CLog::Log(LOGDEBUG, "%s - Assuming NTSC or 60i interlaced content. Adjusted frames per second from %.3f (~59.940 fps) to %.3f", - __FUNCTION__, fFrameRate, fFramesPerSecond); - } - else if (int(fFrameRate * 100) == 4795) // 47.952 fps = 24p -> NTSC conversion - { - fFramesPerSecond = fFrameRate / 2; // ~23.976f - division used to retain accuracy of original. - CLog::Log(LOGDEBUG, "%s - Assuming 24p -> NTSC conversion interlaced content. Adjusted frames per second from %.3f (~47.952 fps) to %.3f", - __FUNCTION__, fFrameRate, fFramesPerSecond); - } - else if (iHeight == 576 && fFrameRate > 30.0) // PAL @ 50.0fps rather than PAL @ 25.0 fps. Can't use direct fps check of 50.0 as this is valid for 720p - { - fFramesPerSecond = fFrameRate / 2; // ~25.0f - division used to retain accuracy of original. - CLog::Log(LOGDEBUG, "%s - Assuming PAL interlaced content. Adjusted frames per second from %.3f (~50.00 fps) to %.3f", - __FUNCTION__, fFrameRate, fFramesPerSecond); - } - else if (iHeight == 1080 && fFrameRate > 30.0) // Don't know of any 1080p content being broadcast at higher than 30.0 fps so assume 1080i - { - fFramesPerSecond = fFrameRate / 2; - CLog::Log(LOGDEBUG, "%s - Assuming 1080i interlaced content. Adjusted frames per second from %.3f to %.3f", - __FUNCTION__, fFrameRate, fFramesPerSecond); - } - else // Assume everything else is not interlaced, e.g. 720p. - fFramesPerSecond = fFrameRate; - bool bFound = false; /* @@ -225,7 +185,16 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) } else if (strFields[i][0] == '#') // #12345 format for frame number { - iCutStartEnd[i] = (int64_t)(atol(strFields[i].substr(1).c_str()) / fFramesPerSecond * 1000); // frame number to ms + if (fFramesPerSecond > 0.0f) + { + iCutStartEnd[i] = static_cast(std::atol(strFields[i].substr(1).c_str()) / fFramesPerSecond * 1000); // frame number to ms + } + else + { + CLog::Log(LOGERROR, "Edl::ReadEdl - Frame number not supported in EDL files when frame rate is unavailable (ts) - supplied frame number: %s", + strFields[i].substr(1).c_str()); + return false; + } } else // Plain old seconds in float format, e.g. 123.45 { @@ -335,9 +304,16 @@ bool CEdl::ReadComskip(const std::string& strMovie, const float fFramesPerSecond /* * Not all generated Comskip files have the frame rate information. */ - fFrameRate = fFramesPerSecond; - CLog::Log(LOGWARNING, "%s - Frame rate not in Comskip file. Using detected frames per second: %.3f", - __FUNCTION__, fFrameRate); + if (fFramesPerSecond > 0.0f) + { + fFrameRate = fFramesPerSecond; + CLog::Log(LOGWARNING, "Edl::ReadComskip - Frame rate not in Comskip file. Using detected frames per second: %.3f", fFrameRate); + } + else + { + CLog::Log(LOGERROR, "Edl::ReadComskip - Frame rate is unavailable and also not in Comskip file (ts)."); + return false; + } } else fFrameRate /= 100; // Reduce by factor of 100 to get fps. diff --git a/xbmc/cores/VideoPlayer/Edl.h b/xbmc/cores/VideoPlayer/Edl.h index 4334d2f28d8ef..a095d6163127e 100644 --- a/xbmc/cores/VideoPlayer/Edl.h +++ b/xbmc/cores/VideoPlayer/Edl.h @@ -33,7 +33,7 @@ class CEdl Action action; }; - bool ReadEditDecisionLists(const CFileItem& fileItem, const float fFramesPerSecond, const int iHeight); + bool ReadEditDecisionLists(const CFileItem& fileItem, const float fFramesPerSecond); void Clear(); bool HasCut() const; diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp index d8840ce4403b1..459d2aacc0fab 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp @@ -3770,12 +3770,10 @@ bool CVideoPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) // look for any EDL files m_Edl.Clear(); - if (hint.fpsrate > 0 && hint.fpsscale > 0) - { - float fFramesPerSecond = (float)m_CurrentVideo.hint.fpsrate / (float)m_CurrentVideo.hint.fpsscale; - m_Edl.ReadEditDecisionLists(m_item, fFramesPerSecond, m_CurrentVideo.hint.height); - } - + float fFramesPerSecond = 0.0f; + if (m_CurrentVideo.hint.fpsscale > 0.0f) + fFramesPerSecond = static_cast(m_CurrentVideo.hint.fpsrate) / static_cast(m_CurrentVideo.hint.fpsscale); + m_Edl.ReadEditDecisionLists(m_item, fFramesPerSecond); static_cast(player)->SetSpeed(m_streamPlayerSpeed); m_CurrentVideo.syncState = IDVDStreamPlayer::SYNC_STARTING; m_CurrentVideo.packets = 0;