Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
renderer: squash to buffering
  • Loading branch information
FernetMenta committed Mar 26, 2012
1 parent 2c08ff4 commit cf92e19
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 43 deletions.
10 changes: 7 additions & 3 deletions xbmc/cores/VideoRenderers/RenderManager.cpp
Expand Up @@ -246,6 +246,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
m_bReconfigured = true;
m_presentstep = PRESENT_IDLE;
m_presentevent.Set();
ResetRenderBuffer();
}

return result;
Expand Down Expand Up @@ -930,8 +931,9 @@ void CXBMCRenderManager::PrepareNextRender()
presenttime = clocktime + MAXPRESENTDELAY;

m_sleeptime = presenttime - clocktime;
m_presentPts = m_renderBuffers[idx].pts;

if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime)
if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01)
{
m_presenttime = presenttime;
m_presentmethod = m_renderBuffers[idx].presentmethod;
Expand Down Expand Up @@ -970,10 +972,12 @@ void CXBMCRenderManager::NotifyDisplayFlip()
m_flipEvent.Set();
}

double CXBMCRenderManager::GetLastSleeptime()
bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts)
{
CSharedLock lock(m_sharedSection);
return m_sleeptime;
sleeptime = m_sleeptime;
pts = m_presentPts;
return true;
}

bool CXBMCRenderManager::HasFrame()
Expand Down
3 changes: 2 additions & 1 deletion xbmc/cores/VideoRenderers/RenderManager.h
Expand Up @@ -185,7 +185,7 @@ class CXBMCRenderManager

int WaitForBuffer(volatile bool& bStop);
void NotifyDisplayFlip();
double GetLastSleeptime();
bool GetStats(double &sleeptime, double &pts);
bool HasFrame();

protected:
Expand Down Expand Up @@ -266,6 +266,7 @@ class CXBMCRenderManager
}m_renderBuffers[5];

double m_sleeptime;
double m_presentPts;

double m_presenttime;
double m_presentcorr;
Expand Down
5 changes: 5 additions & 0 deletions xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
Expand Up @@ -242,6 +242,11 @@ class CDVDVideoCodec
return 0;
}

virtual bool GetPts(double &pts)
{
return false;
}

virtual void NormalSpeed(bool normal)
{
return;
Expand Down
7 changes: 7 additions & 0 deletions xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
Expand Up @@ -142,6 +142,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec()
m_iLastKeyframe = 0;
m_dts = DVD_NOPTS_VALUE;
m_started = false;
m_decoderPts = DVD_NOPTS_VALUE;
}

CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
Expand Down Expand Up @@ -570,6 +571,7 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts)
void CDVDVideoCodecFFmpeg::Reset()
{
m_started = false;
m_decoderPts = DVD_NOPTS_VALUE;
m_iLastKeyframe = m_pCodecContext->has_b_frames;
m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);

Expand Down Expand Up @@ -675,6 +677,11 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
else
pDvdVideoPicture->pts = DVD_NOPTS_VALUE;

if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
m_decoderPts = pDvdVideoPicture->pts;
else
m_decoderPts = m_dts;

if(!m_started)
pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;

Expand Down
2 changes: 2 additions & 0 deletions xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
Expand Up @@ -60,6 +60,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
virtual unsigned int SetFilters(unsigned int filters);
virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
virtual unsigned GetConvergeCount();
virtual bool GetPts(double &pts) {pts=m_decoderPts; return true;}

bool IsHardwareAllowed() { return !m_bSoftware; }
IHardwareDecoder * GetHardware() { return m_pHardware; };
Expand Down Expand Up @@ -108,4 +109,5 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
int m_iLastKeyframe;
double m_dts;
bool m_started;
double m_decoderPts, m_decoderInterval;
};
123 changes: 85 additions & 38 deletions xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
Expand Up @@ -314,6 +314,7 @@ void CDVDPlayerVideo::Process()
int iDropDirective;

m_videoStats.Start();
m_droppingStats.Reset();

while (!m_bStop)
{
Expand Down Expand Up @@ -416,6 +417,7 @@ void CDVDPlayerVideo::Process()
m_pVideoCodec->Reset();
m_packets.clear();
m_started = false;
m_droppingStats.Reset();
}
else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
{
Expand All @@ -427,6 +429,7 @@ void CDVDPlayerVideo::Process()
//we need to recalculate the framerate
//TODO: this needs to be set on a streamchange instead
ResetFrameRateCalc();
m_droppingStats.Reset();

m_stalled = true;
m_started = false;
Expand Down Expand Up @@ -490,7 +493,7 @@ void CDVDPlayerVideo::Process()
}
#endif

iDropDirective = CalcDropRequirement();
iDropDirective = CalcDropRequirement(pts, frametime);
if (iDropDirective & EOS_VERYLATE)
bRequestDrop = true;

Expand Down Expand Up @@ -529,7 +532,7 @@ void CDVDPlayerVideo::Process()
if(m_pVideoCodec->GetConvergeCount() > 0)
{
m_packets.push_back(DVDMessageListItem(pMsg, 0));
if(m_packets.size() > m_pVideoCodec->GetConvergeCount()
if(m_packets.size() > m_pVideoCodec->GetConvergeCount()
|| m_packets.size() * frametime > DVD_SEC_TO_TIME(10))
m_packets.pop_front();
}
Expand Down Expand Up @@ -1583,55 +1586,99 @@ void CDVDPlayerVideo::CalcFrameRate()
}
}

