summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2009-04-05 09:08:02 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2009-04-05 09:08:02 +0200
commitc886e69bc6371910a139c128aa37d76043892988 (patch)
tree1b8e765156485162e03f78c1805db3a0d785c36e
parent1b02cc9c9416f298be05f79e83abb7e4b0a1f164 (diff)
downloadvdr-c886e69bc6371910a139c128aa37d76043892988.tar.gz
vdr-c886e69bc6371910a139c128aa37d76043892988.tar.bz2
Improved replay at the begin and end of a recording; cDvbPlayer::Action() no longer calls DeviceFlush()
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY6
-rw-r--r--dvbplayer.c114
3 files changed, 64 insertions, 57 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 972d8706..b85ee360 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1200,6 +1200,7 @@ Reinhard Nissl <rnissl@gmx.de>
to cDevice::PlayTs()
for reporting that the PAT/PMT is processed too often, even if its version
hasn't changed
+ for making sure vdr-xine no longer needs cDvbPlayer::Action() to call DeviceFlush()
Richard Robson <richard_robson@beeb.net>
for reporting freezing replay if a timer starts while in Transfer Mode from the
diff --git a/HISTORY b/HISTORY
index c888c36b..e5c60680 100644
--- a/HISTORY
+++ b/HISTORY
@@ -5979,7 +5979,7 @@ Video Disk Recorder Revision History
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
new function works as expected.
-2009-03-28: Version 1.7.5
+2009-04-05: Version 1.7.5
- Fixed a hangup when replaying a TS recording with subtitles activated (reported
by Timo Helkio).
@@ -6009,3 +6009,7 @@ Video Disk Recorder Revision History
- Added command line help for the '-i' option.
- Fixed cDvbPlayer::NextFile() to handle files larger than 2GB (thanks to Jose
Alberto Reguero).
+- Improved replay at the begin and end of a recording. The very first and very last
+ frame is now sent to the output device repeatedly until GetSTC() reports that it
+ has been played. cDvbPlayer::Action() no longer calls DeviceFlush() (thanks to
+ Reinhard Nissl for making sure vdr-xine no longer needs this).
diff --git a/dvbplayer.c b/dvbplayer.c
index 63c18d45..de7cd2e1 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 2.6 2009/03/28 21:56:56 kls Exp $
+ * $Id: dvbplayer.c 2.7 2009/04/05 09:05:54 kls Exp $
*/
#include "dvbplayer.h"
@@ -18,7 +18,7 @@
// --- cPtsIndex -------------------------------------------------------------
-#define PTSINDEX_ENTRIES 100
+#define PTSINDEX_ENTRIES 500
class cPtsIndex {
private:
@@ -194,7 +194,7 @@ bool cNonBlockingFileReader::WaitForDataMs(int msToWait)
#define PLAYERBUFSIZE MEGABYTE(1)
#define RESUMEBACKUP 10 // number of seconds to back up when resuming an interrupted replay session
-#define MAXSTUCKATEND 3 // max. number of seconds to wait in case the device doesn't play the last frame
+#define MAXSTUCKATEOF 3 // max. number of seconds to wait in case the device doesn't play the last frame
class cDvbPlayer : public cPlayer, cThread {
private:
@@ -393,9 +393,11 @@ void cDvbPlayer::Action(void)
int Length = 0;
bool Sleep = false;
bool WaitingForData = false;
- time_t StuckAtEnd = 0;
+ time_t StuckAtEof = 0;
+ uint32_t LastStc = 0;
+ int LastReadIFrame = -1;
- while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
+ while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available())) {
if (Sleep) {
if (WaitingForData)
nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
@@ -407,8 +409,6 @@ void cDvbPlayer::Action(void)
if (DevicePoll(Poller, 100)) {
LOCK_THREAD;
- bool HitBegin = false;
- bool HitEnd = false;
// Read the next frame from the file:
@@ -429,7 +429,10 @@ void cDvbPlayer::Action(void)
int d = int(round(0.4 * framesPerSecond));
if (playDir != pdForward)
d = -d;
- Index = index->GetNextIFrame(readIndex + d, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
+ int NewIndex = readIndex + d;
+ if (NewIndex <= 0 && readIndex > 0)
+ NewIndex = 1; // make sure the very first frame is delivered
+ Index = index->GetNextIFrame(NewIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
readIndependent = true;
}
if (Index >= 0) {
@@ -437,27 +440,16 @@ void cDvbPlayer::Action(void)
if (!NextFile(FileNumber, FileOffset))
continue;
}
- else {
- if (playDir == pdForward) {
- if (!TimeShiftMode) {
- // hit end of recording: signal end of file but don't change playMode
- eof = true;
- HitEnd = true;
- }
- }
- else
- HitBegin = true; // hit begin of recording - trigger wait until device has replayed the very first frame:
- }
+ else if (playDir != pdForward || !TimeShiftMode)
+ eof = true;
}
else if (index) {
uint16_t FileNumber;
off_t FileOffset;
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset))
readIndex++;
- else {
+ else
eof = true;
- HitEnd = true;
- }
}
else // allows replay even if the index file is missing
Length = MAXFRAMESIZE;
@@ -476,7 +468,9 @@ void cDvbPlayer::Action(void)
uint32_t Pts = 0;
if (readIndependent)
Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
- readFrame = new cFrame(b, -r, ftUnknown, readIndependent ? readIndex : -1, Pts); // hands over b to the ringBuffer
+ readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts); // hands over b to the ringBuffer
+ if (readIndependent)
+ LastReadIFrame = readIndex;
b = NULL;
}
else if (r == 0)
@@ -529,22 +523,28 @@ void cDvbPlayer::Action(void)
}
}
if (p) {
- int w;
- if (isPesRecording)
- w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo());
- else
- w = PlayTs(p, TS_SIZE, playMode != pmPlay && DeviceIsPlayingVideo());
- if (w > 0) {
- p += w;
- pc -= w;
- }
- else if (w < 0 && FATALERRNO) {
- LOG_ERROR;
- break;
- }
+ //XXX maybe make PlayTs() play as much as possible, until w == 0? would save this extra code here (and the goto)...
+ while (pc > 0) {
+ int w;
+ if (isPesRecording)
+ w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo());
+ else
+ w = PlayTs(p, TS_SIZE, playMode != pmPlay && DeviceIsPlayingVideo());
+ if (w > 0) {
+ p += w;
+ pc -= w;
+ }
+ else if (w == 0)
+ break;
+ else if (w < 0 && FATALERRNO) {
+ LOG_ERROR;
+ goto End;
+ }
+ }
}
if (pc <= 0) {
- ringBuffer->Drop(playFrame);
+ if (!eof || (playDir != pdForward && playFrame->Index() > 0) || (playDir == pdForward && playFrame->Index() < readIndex))
+ ringBuffer->Drop(playFrame); // the very first and last frame are continously repeated to flush data through the device
playFrame = NULL;
p = NULL;
}
@@ -554,34 +554,36 @@ void cDvbPlayer::Action(void)
// Handle hitting begin/end of recording:
- if (HitBegin || HitEnd) {
- if (DeviceFlush(10)) { // give device a chance to display the last frame
- cCondWait::SleepMs(10); // don't get into a tight loop
+ if (eof) {
+ bool SwitchToPlay = false;
+ uint32_t Stc = DeviceGetSTC();
+ if (Stc != LastStc)
+ StuckAtEof = 0;
+ else if (!StuckAtEof)
+ StuckAtEof = time(NULL);
+ else if (time(NULL) - StuckAtEof > MAXSTUCKATEOF) {
+ if (playDir == pdForward)
+ break; // automatically stop at end of recording
+ SwitchToPlay = true;
}
- else
- HitBegin = HitEnd = false;
- }
- if (HitBegin) {
- if (ptsIndex.FindIndex(DeviceGetSTC()) <= 0) {
+ LastStc = Stc;
+ int Index = ptsIndex.FindIndex(Stc);
+ if (playDir == pdForward) {
+ if (Index >= LastReadIFrame)
+ break; // automatically stop at end of recording
+ }
+ else if (Index <= 0)
+ SwitchToPlay = true;
+ if (SwitchToPlay) {
Empty();
DevicePlay();
playMode = pmPlay;
playDir = pdForward;
}
}
- else if (HitEnd) {
- if (ptsIndex.FindIndex(DeviceGetSTC()) >= readIndex)
- break;
- else if (!StuckAtEnd)
- StuckAtEnd = time(NULL);
- else if (time(NULL) - StuckAtEnd > MAXSTUCKATEND)
- break;
- }
- else
- StuckAtEnd = 0;
}
}
-
+End:
cNonBlockingFileReader *nbfr = nonBlockingFileReader;
nonBlockingFileReader = NULL;
delete nbfr;