Version 1.7.6

- cDevice::PlayTs() now syncs on the TS packet sync bytes.
- Made MAXFRAMESIZE a multiple of TS_SIZE to avoid breaking up TS packets.
- No longer resetting the patPmtParser in cDevice::PlayTs(), because this
  caused the selected audio and subtitle tracks to fall back to the default.
- The SVDRP command PUTE now supports reading the EPG data from a given file
  (thanks to Helmut Auer).
- Added cThread::SetIOPriority() and using it in cRemoveDeletedRecordingsThread
  (thanks to Rolf Ahrenberg).
- Fixed the MEGABYTE() macro to make it correctly handle parameters resulting in
  values larger than 2GB.
- Added cDevice::NumProvidedSystems() to PLUGINS.html (was missing since it had
  been implemented).
- Fixed distortions when switching to the next file during replay.
- Fixed detecting the frame rate for streams with PTS distances of 1800, which
  apparently split one frame over two payload units.
- Added missing 'const' to cRecording::FramesPerSecond() (thanks to Joachim Wilke).
- Any TS packets in the first "frame" after a cut in an edited recording that don't
  belong to a payload unit that started in that frame now get their TEI flag set,
  so that a decoder will ignore them together with any PES data collected for that
  PID so far (thanks to Oliver Endriss for reporting chirping sound disturbences at
  editing points in TS recordings).
- cDvbPlayer::Empty() subtracts 1 from readIndex, because Action() will first
  increment it.
- Only storing non-zero Pts values in ptsIndex.
- Added a note to the INSTALL file about using subdirectories to split a large
  disk into separate areas for VDR's video data and other stuff (suggested by
  Udo Richter).
This commit is contained in:
Klaus Schmidinger
2009-04-26 12:19:00 +02:00
parent 1aadb31fb3
commit 733a2becc4
17 changed files with 325 additions and 205 deletions

View File

@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbplayer.c 2.11 2009/04/05 13:04:33 kls Exp $
* $Id: dvbplayer.c 2.15 2009/04/19 15:19:10 kls Exp $
*/
#include "dvbplayer.h"
@@ -318,7 +318,7 @@ void cDvbPlayer::Empty(void)
if (nonBlockingFileReader)
nonBlockingFileReader->Clear();
if (!firstPacket) // don't set the readIndex twice if Empty() is called more than once
readIndex = ptsIndex.FindIndex(DeviceGetSTC());
readIndex = ptsIndex.FindIndex(DeviceGetSTC()) - 1; // Action() will first increment it!
delete readFrame; // might not have been stored in the buffer in Action()
readFrame = NULL;
playFrame = NULL;
@@ -398,189 +398,191 @@ void cDvbPlayer::Action(void)
int LastReadIFrame = -1;
int SwitchToPlayFrame = 0;
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
else
cCondWait::SleepMs(3); // this keeps the CPU load low
while (Running()) {
if (WaitingForData)
nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
else if (Sleep) {
cPoller Poller;
DevicePoll(Poller, 10);
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) {
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 / TS_SIZE * TS_SIZE;// FIXME: use a linear ringbuffer in this case, and fix cDevice::PlayPes()
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:
// Store the frame in the buffer:
if (readFrame) {
if (ringBuffer->Put(readFrame))
readFrame = NULL;
else
Sleep = true;
}
}
else
Sleep = true;
if (readFrame) {
if (ringBuffer->Put(readFrame))
readFrame = NULL;
}
}
else
Sleep = true;
// Get the next frame from the buffer:
// Get the next frame from the buffer:
if (!playFrame) {
playFrame = ringBuffer->Get();
p = NULL;
pc = 0;
}
if (!playFrame) {
playFrame = ringBuffer->Get();
p = NULL;
pc = 0;
}
// Play the frame:
// Play the frame:
if (playFrame) {
if (!p) {
p = playFrame->Data();
pc = playFrame->Count();
if (p) {
if (playFrame->Index() >= 0 && playFrame->Pts() != 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) {
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:
// Handle hitting begin/end of recording:
if (eof || SwitchToPlayFrame) {
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;
}
LastStc = Stc;
int Index = ptsIndex.FindIndex(Stc);
if (playDir == pdForward && !SwitchToPlayFrame) {
if (Index >= LastReadIFrame)
break; // automatically stop at end of recording
}
else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame)
SwitchToPlay = true;
if (SwitchToPlay) {
if (!SwitchToPlayFrame)
Empty();
DevicePlay();
playMode = pmPlay;
playDir = pdForward;
SwitchToPlayFrame = 0;
}
}
}
if (eof || SwitchToPlayFrame) {
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;
}
LastStc = Stc;
int Index = ptsIndex.FindIndex(Stc);
if (playDir == pdForward && !SwitchToPlayFrame) {
if (Index >= LastReadIFrame)
break; // automatically stop at end of recording
}
else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame)
SwitchToPlay = true;
if (SwitchToPlay) {
if (!SwitchToPlayFrame)
Empty();
DevicePlay();
playMode = pmPlay;
playDir = pdForward;
SwitchToPlayFrame = 0;
}
}
}
}
cNonBlockingFileReader *nbfr = nonBlockingFileReader;