int CDVDPlayerVideo::CalcDropRequirement()
int CDVDPlayerVideo::CalcDropRequirement(double pts, double frametime)
{
int result = 0;
double iSleepTime = g_renderManager.GetLastSleeptime();
// double correct = 0.0;
// if (iSleepTime == m_iLastSleepTime && m_iLateFrames > 10)
// correct = 0.02;
//
// m_iLastSleepTime = iSleepTime;
// iSleepTime += correct;
double iSleepTime;
double iDecoderPts, iRenderPts;
double iInterval;
double iGain;
double iLateness;

// get decoder stats
if (!m_pVideoCodec->GetPts(iDecoderPts))
iDecoderPts = pts;

iInterval = frametime;;

// get render stats
g_renderManager.GetStats(iSleepTime, iRenderPts);
// add any gains regardless of being late
if (m_droppingStats.m_lastDecoderPts > 0)
{
iGain = (iDecoderPts - m_droppingStats.m_lastDecoderPts - iInterval)/(double)DVD_TIME_BASE;
if (iGain > 0)
{
CDroppingStats::CGain gain;
gain.gain = iGain;
gain.pts = iDecoderPts;
m_droppingStats.m_gain.push_back(gain);
m_droppingStats.m_totalGain += iGain;
}
}
m_droppingStats.m_lastDecoderPts = iDecoderPts;

int urgent = iSleepTime < -0.2 ? 1 : 2;
if (m_speed != DVD_PLAYSPEED_NORMAL)
urgent = 2;
// subtract gains
while (!m_droppingStats.m_gain.empty() &&
iRenderPts >= m_droppingStats.m_gain.front().pts)
{
m_droppingStats.m_totalGain -= m_droppingStats.m_gain.front().gain;
m_droppingStats.m_gain.pop_front();
}

if (iSleepTime <= 0 && m_speed)
m_iLateFrames++;
else
m_iLateFrames = 0;
// if (iSleepTime < 0)
// {
// CLog::Log(LOGNOTICE,"----- sleep: %f, gain :%f",
// iSleepTime, m_droppingStats.m_totalGain);
// }

// ask decoder to drop frames next round, as we are very late
if(m_iLateFrames > 10)
// calculate lateness
iLateness = iSleepTime + m_droppingStats.m_totalGain;
if (iLateness < 0 && m_speed)
{
if (m_iNrOfPicturesNotToSkip <= 0)
{
//if we're calculating the framerate,
//don't drop frames until we've calculated a stable framerate
if ((m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL)
&& m_iLateFrames % urgent)
{
// CLog::Log(LOGNOTICE,"------- late2: %f", iSleepTime);
result |= EOS_VERYLATE;
m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it
}
m_droppingStats.m_lateFrames++;

//if we requested 5 drops in a row and we're still late, drop on output
//this keeps a/v sync if the decoder can't drop, or we're still calculating the framerate
if (m_iDroppedRequest > 5)
// if lateness is smaller than frametime, we observe this state
// for 10 cycles
if (m_droppingStats.m_lateFrames > 10 || iLateness < -1/m_fFrameRate)
{
// is frame allowed to skip
if (m_iNrOfPicturesNotToSkip <= 0)
{
m_iDroppedRequest--; //decrease so we only drop half the frames
result |= EOS_DROPPED;
// try decoder dropping
if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL)
{
result |= EOS_VERYLATE;
m_pullupCorrection.Flush();
// CLog::Log(LOGNOTICE,"-------- drop decoder");
}
// drop in output
if (m_droppingStats.m_dropRequests > 5)
{
m_droppingStats.m_dropRequests--; //decrease so we only drop half the frames
result |= EOS_DROPPED;
// CLog::Log(LOGNOTICE,"-------- drop output");
}
else
m_droppingStats.m_dropRequests++;
}
else
m_iDroppedRequest++;
}
else
CLog::Log(LOGNOTICE,"-------- no drop allowed: %d", m_iNrOfPicturesNotToSkip);
}
else
{
m_iDroppedRequest = 0;
m_droppingStats.m_dropRequests = 0;
m_droppingStats.m_lateFrames = 0;
}
return result;
}

void CDroppingStats::Reset()
{
m_gain.clear();
m_totalGain = 0;
m_lastDecoderPts = 0;
m_lateFrames = 0;
m_dropRequests = 0;
}
21 changes: 20 additions & 1 deletion xbmc/cores/dvdplayer/DVDPlayerVideo.h
Expand Up @@ -38,6 +38,23 @@ class CDVDOverlayCodecCC;

#define VIDEO_PICTURE_QUEUE_SIZE 1

class CDroppingStats
{
public:
void Reset();
struct CGain
{
double gain;
double pts;
};
std::deque<CGain> m_gain;
double m_totalGain;
double m_lastDecoderPts;
unsigned int m_lateFrames;
unsigned int m_dropRequests;
};


class CDVDPlayerVideo : public CThread
{
public:
Expand Down Expand Up @@ -134,7 +151,7 @@ class CDVDPlayerVideo : public CThread

void ResetFrameRateCalc();
void CalcFrameRate();
int CalcDropRequirement();
int CalcDropRequirement(double pts, double frametime);

double m_fFrameRate; //framerate of the video currently playing
bool m_bCalcFrameRate; //if we should calculate the framerate from the timestamps
Expand Down Expand Up @@ -195,5 +212,7 @@ class CDVDPlayerVideo : public CThread
CPullupCorrection m_pullupCorrection;

std::list<DVDMessageListItem> m_packets;

CDroppingStats m_droppingStats;
};

0 comments on commit cf92e19

Please sign in to comment.