mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Improved replay at the begin and end of a recording; cDvbPlayer::Action() no longer calls DeviceFlush()
This commit is contained in:
parent
1b02cc9c94
commit
c886e69bc6
@ -1200,6 +1200,7 @@ Reinhard Nissl <rnissl@gmx.de>
|
|||||||
to cDevice::PlayTs()
|
to cDevice::PlayTs()
|
||||||
for reporting that the PAT/PMT is processed too often, even if its version
|
for reporting that the PAT/PMT is processed too often, even if its version
|
||||||
hasn't changed
|
hasn't changed
|
||||||
|
for making sure vdr-xine no longer needs cDvbPlayer::Action() to call DeviceFlush()
|
||||||
|
|
||||||
Richard Robson <richard_robson@beeb.net>
|
Richard Robson <richard_robson@beeb.net>
|
||||||
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
||||||
|
6
HISTORY
6
HISTORY
@ -5979,7 +5979,7 @@ Video Disk Recorder Revision History
|
|||||||
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
|
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
|
||||||
new function works as expected.
|
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
|
- Fixed a hangup when replaying a TS recording with subtitles activated (reported
|
||||||
by Timo Helkio).
|
by Timo Helkio).
|
||||||
@ -6009,3 +6009,7 @@ Video Disk Recorder Revision History
|
|||||||
- Added command line help for the '-i' option.
|
- Added command line help for the '-i' option.
|
||||||
- Fixed cDvbPlayer::NextFile() to handle files larger than 2GB (thanks to Jose
|
- Fixed cDvbPlayer::NextFile() to handle files larger than 2GB (thanks to Jose
|
||||||
Alberto Reguero).
|
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).
|
||||||
|
86
dvbplayer.c
86
dvbplayer.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "dvbplayer.h"
|
||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
// --- cPtsIndex -------------------------------------------------------------
|
// --- cPtsIndex -------------------------------------------------------------
|
||||||
|
|
||||||
#define PTSINDEX_ENTRIES 100
|
#define PTSINDEX_ENTRIES 500
|
||||||
|
|
||||||
class cPtsIndex {
|
class cPtsIndex {
|
||||||
private:
|
private:
|
||||||
@ -194,7 +194,7 @@ bool cNonBlockingFileReader::WaitForDataMs(int msToWait)
|
|||||||
#define PLAYERBUFSIZE MEGABYTE(1)
|
#define PLAYERBUFSIZE MEGABYTE(1)
|
||||||
|
|
||||||
#define RESUMEBACKUP 10 // number of seconds to back up when resuming an interrupted replay session
|
#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 {
|
class cDvbPlayer : public cPlayer, cThread {
|
||||||
private:
|
private:
|
||||||
@ -393,9 +393,11 @@ void cDvbPlayer::Action(void)
|
|||||||
int Length = 0;
|
int Length = 0;
|
||||||
bool Sleep = false;
|
bool Sleep = false;
|
||||||
bool WaitingForData = 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 (Sleep) {
|
||||||
if (WaitingForData)
|
if (WaitingForData)
|
||||||
nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
|
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)) {
|
if (DevicePoll(Poller, 100)) {
|
||||||
|
|
||||||
LOCK_THREAD;
|
LOCK_THREAD;
|
||||||
bool HitBegin = false;
|
|
||||||
bool HitEnd = false;
|
|
||||||
|
|
||||||
// Read the next frame from the file:
|
// Read the next frame from the file:
|
||||||
|
|
||||||
@ -429,7 +429,10 @@ void cDvbPlayer::Action(void)
|
|||||||
int d = int(round(0.4 * framesPerSecond));
|
int d = int(round(0.4 * framesPerSecond));
|
||||||
if (playDir != pdForward)
|
if (playDir != pdForward)
|
||||||
d = -d;
|
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;
|
readIndependent = true;
|
||||||
}
|
}
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
@ -437,27 +440,16 @@ void cDvbPlayer::Action(void)
|
|||||||
if (!NextFile(FileNumber, FileOffset))
|
if (!NextFile(FileNumber, FileOffset))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else if (playDir != pdForward || !TimeShiftMode)
|
||||||
if (playDir == pdForward) {
|
|
||||||
if (!TimeShiftMode) {
|
|
||||||
// hit end of recording: signal end of file but don't change playMode
|
|
||||||
eof = true;
|
eof = true;
|
||||||
HitEnd = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
HitBegin = true; // hit begin of recording - trigger wait until device has replayed the very first frame:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (index) {
|
else if (index) {
|
||||||
uint16_t FileNumber;
|
uint16_t FileNumber;
|
||||||
off_t FileOffset;
|
off_t FileOffset;
|
||||||
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset))
|
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset))
|
||||||
readIndex++;
|
readIndex++;
|
||||||
else {
|
else
|
||||||
eof = true;
|
eof = true;
|
||||||
HitEnd = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else // allows replay even if the index file is missing
|
else // allows replay even if the index file is missing
|
||||||
Length = MAXFRAMESIZE;
|
Length = MAXFRAMESIZE;
|
||||||
@ -476,7 +468,9 @@ void cDvbPlayer::Action(void)
|
|||||||
uint32_t Pts = 0;
|
uint32_t Pts = 0;
|
||||||
if (readIndependent)
|
if (readIndependent)
|
||||||
Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
|
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;
|
b = NULL;
|
||||||
}
|
}
|
||||||
else if (r == 0)
|
else if (r == 0)
|
||||||
@ -529,6 +523,8 @@ void cDvbPlayer::Action(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p) {
|
if (p) {
|
||||||
|
//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;
|
int w;
|
||||||
if (isPesRecording)
|
if (isPesRecording)
|
||||||
w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo());
|
w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo());
|
||||||
@ -538,13 +534,17 @@ void cDvbPlayer::Action(void)
|
|||||||
p += w;
|
p += w;
|
||||||
pc -= w;
|
pc -= w;
|
||||||
}
|
}
|
||||||
|
else if (w == 0)
|
||||||
|
break;
|
||||||
else if (w < 0 && FATALERRNO) {
|
else if (w < 0 && FATALERRNO) {
|
||||||
LOG_ERROR;
|
LOG_ERROR;
|
||||||
break;
|
goto End;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pc <= 0) {
|
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;
|
playFrame = NULL;
|
||||||
p = NULL;
|
p = NULL;
|
||||||
}
|
}
|
||||||
@ -554,34 +554,36 @@ void cDvbPlayer::Action(void)
|
|||||||
|
|
||||||
// Handle hitting begin/end of recording:
|
// Handle hitting begin/end of recording:
|
||||||
|
|
||||||
if (HitBegin || HitEnd) {
|
if (eof) {
|
||||||
if (DeviceFlush(10)) { // give device a chance to display the last frame
|
bool SwitchToPlay = false;
|
||||||
cCondWait::SleepMs(10); // don't get into a tight loop
|
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
|
LastStc = Stc;
|
||||||
HitBegin = HitEnd = false;
|
int Index = ptsIndex.FindIndex(Stc);
|
||||||
|
if (playDir == pdForward) {
|
||||||
|
if (Index >= LastReadIFrame)
|
||||||
|
break; // automatically stop at end of recording
|
||||||
}
|
}
|
||||||
if (HitBegin) {
|
else if (Index <= 0)
|
||||||
if (ptsIndex.FindIndex(DeviceGetSTC()) <= 0) {
|
SwitchToPlay = true;
|
||||||
|
if (SwitchToPlay) {
|
||||||
Empty();
|
Empty();
|
||||||
DevicePlay();
|
DevicePlay();
|
||||||
playMode = pmPlay;
|
playMode = pmPlay;
|
||||||
playDir = pdForward;
|
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;
|
cNonBlockingFileReader *nbfr = nonBlockingFileReader;
|
||||||
nonBlockingFileReader = NULL;
|
nonBlockingFileReader = NULL;
|
||||||
delete nbfr;
|
delete nbfr;
|
||||||
|
Loading…
Reference in New Issue
Block a user