2012-04-24, 21:18
Issue: With some OGM files - for example containing XviD with packed bitstream - pullup pattern corrections fails, causing heavily choppy playback. Detailed description and debug log see here.
Cause: Some frames are returned with an incorrect pts (ie. earlier than the preceding frame), resulting in negative frame duration which confuses CPullupCorrection. I assume that the broken pts is returned by the decoder or demuxer.
Fix: When encountering an obviously broken pts, replace it with a proper/better one calculated from the stream's frame rate.
Please review and comment.
Patch:
Patched against 2fdc4dfac3 (2012-04-22)
Cause: Some frames are returned with an incorrect pts (ie. earlier than the preceding frame), resulting in negative frame duration which confuses CPullupCorrection. I assume that the broken pts is returned by the decoder or demuxer.
Fix: When encountering an obviously broken pts, replace it with a proper/better one calculated from the stream's frame rate.
Please review and comment.
Patch:
Code:
---
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 ++++
xbmc/cores/dvdplayer/DVDTSCorrection.cpp | 6 ++++++
xbmc/cores/dvdplayer/DVDTSCorrection.h | 2 +-
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 64f08df..5590044 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -1141,6 +1141,10 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
if(m_fFrameRate * abs(m_speed) / DVD_PLAYSPEED_NORMAL > maxfps*0.9)
limited = true;
+ // decoder/demuxer might return an incorrect timestamp that will
+ // cause pattern detection to fail, so we ignore an obviously broken pts
+ // and use the given frame rate to calculate a better one instead
+ pts = m_pullupCorrection.GetPlausiblePTS(pts,m_fFrameRate);
//correct any pattern in the timestamps
m_pullupCorrection.Add(pts);
pts += m_pullupCorrection.GetCorrection();
diff --git a/xbmc/cores/dvdplayer/DVDTSCorrection.cpp b/xbmc/cores/dvdplayer/DVDTSCorrection.cpp
index 20d40e6..08d85b5 100644
--- a/xbmc/cores/dvdplayer/DVDTSCorrection.cpp
+++ b/xbmc/cores/dvdplayer/DVDTSCorrection.cpp
@@ -48,6 +48,12 @@ void CPullupCorrection::Flush()
m_trackingpts = DVD_NOPTS_VALUE;
}
+double CPullupCorrection::GetPlausiblePTS(double pts, double framerate)
+{
+ if (m_prevpts != DVD_NOPTS_VALUE && pts < m_prevpts) return m_prevpts + 1000000 / framerate;
+ else return pts;
+}
+
void CPullupCorrection::Add(double pts)
{
//can't get a diff with just one pts
diff --git a/xbmc/cores/dvdplayer/DVDTSCorrection.h b/xbmc/cores/dvdplayer/DVDTSCorrection.h
index ded74b2..f975aba 100644
--- a/xbmc/cores/dvdplayer/DVDTSCorrection.h
+++ b/xbmc/cores/dvdplayer/DVDTSCorrection.h
@@ -31,7 +31,7 @@ class CPullupCorrection
CPullupCorrection();
void Add(double pts);
void Flush(); //flush the saved pattern and the ringbuffer
-
+ double GetPlausiblePTS(double pts, double framerate);
double GetCorrection() { return m_ptscorrection; }
int GetPatternLength() { return m_patternlength; }
double GetFrameDuration() { return m_frameduration; }
--