1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Fixed distortions when switching to the next file during replay

This commit is contained in:
Klaus Schmidinger 2009-04-18 14:28:15 +02:00
parent fc54164405
commit efd7427bbe
2 changed files with 175 additions and 172 deletions

View File

@ -6045,3 +6045,4 @@ Video Disk Recorder Revision History
values larger than 2GB. values larger than 2GB.
- Added cDevice::NumProvidedSystems() to PLUGINS.html (was missing since it had - Added cDevice::NumProvidedSystems() to PLUGINS.html (was missing since it had
been implemented). been implemented).
- Fixed distortions when switching to the next file during replay.

View File

@ -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.12 2009/04/13 11:10:50 kls Exp $ * $Id: dvbplayer.c 2.13 2009/04/18 14:18:22 kls Exp $
*/ */
#include "dvbplayer.h" #include "dvbplayer.h"
@ -398,189 +398,191 @@ void cDvbPlayer::Action(void)
int LastReadIFrame = -1; int LastReadIFrame = -1;
int SwitchToPlayFrame = 0; int SwitchToPlayFrame = 0;
while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available())) { while (Running()) {
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 else if (Sleep) {
else cPoller Poller;
cCondWait::SleepMs(3); // this keeps the CPU load low DevicePoll(Poller, 10);
Sleep = false; Sleep = false;
} }
cPoller Poller; {
if (DevicePoll(Poller, 100)) { LOCK_THREAD;
LOCK_THREAD; // Read the next frame from the file:
// Read the next frame from the file: if (playMode != pmStill && playMode != pmPause) {
if (!readFrame && (replayFile || readIndex >= 0)) {
if (!nonBlockingFileReader->Reading()) {
if (!SwitchToPlayFrame && (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))) {
uint16_t FileNumber;
off_t FileOffset;
bool TimeShiftMode = index->IsStillRecording();
int Index = -1;
readIndependent = false;
if (DeviceHasIBPTrickSpeed() && playDir == pdForward) {
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length))
Index = readIndex + 1;
}
else {
int d = int(round(0.4 * framesPerSecond));
if (playDir != pdForward)
d = -d;
int NewIndex = readIndex + d;
if (NewIndex <= 0 && readIndex > 0)
NewIndex = 1; // make sure the very first frame is delivered
NewIndex = index->GetNextIFrame(NewIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
if (NewIndex < 0 && TimeShiftMode && playDir == pdForward)
SwitchToPlayFrame = Index;
Index = NewIndex;
readIndependent = true;
}
if (Index >= 0) {
readIndex = Index;
if (!NextFile(FileNumber, FileOffset))
continue;
}
else
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
eof = true;
}
else // allows replay even if the index file is missing
Length = MAXFRAMESIZE;
if (Length == -1)
Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
else if (Length > MAXFRAMESIZE) {
esyslog("ERROR: frame larger than buffer (%d > %d)", Length, MAXFRAMESIZE);
Length = MAXFRAMESIZE;
}
b = MALLOC(uchar, Length);
}
if (!eof) {
int r = nonBlockingFileReader->Read(replayFile, b, Length);
if (r > 0) {
WaitingForData = false;
uint32_t Pts = 0;
if (readIndependent) {
Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
LastReadIFrame = readIndex;
}
readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts); // hands over b to the ringBuffer
b = NULL;
}
else if (r == 0)
eof = true;
else if (r < 0 && errno == EAGAIN)
WaitingForData = true;
else if (r < 0 && FATALERRNO) {
LOG_ERROR;
break;
}
}
}
if (playMode != pmStill && playMode != pmPause) { // Store the frame in the buffer:
if (!readFrame && (replayFile || readIndex >= 0)) {
if (!nonBlockingFileReader->Reading()) {
if (!SwitchToPlayFrame && (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))) {
uint16_t FileNumber;
off_t FileOffset;
bool TimeShiftMode = index->IsStillRecording();
int Index = -1;
readIndependent = false;
if (DeviceHasIBPTrickSpeed() && playDir == pdForward) {
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length))
Index = readIndex + 1;
}
else {
int d = int(round(0.4 * framesPerSecond));
if (playDir != pdForward)
d = -d;
int NewIndex = readIndex + d;
if (NewIndex <= 0 && readIndex > 0)
NewIndex = 1; // make sure the very first frame is delivered
NewIndex = index->GetNextIFrame(NewIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
if (NewIndex < 0 && TimeShiftMode && playDir == pdForward)
SwitchToPlayFrame = Index;
Index = NewIndex;
readIndependent = true;
}
if (Index >= 0) {
readIndex = Index;
if (!NextFile(FileNumber, FileOffset))
continue;
}
else
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
eof = true;
}
else // allows replay even if the index file is missing
Length = MAXFRAMESIZE;
if (Length == -1)
Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
else if (Length > MAXFRAMESIZE) {
esyslog("ERROR: frame larger than buffer (%d > %d)", Length, MAXFRAMESIZE);
Length = MAXFRAMESIZE;
}
b = MALLOC(uchar, Length);
}
if (!eof) {
int r = nonBlockingFileReader->Read(replayFile, b, Length);
if (r > 0) {
WaitingForData = false;
uint32_t Pts = 0;
if (readIndependent) {
Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
LastReadIFrame = readIndex;
}
readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts); // hands over b to the ringBuffer
b = NULL;
}
else if (r == 0)
eof = true;
else if (r < 0 && errno == EAGAIN)
WaitingForData = true;
else if (r < 0 && FATALERRNO) {
LOG_ERROR;
break;
}
}
}
// Store the frame in the buffer: if (readFrame) {
if (ringBuffer->Put(readFrame))
readFrame = NULL;
else
Sleep = true;
}
}
else
Sleep = true;
if (readFrame) { // Get the next frame from the buffer:
if (ringBuffer->Put(readFrame))
readFrame = NULL;
}
}
else
Sleep = true;
// Get the next frame from the buffer: if (!playFrame) {
playFrame = ringBuffer->Get();
p = NULL;
pc = 0;
}
if (!playFrame) { // Play the frame:
playFrame = ringBuffer->Get();
p = NULL;
pc = 0;
}
// Play the frame: if (playFrame) {
if (!p) {
p = playFrame->Data();
pc = playFrame->Count();
if (p) {
if (playFrame->Index() >= 0)
ptsIndex.Put(playFrame->Pts(), playFrame->Index());
if (firstPacket) {
if (isPesRecording) {
PlayPes(NULL, 0);
cRemux::SetBrokenLink(p, pc);
}
else
PlayTs(NULL, 0);
firstPacket = false;
}
}
}
if (p) {
int w;
if (isPesRecording)
w = PlayPes(p, pc, playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward) && DeviceIsPlayingVideo());
else
w = PlayTs(p, pc, playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward) && DeviceIsPlayingVideo());
if (w > 0) {
p += w;
pc -= w;
}
else if (w < 0 && FATALERRNO)
LOG_ERROR;
else
Sleep = true;
}
if (pc <= 0) {
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;
}
}
else
Sleep = true;
if (playFrame) { // Handle hitting begin/end of recording:
if (!p) {
p = playFrame->Data();
pc = playFrame->Count();
if (p) {
if (playFrame->Index() >= 0)
ptsIndex.Put(playFrame->Pts(), playFrame->Index());
if (firstPacket) {
if (isPesRecording) {
PlayPes(NULL, 0);
cRemux::SetBrokenLink(p, pc);
}
else
PlayTs(NULL, 0);
firstPacket = false;
}
}
}
if (p) {
int w;
if (isPesRecording)
w = PlayPes(p, pc, playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward) && DeviceIsPlayingVideo());
else
w = PlayTs(p, pc, playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward) && DeviceIsPlayingVideo());
if (w > 0) {
p += w;
pc -= w;
}
else if (w < 0 && FATALERRNO)
LOG_ERROR;
}
if (pc <= 0) {
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;
}
}
else
Sleep = true;
// Handle hitting begin/end of recording: if (eof || SwitchToPlayFrame) {
bool SwitchToPlay = false;
if (eof || SwitchToPlayFrame) { uint32_t Stc = DeviceGetSTC();
bool SwitchToPlay = false; if (Stc != LastStc)
uint32_t Stc = DeviceGetSTC(); StuckAtEof = 0;
if (Stc != LastStc) else if (!StuckAtEof)
StuckAtEof = 0; StuckAtEof = time(NULL);
else if (!StuckAtEof) else if (time(NULL) - StuckAtEof > MAXSTUCKATEOF) {
StuckAtEof = time(NULL); if (playDir == pdForward)
else if (time(NULL) - StuckAtEof > MAXSTUCKATEOF) { break; // automatically stop at end of recording
if (playDir == pdForward) SwitchToPlay = true;
break; // automatically stop at end of recording }
SwitchToPlay = true; LastStc = Stc;
} int Index = ptsIndex.FindIndex(Stc);
LastStc = Stc; if (playDir == pdForward && !SwitchToPlayFrame) {
int Index = ptsIndex.FindIndex(Stc); if (Index >= LastReadIFrame)
if (playDir == pdForward && !SwitchToPlayFrame) { break; // automatically stop at end of recording
if (Index >= LastReadIFrame) }
break; // automatically stop at end of recording else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame)
} SwitchToPlay = true;
else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame) if (SwitchToPlay) {
SwitchToPlay = true; if (!SwitchToPlayFrame)
if (SwitchToPlay) { Empty();
if (!SwitchToPlayFrame) DevicePlay();
Empty(); playMode = pmPlay;
DevicePlay(); playDir = pdForward;
playMode = pmPlay; SwitchToPlayFrame = 0;
playDir = pdForward; }
SwitchToPlayFrame = 0; }
} }
}
}
} }
cNonBlockingFileReader *nbfr = nonBlockingFileReader; cNonBlockingFileReader *nbfr = nonBlockingFileReader;