mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-12-27 07:11:05 +01:00
Improved handling frame numbers to have a smoother progress display during replay of recordings with B-frames
This commit is contained in:
66
dvbplayer.c
66
dvbplayer.c
@@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: dvbplayer.c 4.2 2016/12/22 09:40:30 kls Exp $
|
||||
* $Id: dvbplayer.c 4.3 2016/12/22 10:43:10 kls Exp $
|
||||
*/
|
||||
|
||||
#include "dvbplayer.h"
|
||||
@@ -17,13 +17,14 @@
|
||||
|
||||
// --- cPtsIndex -------------------------------------------------------------
|
||||
|
||||
#define PTSINDEX_ENTRIES 500
|
||||
#define PTSINDEX_ENTRIES 1024
|
||||
|
||||
class cPtsIndex {
|
||||
private:
|
||||
struct tPtsIndex {
|
||||
uint32_t pts; // no need for 33 bit - some devices don't even supply the msb
|
||||
int index;
|
||||
bool independent;
|
||||
};
|
||||
tPtsIndex pi[PTSINDEX_ENTRIES];
|
||||
int w, r;
|
||||
@@ -33,8 +34,9 @@ public:
|
||||
cPtsIndex(void);
|
||||
void Clear(void);
|
||||
bool IsEmpty(void);
|
||||
void Put(uint32_t Pts, int Index);
|
||||
void Put(uint32_t Pts, int Index, bool Independent);
|
||||
int FindIndex(uint32_t Pts);
|
||||
int FindFrameNumber(uint32_t Pts);
|
||||
};
|
||||
|
||||
cPtsIndex::cPtsIndex(void)
|
||||
@@ -55,10 +57,11 @@ bool cPtsIndex::IsEmpty(void)
|
||||
return w == r;
|
||||
}
|
||||
|
||||
void cPtsIndex::Put(uint32_t Pts, int Index)
|
||||
void cPtsIndex::Put(uint32_t Pts, int Index, bool Independent)
|
||||
{
|
||||
cMutexLock MutexLock(&mutex);
|
||||
pi[w].pts = Pts;
|
||||
pi[w].independent = Independent;
|
||||
pi[w].index = Index;
|
||||
w = (w + 1) % PTSINDEX_ENTRIES;
|
||||
if (w == r)
|
||||
@@ -87,6 +90,36 @@ int cPtsIndex::FindIndex(uint32_t Pts)
|
||||
return Index;
|
||||
}
|
||||
|
||||
int cPtsIndex::FindFrameNumber(uint32_t Pts)
|
||||
{
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (w == r)
|
||||
return lastFound; // replay always starts at an I frame
|
||||
bool Valid = false;
|
||||
int d;
|
||||
int FrameNumber = 0;
|
||||
int UnplayedIFrame = 2; // GOPs may intersect, so we're looping until we found two unplayed I frames
|
||||
for (int i = r; i != w && UnplayedIFrame; ) {
|
||||
d = Pts - pi[i].pts;
|
||||
if (d > 0x7FFFFFFF)
|
||||
d = 0xFFFFFFFF - d; // handle rollover
|
||||
if (d > 0) {
|
||||
if (pi[i].independent) {
|
||||
FrameNumber = pi[i].index; // an I frame's index represents its frame number
|
||||
Valid = true;
|
||||
}
|
||||
else
|
||||
FrameNumber++; // for every played non-I frame, increase frame number
|
||||
}
|
||||
else
|
||||
if (pi[i].independent)
|
||||
--UnplayedIFrame;
|
||||
if (++i >= PTSINDEX_ENTRIES)
|
||||
i = 0;
|
||||
}
|
||||
return Valid ? FrameNumber : FindIndex(Pts); // fall back during trick speeds
|
||||
}
|
||||
|
||||
// --- cNonBlockingFileReader ------------------------------------------------
|
||||
|
||||
class cNonBlockingFileReader : public cThread {
|
||||
@@ -251,6 +284,7 @@ public:
|
||||
virtual double FramesPerSecond(void) { return framesPerSecond; }
|
||||
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId);
|
||||
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
|
||||
virtual bool GetFrameNumber(int &Current, int &Total);
|
||||
virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
|
||||
};
|
||||
|
||||
@@ -606,7 +640,7 @@ void cDvbPlayer::Action(void)
|
||||
pc = playFrame->Count();
|
||||
if (p) {
|
||||
if (playFrame->Index() >= 0 && playFrame->Pts() != 0)
|
||||
ptsIndex.Put(playFrame->Pts(), playFrame->Index());
|
||||
ptsIndex.Put(playFrame->Pts(), playFrame->Index(), playFrame->Independent());
|
||||
if (firstPacket) {
|
||||
if (isPesRecording) {
|
||||
PlayPes(NULL, 0);
|
||||
@@ -880,7 +914,7 @@ void cDvbPlayer::Goto(int Index, bool Still)
|
||||
if (playMode == pmPause)
|
||||
DevicePlay();
|
||||
DeviceStillPicture(b, r);
|
||||
ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index);
|
||||
ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index, true);
|
||||
}
|
||||
playMode = pmStill;
|
||||
readIndex = Index;
|
||||
@@ -925,6 +959,17 @@ bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDvbPlayer::GetFrameNumber(int &Current, int &Total)
|
||||
{
|
||||
if (index) {
|
||||
Current = ptsIndex.FindFrameNumber(DeviceGetSTC());
|
||||
Total = index->Last();
|
||||
return true;
|
||||
}
|
||||
Current = Total = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
|
||||
{
|
||||
Play = (playMode == pmPlay || playMode == pmFast);
|
||||
@@ -1011,6 +1056,15 @@ bool cDvbPlayerControl::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDvbPlayerControl::GetFrameNumber(int &Current, int &Total)
|
||||
{
|
||||
if (player) {
|
||||
player->GetFrameNumber(Current, Total);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDvbPlayerControl::GetReplayMode(bool &Play, bool &Forward, int &Speed)
|
||||
{
|
||||
return player && player->GetReplayMode(Play, Forward, Speed);
|
||||
|
||||
Reference in New Issue
Block a user