summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS2
-rw-r--r--HISTORY2
-rw-r--r--dvbplayer.c66
-rw-r--r--dvbplayer.h6
-rw-r--r--menu.c67
-rw-r--r--menu.h3
-rw-r--r--player.h7
-rw-r--r--ringbuffer.c5
-rw-r--r--ringbuffer.h6
9 files changed, 120 insertions, 44 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index a695bc11..d89a6037 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -3328,6 +3328,8 @@ Thomas Reufer <thomas@reufer.ch>
for making the cPlayer member functions FramesPerSecond, GetIndex and GetReplayMode
'const'
for fixing resuming replay at a given position, which was off by one frame
+ for improving handling frame numbers to have a smoother progress display during
+ replay of recordings with B-frames
Eike Sauer <EikeSauer@t-online.de>
for reporting a problem with channels that need more than 5 TS packets for detecting
diff --git a/HISTORY b/HISTORY
index 4edf138c..722cebfe 100644
--- a/HISTORY
+++ b/HISTORY
@@ -8857,3 +8857,5 @@ Video Disk Recorder Revision History
'const' (thanks to Thomas Reufer).
- Fixed resuming replay at a given position, which was off by one frame (thanks
to Thomas Reufer).
+- Improved handling frame numbers to have a smoother progress display during
+ replay of recordings with B-frames (thanks to Thomas Reufer).
diff --git a/dvbplayer.c b/dvbplayer.c
index e5c9270b..6db497e3 100644
--- a/dvbplayer.c
+++ b/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);
diff --git a/dvbplayer.h b/dvbplayer.h
index ef6f1fce..2fe6e4c9 100644
--- a/dvbplayer.h
+++ b/dvbplayer.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbplayer.h 4.1 2015/08/02 13:01:44 kls Exp $
+ * $Id: dvbplayer.h 4.2 2016/12/22 10:36:50 kls Exp $
*/
#ifndef __DVBPLAYER_H
@@ -50,6 +50,10 @@ public:
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.
+ bool GetFrameNumber(int &Current, int &Total);
+ // Returns the current and total frame number. In contrast to GetIndex(),
+ // this function respects the chronological order of frames, which is
+ // different from its index for streams containing B frames (e.g. H264)
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
// Returns the current replay mode (if applicable).
// 'Play' tells whether we are playing or pausing, 'Forward' tells whether
diff --git a/menu.c b/menu.c
index 48889a48..30c95f8d 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 4.18 2016/12/13 12:49:10 kls Exp $
+ * $Id: menu.c 4.19 2016/12/22 11:00:13 kls Exp $
*/
#include "menu.h"
@@ -5435,6 +5435,7 @@ cReplayControl::cReplayControl(bool PauseLive)
lastPlay = lastForward = false;
lastSpeed = -2; // an invalid value
timeoutShow = 0;
+ lastProgressUpdate = 0;
timeSearchActive = false;
cRecording Recording(fileName);
cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
@@ -5583,41 +5584,43 @@ void cReplayControl::ShowMode(void)
bool cReplayControl::ShowProgress(bool Initial)
{
int Current, Total;
-
- if (GetIndex(Current, Total) && Total > 0) {
- if (!visible) {
- displayReplay = Skins.Current()->DisplayReplay(modeOnly);
- displayReplay->SetMarks(&marks);
- SetNeedsFastResponse(true);
- visible = true;
- }
- if (Initial) {
- if (*fileName) {
- LOCK_RECORDINGS_READ;
- if (const cRecording *Recording = Recordings->GetByName(fileName))
- displayReplay->SetRecording(Recording);
+ if (Initial || time(NULL) - lastProgressUpdate >= 1) {
+ if (GetFrameNumber(Current, Total) && Total > 0) {
+ if (!visible) {
+ displayReplay = Skins.Current()->DisplayReplay(modeOnly);
+ displayReplay->SetMarks(&marks);
+ SetNeedsFastResponse(true);
+ visible = true;
}
- lastCurrent = lastTotal = -1;
- }
- if (Current != lastCurrent || Total != lastTotal) {
- if (Setup.ShowRemainingTime || Total != lastTotal) {
- int Index = Total;
- if (Setup.ShowRemainingTime)
- Index = Current - Index;
- displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond()));
+ if (Initial) {
+ if (*fileName) {
+ LOCK_RECORDINGS_READ;
+ if (const cRecording *Recording = Recordings->GetByName(fileName))
+ displayReplay->SetRecording(Recording);
+ }
+ lastCurrent = lastTotal = -1;
+ }
+ if (Current != lastCurrent || Total != lastTotal) {
+ time(&lastProgressUpdate);
+ if (Setup.ShowRemainingTime || Total != lastTotal) {
+ int Index = Total;
+ if (Setup.ShowRemainingTime)
+ Index = Current - Index;
+ displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond()));
+ if (!Initial)
+ displayReplay->Flush();
+ }
+ displayReplay->SetProgress(Current, Total);
if (!Initial)
displayReplay->Flush();
- }
- displayReplay->SetProgress(Current, Total);
- if (!Initial)
+ displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, FramesPerSecond()));
displayReplay->Flush();
- displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, FramesPerSecond()));
- displayReplay->Flush();
- lastCurrent = Current;
+ lastCurrent = Current;
+ }
+ lastTotal = Total;
+ ShowMode();
+ return true;
}
- lastTotal = Total;
- ShowMode();
- return true;
}
return false;
}
@@ -5858,6 +5861,8 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
return osEnd;
if (Key == kNone && !marksModified)
marks.Update();
+ if (Key != kNone)
+ lastProgressUpdate = 0;
if (visible) {
if (timeoutShow && time(NULL) > timeoutShow) {
Hide();
diff --git a/menu.h b/menu.h
index 3f2878b3..9a971ad0 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 4.4 2015/09/13 14:17:56 kls Exp $
+ * $Id: menu.h 4.5 2016/12/22 10:55:36 kls Exp $
*/
#ifndef __MENU_H
@@ -300,6 +300,7 @@ private:
bool lastPlay, lastForward;
int lastSpeed;
time_t timeoutShow;
+ time_t lastProgressUpdate;
bool timeSearchActive, timeSearchHide;
int timeSearchTime, timeSearchPos;
void TimeSearchDisplay(void);
diff --git a/player.h b/player.h
index e53a952d..aeb8af8f 100644
--- a/player.h
+++ b/player.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: player.h 4.1 2016/12/22 09:22:27 kls Exp $
+ * $Id: player.h 4.2 2016/12/22 10:38:11 kls Exp $
*/
#ifndef __PLAYER_H
@@ -57,6 +57,10 @@ public:
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return false; }
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.
+ virtual bool GetFrameNumber(int &Current, int &Total) { return false; }
+ // Returns the current and total frame number. In contrast to GetIndex(),
+ // this function respects the chronological order of frames, which is
+ // different from its index for streams containing B frames (e.g. H264)
virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed) { return false; }
// Returns the current replay mode (if applicable).
// 'Play' tells whether we are playing or pausing, 'Forward' tells whether
@@ -100,6 +104,7 @@ public:
///< string. The default implementation returns an empty string.
double FramesPerSecond(void) const { return player->FramesPerSecond(); }
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) const { return player->GetIndex(Current, Total, SnapToIFrame); }
+ bool GetFrameNumber(int &Current, int &Total) const { return player->GetFrameNumber(Current, Total); }
bool GetReplayMode(bool &Play, bool &Forward, int &Speed) const { return player->GetReplayMode(Play, Forward, Speed); }
static void Launch(cControl *Control);
static void Attach(void);
diff --git a/ringbuffer.c b/ringbuffer.c
index abe78990..d33a4719 100644
--- a/ringbuffer.c
+++ b/ringbuffer.c
@@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
- * $Id: ringbuffer.c 2.5 2012/09/22 11:26:49 kls Exp $
+ * $Id: ringbuffer.c 4.1 2016/12/22 10:26:13 kls Exp $
*/
#include "ringbuffer.h"
@@ -390,12 +390,13 @@ void cRingBufferLinear::Del(int Count)
// --- cFrame ----------------------------------------------------------------
-cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index, uint32_t Pts)
+cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index, uint32_t Pts, bool Independent)
{
count = abs(Count);
type = Type;
index = Index;
pts = Pts;
+ independent = Type == ftAudio ? true : Independent;
if (Count < 0)
data = (uchar *)Data;
else {
diff --git a/ringbuffer.h b/ringbuffer.h
index 1fff611c..9699bbc8 100644
--- a/ringbuffer.h
+++ b/ringbuffer.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ringbuffer.h 2.5 2013/02/16 15:20:37 kls Exp $
+ * $Id: ringbuffer.h 4.1 2016/12/22 10:26:13 kls Exp $
*/
#ifndef __RINGBUFFER_H
@@ -113,8 +113,9 @@ private:
eFrameType type;
int index;
uint32_t pts;
+ bool independent;
public:
- cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1, uint32_t Pts = 0);
+ cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1, uint32_t Pts = 0, bool independent = false);
///< Creates a new cFrame object.
///< If Count is negative, the cFrame object will take ownership of the given
///< Data. Otherwise it will allocate Count bytes of memory and copy Data.
@@ -124,6 +125,7 @@ public:
eFrameType Type(void) const { return type; }
int Index(void) const { return index; }
uint32_t Pts(void) const { return pts; }
+ bool Independent(void) const { return independent; }
};
class cRingBufferFrame : public cRingBuffer {