Fix for VFR files play issue (ticked #12012 i've opened). #1387

Closed
wants to merge 2 commits into
from
@@ -190,6 +190,7 @@ bool CDVDPlayerVideo::OpenStream( CDVDStreamInfo &hint )
formats = g_renderManager.SupportedFormats();
#endif
+ m_pullupCorrection.ResetVFRDetection();
if(hint.flags & AV_DISPOSITION_ATTACHED_PIC)
return false;
@@ -231,14 +232,15 @@ void CDVDPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec)
m_bFpsInvalid = (hint.fpsrate == 0 || hint.fpsscale == 0);
+ m_pullupCorrection.ResetVFRDetection();
m_bCalcFrameRate = CSettings::Get().GetBool("videoplayer.usedisplayasclock") ||
CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF;
ResetFrameRateCalc();
m_iDroppedRequest = 0;
m_iLateFrames = 0;
- if( m_fFrameRate > 100 || m_fFrameRate < 5 )
+ if( m_fFrameRate > 120 || m_fFrameRate < 5 )
{
CLog::Log(LOGERROR, "CDVDPlayerVideo::OpenStream - Invalid framerate %d, using forced 25fps and just trust timestamps", (int)m_fFrameRate);
m_fFrameRate = 25;
@@ -1483,9 +1485,11 @@ void CDVDPlayerVideo::CalcFrameRate()
//see if m_pullupCorrection was able to detect a pattern in the timestamps
//and is able to calculate the correct frame duration from it
double frameduration = m_pullupCorrection.GetFrameDuration();
+ if (m_pullupCorrection.VFRDetection())
+ frameduration = m_pullupCorrection.GetMinFrameDuration();
- if (frameduration == DVD_NOPTS_VALUE ||
- (g_advancedSettings.m_videoFpsDetect == 1 && m_pullupCorrection.GetPatternLength() > 1))
+ if ((frameduration == DVD_NOPTS_VALUE) ||
+ ((g_advancedSettings.m_videoFpsDetect == 1) && ((m_pullupCorrection.GetPatternLength() > 1) && !m_pullupCorrection.VFRDetection())))
{
//reset the stored framerates if no good framerate was detected
m_fStableFrameRate = 0.0;
@@ -26,14 +26,24 @@
#include <cmath>
#define MAXERR DVD_MSEC_TO_TIME(2.5)
+#define MINVALIDFRAMEDURATION DVD_MSEC_TO_TIME(8.33) // For VFR detection, max framerate allowed is 120fps
+#define MAXVALIDFRAMEDURATION DVD_MSEC_TO_TIME(200.0) // For VFR detection, min framerate allowed is 5fps
using namespace std;
CPullupCorrection::CPullupCorrection()
{
+ ResetVFRDetection();
Flush();
}
+void CPullupCorrection::ResetVFRDetection(void)
+{
+ m_minframeduration = DVD_NOPTS_VALUE;
+ m_maxframeduration = DVD_NOPTS_VALUE;
+ m_VFRCounter = 0;
+}
+
void CPullupCorrection::Flush()
{
m_pattern.clear();
@@ -82,7 +92,8 @@ void CPullupCorrection::Add(double pts)
{
if (m_haspattern)
{
- CLog::Log(LOGDEBUG, "CPullupCorrection: pattern lost on diff %f", GetDiff(0));
+ m_VFRCounter++;
+ CLog::Log(LOGDEBUG, "CPullupCorrection: pattern lost on diff %f, number of losses %i", GetDiff(0), m_VFRCounter);
Flush();
}
@@ -297,17 +308,59 @@ bool CPullupCorrection::CheckPattern(std::vector<double>& pattern)
}
//calculate how long each frame should last from the saved pattern
+//Retreive also information of max and min frame rate duration, for VFR files case
double CPullupCorrection::CalcFrameDuration()
{
if (!m_pattern.empty())
{
//take the average of all diffs in the pattern
- double frameduration = 0.0;
- for (unsigned int i = 0; i < m_pattern.size(); i++)
- frameduration += m_pattern[i];
+ double frameduration;
+ double current, currentmin, currentmax;
+ currentmin = m_pattern[0];
+ currentmax = currentmin;
+ frameduration = currentmin;
+ for (unsigned int i = 1; i < m_pattern.size(); i++)
+ {
+ current = m_pattern[i];
+ if (current > currentmax)
+ currentmax = current;
+ if (current < currentmin)
+ currentmin = current;
+ frameduration += current;
+ }
frameduration /= m_pattern.size();
+ // Update min and max frame duration, only if data is valid
+ if (m_minframeduration == DVD_NOPTS_VALUE)
+ {
+ if ((currentmin >= MINVALIDFRAMEDURATION) && (currentmin <= MAXVALIDFRAMEDURATION))
+ m_minframeduration=currentmin;
+ }
+ else
+ {
+ if ((currentmin < m_minframeduration) &&
+ ((currentmin >= MINVALIDFRAMEDURATION) && (currentmin <= MAXVALIDFRAMEDURATION)))
+ m_minframeduration = currentmin;
+ }
+
+ if (m_maxframeduration == DVD_NOPTS_VALUE)
+ {
+ if ((currentmax >= MINVALIDFRAMEDURATION) && (currentmax <= MAXVALIDFRAMEDURATION))
+ m_maxframeduration = currentmax;
+ }
+ else
+ {
+ if ((currentmax > m_maxframeduration) &&
+ ((currentmax >= MINVALIDFRAMEDURATION) && (currentmax <= MAXVALIDFRAMEDURATION)))
+ m_maxframeduration = currentmax;
+ }
+
+ //frameduration is not completely correct, use a common one if it's close
+ m_minframeduration = CDVDCodecUtils::NormalizeFrameduration(m_minframeduration);
+ m_maxframeduration = CDVDCodecUtils::NormalizeFrameduration(m_maxframeduration);
+ CLog::Log(LOGDEBUG, "CPullupCorrection: min frame duration %f, max frame duration %f", m_minframeduration, m_maxframeduration);
+
//frameduration is not completely correct, use a common one if it's close
return CDVDCodecUtils::NormalizeFrameduration(frameduration);
}
@@ -24,18 +24,23 @@
#include <vector>
#define DIFFRINGSIZE 120
+#define VFR_DETECTION_THRESHOLD 3
class CPullupCorrection
{
public:
CPullupCorrection();
void Add(double pts);
void Flush(); //flush the saved pattern and the ringbuffer
+ void ResetVFRDetection(void);
double GetCorrection() { return m_ptscorrection; }
int GetPatternLength() { return m_patternlength; }
double GetFrameDuration() { return m_frameduration; }
+ double GetMaxFrameDuration(void) { return m_maxframeduration; }
+ double GetMinFrameDuration(void) { return m_minframeduration; }
bool HasFullBuffer() { return m_ringfill == DIFFRINGSIZE; }
+ bool VFRDetection(void) { return (m_VFRCounter>=VFR_DETECTION_THRESHOLD); }
private:
double m_prevpts; //last pts added
@@ -63,7 +68,9 @@ class CPullupCorrection
double m_ptscorrection; //the correction needed for the last added pts
double m_trackingpts; //tracked pts for smoothing the timestamps
double m_frameduration; //frameduration exposed to dvdplayer, used for calculating the fps
- bool m_haspattern; //for the log
+ double m_maxframeduration; //Max value detected for frame duration (for VFR files case)
+ double m_minframeduration; //Min value detected for frame duration (for VFR files case)
+ bool m_haspattern; //for the log and detecting VFR files case
int m_patternlength; //for the codec info
std::string GetPatternStr(); //also for the log
};