Revision: 21327
http://xbmc.svn.sourceforge.net/xbmc/?rev=21327&view=rev
Author: bobo1on1
Date: 2009-07-01 19:35:52 +0000 (Wed, 01 Jul 2009)
Log Message:
-----------
added: correction for repeating patterns in picture timestamps
Modified Paths:
--------------
branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.cpp
branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.h
branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.h
branches/linuxport/XBMC/xbmc/cores/dvdplayer/Makefile
Added Paths:
-----------
branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.cpp
branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.h
Modified: branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.cpp
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.cpp 2009-07-01 19:01:46 UTC (rev 21326)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.cpp 2009-07-01 19:35:52 UTC (rev 21327)
@@ -207,14 +207,14 @@
return m_speedadjust;
}
-void CDVDClock::UpdateFramerate(double fps)
+bool CDVDClock::UpdateFramerate(double fps)
{
//sent with fps of 0 means we are not playing video
if(fps == 0.0)
{
CSingleLock lock(m_speedsection);
m_speedadjust = false;
- return;
+ return false;
}
//check if the videoreferenceclock is running, will return -1 if not
@@ -239,6 +239,9 @@
lock.Leave();
g_VideoReferenceClock.SetSpeed(speed);
+
+ return true;
}
+ return false;
}
Modified: branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.h
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.h 2009-07-01 19:01:46 UTC (rev 21326)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDClock.h 2009-07-01 19:35:52 UTC (rev 21327)
@@ -62,7 +62,7 @@
/* tells clock at what framerate video is, to *
* allow it to adjust speed for a better match */
- void UpdateFramerate(double fps);
+ bool UpdateFramerate(double fps);
bool SetMaxSpeedAdjust(double speed);
Modified: branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2009-07-01 19:01:46 UTC (rev 21326)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2009-07-01 19:35:52 UTC (rev 21327)
@@ -382,6 +382,8 @@
if(m_pVideoCodec)
m_pVideoCodec->Reset();
LeaveCriticalSection(&m_critCodecSection);
+
+ m_pullupCorrection.Flush();
}
else if (pMsg->IsType(CDVDMsg::VIDEO_NOSKIP))
{
@@ -836,6 +838,17 @@
if(m_fFrameRate * abs(m_speed) / DVD_PLAYSPEED_NORMAL > maxfps*0.9)
limited = true;
+ // signal to clock what our framerate is, it may want to adjust it's
+ // speed to better match with our video renderer's output speed
+ // TODO - this should be based on m_fFrameRate, as the timestamps
+ // in the stream matches that better, durations can vary
+ if (m_pClock->UpdateFramerate(1.0 / (pPicture->iDuration / DVD_TIME_BASE)))
+ {
+ //correct any pattern in the timestamps if the videoreferenceclock is running
+ m_pullupCorrection.Add(pts);
+ pts += m_pullupCorrection.Correction();
+ }
+
//User set delay
pts += m_iVideoDelay;
@@ -847,12 +860,6 @@
iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
iFrameDuration = pPicture->iDuration;
- // signal to clock what our framerate is, it may want to adjust it's
- // speed to better match with our video renderer's output speed
- // TODO - this should be based on m_fFrameRate, as the timestamps
- // in the stream matches that better, durations can vary
- m_pClock->UpdateFramerate(1.0 / (iFrameDuration / DVD_TIME_BASE));
-
// correct sleep times based on speed
if(m_speed)
{
Modified: branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.h
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.h 2009-07-01 19:01:46 UTC (rev 21326)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDPlayerVideo.h 2009-07-01 19:35:52 UTC (rev 21327)
@@ -27,6 +27,7 @@
#include "DVDCodecs/Video/DVDVideoCodec.h"
#include "DVDClock.h"
#include "DVDOverlayContainer.h"
+#include "DVDTSCorrection.h"
#ifdef HAS_VIDEO_PLAYBACK
#include "cores/VideoRenderers/RenderManager.h"
#endif
@@ -170,5 +171,7 @@
DVDVideoPicture* m_pTempOverlayPicture;
CRITICAL_SECTION m_critCodecSection;
+
+ CPullupCorrection m_pullupCorrection;
};
Added: branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.cpp
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.cpp (rev 0)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.cpp 2009-07-01 19:35:52 UTC (rev 21327)
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.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, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "stdafx.h"
+#include "../../Util.h"
+#include "DVDTSCorrection.h"
+
+using namespace std;
+
+CPullupCorrection::CPullupCorrection()
+{
+ Flush();
+}
+
+void CPullupCorrection::Flush()
+{
+ m_ringpos = 0;
+ m_ptscorrection = 0.0;
+ m_prevpts = 0.0;
+ m_patternpos = 0;
+ m_ringfill = 0;
+ m_pattern.clear();
+ m_haspattern = false;
+}
+
+void CPullupCorrection::Add(double pts)
+{
+ //can't get a diff with just one pts
+ if (m_prevpts == 0.0)
+ {
+ m_prevpts = pts;
+ return;
+ }
+
+ //increase the ringbuffer position
+ m_ringpos = (m_ringpos + 1) % DIFFRINGSIZE;
+ //add the current diff to the ringbuffer
+ m_diffring[m_ringpos] = pts - m_prevpts;
+ //save the pts
+ m_prevpts = pts;
+
+ //only search for patterns in a full ringbuffer
+ m_ringfill++;
+ if (m_ringfill < DIFFRINGSIZE)
+ return;
+
+ m_ringfill = DIFFRINGSIZE;
+
+ //get the current pattern in the ringbuffer
+ vector<double> pattern = GetPattern();
+
+ //check if the pattern is the same as the saved pattern
+ //and if it is actually a pattern
+ if (!CheckPattern(pattern))
+ {
+ m_ptscorrection = 0.0; //no pattern no correction
+ if (m_haspattern)
+ {
+ m_haspattern = false;
+ CLog::Log(LOGDEBUG, "CPullupCorrection: pattern lost");
+ }
+ return;
+ }
+ else if (!m_haspattern)
+ {
+ m_haspattern = true;
+ CLog::Log(LOGDEBUG, "CPullupCorrection: detected pattern of length %i", pattern.size());
+ }
+
+ //calculate where we are in the pattern
+ double ptsinpattern = 0.0;
+ for (int i = 0; i < m_patternpos; i++)
+ {
+ ptsinpattern += m_pattern[m_pattern.size() - i - 1];
+ }
+
+ double frameduration = CalcFrameDuration();
+
+ //correct the last pts based on where we should be according to the frame duration
+ m_ptscorrection = (frameduration * m_patternpos) - ptsinpattern;
+}
+
+//gets a diff diffnr into the past
+inline double CPullupCorrection::GetDiff(int diffnr)
+{
+ //m_ringpos is the last added diff, so if we want to go in the past we have to move back in the ringbuffer
+ int pos = m_ringpos - diffnr;
+ if (pos < 0) pos += DIFFRINGSIZE;
+
+ return m_diffring[pos];
+}
+
+//calculate the current pattern in the ringbuffer
+std::vector<double> CPullupCorrection::GetPattern()
+{
+ vector<double> difftypes = GetDifftypes(); //get the difftypes
+ vector<double> pattern; //where we store the pattern
+ int difftypesbuff[DIFFRINGSIZE]; //difftypes of the diffs, difftypesbuff[0] is the last added diff,
+ //difftypesbuff[1] the one added before that etc
+
+ //less than 2 difftypes is not a pattern
+ if (difftypes.size() < 2)
+ return pattern;
+
+ //mark each diff with what difftype it is
+ for (int i = 0; i < DIFFRINGSIZE; i++)
+ {
+ for (int j = 0; j < difftypes.size(); j++)
+ {
+ if (MatchDiff(GetDiff(i), difftypes[j]))
+ {
+ difftypesbuff[i] = j;
+ break;
+ }
+ }
+ }
+
+ //we check from patterns of 2 to DIFFRINGSIZE / 3
+ for (int i = 2; i <= DIFFRINGSIZE / 3; i++)
+ {
+ bool hasmatch = true;
+ for (int j = 1; j <= DIFFRINGSIZE / i; j++)
+ {
+ int nrdiffs = i;
+ //we want to check the full buffer to see if the pattern repeats
+ //but we can't go beyond the buffer
+ if (j * i + i > DIFFRINGSIZE)
+ nrdiffs = DIFFRINGSIZE - j * i;
+
+ if (nrdiffs < 1) //if the buffersize can be cleanly divided by i we're done here
+ break;
+
+ if (!MatchDifftype(difftypesbuff, difftypesbuff + j * i, nrdiffs))
+ {
+ hasmatch = false;
+ break;
+ }
+ }
+
+ if (hasmatch)
+ {
+ pattern = BuildPattern(i);
+ break;
+ }
+ }
+
+ return pattern;
+}
+
+//calculate the different types of diffs we have
+vector<double> CPullupCorrection::GetDifftypes()
+{
+ vector<double> difftypes;
+
+ for (int i = 0; i < DIFFRINGSIZE; i++)
+ {
+ bool hasmatch = false;
+ for (int j = 0; j < difftypes.size(); j++)
+ {
+ if (MatchDiff(GetDiff(i), difftypes[j]))
+ {
+ hasmatch = true;
+ break;
+ }
+ }
+
+ //if we don't have a match with a saved difftype, we add it as a new one
+ if (!hasmatch)
+ difftypes.push_back(GetDiff(i));
+ }
+
+ return difftypes;
+}
+
+//builds a pattern of timestamps in the ringbuffer
+std::vector<double> CPullupCorrection::BuildPattern(int patternlength)
+{
+ std::vector<double> pattern;
+
+ for (int i = 0; i < patternlength; i++)
+ {
+ double avgdiff = 0.0;
+ for (int j = 0; j < DIFFRINGSIZE / patternlength; j++)
+ {
+ avgdiff += GetDiff(j * patternlength + i);
+ }
+ avgdiff /= DIFFRINGSIZE / patternlength;
+ pattern.push_back(avgdiff);
+ }
+ return pattern;
+}
+
+#define MAXERR 0.01
+inline bool CPullupCorrection::MatchDiff(double diff1, double diff2)
+{
+ return fabs(1.0 - (diff1 / diff2)) <= MAXERR;
+}
+#undef MAXERR
+
+//check if diffs1 is the same as diffs2
+inline bool CPullupCorrection::MatchDifftype(int* diffs1, int* diffs2, int nrdiffs)
+{
+ for (int i = 0; i < nrdiffs; i++)
+ {
+ if (diffs1[i] != diffs2[i])
+ return false;
+ }
+ return true;
+}
+
+//check if our current detected pattern is the same as the one we saved
+bool CPullupCorrection::CheckPattern(std::vector<double>& pattern)
+{
+ //if the size of the patterns differ we don't have a match
+ //a pattern with a size less than 2 is not something we want to correct
+ if (pattern.size() != m_pattern.size() || pattern.size() < 2)
+ {
+ m_pattern = pattern; //save the current pattern
+ m_patternpos = 0; //reset the position
+ return false;
+ }
+
+ //the saved pattern should have moved 1 diff into the past
+ m_patternpos = (m_patternpos + 1) % m_pattern.size();
+
+ //check if the current pattern matches the saved pattern, with an offset of 1
+ for (int i = 0; i < m_pattern.size(); i++)
+ {
+ double diff = pattern[(m_patternpos + i) % pattern.size()];
+
+ if (!MatchDiff(diff, m_pattern[i]))
+ {
+ Flush(); //if the current pattern doesn't match the saved pattern, flush the ringbuffer
+ return false;
+ }
+ //we save the pattern, in case it changes very slowly
+ m_pattern[i] = diff;
+ }
+
+ return true;
+}
+
+//calculate how long each frame should last from the saved pattern
+double CPullupCorrection::CalcFrameDuration()
+{
+ double frameduration = 0.0;
+
+ for (int i = 0; i < m_pattern.size(); i++)
+ {
+ frameduration += m_pattern[i];
+ }
+ return frameduration / m_pattern.size();
+}
Added: branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.h
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.h (rev 0)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/DVDTSCorrection.h 2009-07-01 19:35:52 UTC (rev 21327)
@@ -0,0 +1,58 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.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, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <vector>
+
+#define DIFFRINGSIZE 100
+
+class CPullupCorrection
+{
+ public:
+ CPullupCorrection();
+ void Add(double pts);
+ double Correction() {return m_ptscorrection;}
+ void Flush(); //flush the saved pattern and the ringbuffer
+
+ private:
+ double m_prevpts; //last pts added
+ double m_diffring[DIFFRINGSIZE]; //ringbuffer of differences between pts'
+ int m_ringpos; //position of last diff added to ringbuffer
+ int m_ringfill; //how many diffs we have in the ringbuffer
+ double GetDiff(int diffnr); //gets diffs from now to the past
+
+ std::vector<double> GetPattern(); //gets the current pattern
+ std::vector<double> GetDifftypes(); //gets the difftypes from the ringbuffer
+ bool MatchDiff(double diff1, double diff2); //checks if two diffs match by MAXERR
+ bool MatchDifftype(int* diffs1, int* diffs2, int nrdiffs); //checks if the difftypes match
+ bool m_haspattern; //for the log
+
+ std::vector<double> m_pattern; //the last saved pattern
+ int m_patternpos; //the position of the pattern in the ringbuffer, moves one to the past each time a pts is added
+
+ std::vector<double> BuildPattern(int patternlength); //builds a pattern of timestamps in the ringbuffer
+ bool CheckPattern(std::vector<double>& pattern); //checks if the current pattern matches with the saved m_pattern
+ //with offset m_patternpos
+
+ double CalcFrameDuration(); //calculates the frame duration from m_pattern
+ double m_ptscorrection; //the correction needed for the last added pts
+};
Modified: branches/linuxport/XBMC/xbmc/cores/dvdplayer/Makefile
===================================================================
--- branches/linuxport/XBMC/xbmc/cores/dvdplayer/Makefile 2009-07-01 19:01:46 UTC (rev 21326)
+++ branches/linuxport/XBMC/xbmc/cores/dvdplayer/Makefile 2009-07-01 19:35:52 UTC (rev 21327)
@@ -17,7 +17,8 @@
DVDPlayerVideo.cpp \
DVDStreamInfo.cpp \
DVDFileInfo.cpp \
- DVDPlayerAudioResampler.cpp \
+ DVDPlayerAudioResampler.cpp \
+ DVDTSCorrection.cpp \
LIB= DVDPlayer.a
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|