diff --git a/HISTORY b/HISTORY index 1f91ad09..1cf82693 100644 --- a/HISTORY +++ b/HISTORY @@ -6650,7 +6650,7 @@ Video Disk Recorder Revision History - Added support for "content identifier descriptor" and "default authority descriptor" to 'libsi' (thanks to Dave Pickles). -2011-08-06: Version 1.7.20 +2011-08-07: Version 1.7.20 - Added some missing 'const' to tChannelID (reported by Sundararaj Reel). - The isnumber() function now checks the given pointer for NULL (thanks to Holger @@ -6666,3 +6666,10 @@ Video Disk Recorder Revision History Udo Richter for suggesting the fix). - Added a mechanism to defer timer handling in case of problems (reported by Frank Niederwipper). +- Fixed distortions that happened when splitting recording into several files + (was a side effect of "Fixed detecting frames in case the Picture Start Code or + Access Unit Delimiter extends over TS packet boundaries" in version 1.7.19). + cRecorder::Action() now buffers TS packets in case the frame type is + not yet known when a new payload starts. This adds no overhead for channels + that broadcast the frame type within the first TS packet of a payload; it only + kicks in if that information is not in the first TS packet. diff --git a/recorder.c b/recorder.c index 2738c97c..b5c0b60a 100644 --- a/recorder.c +++ b/recorder.c @@ -4,13 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recorder.c 2.11 2011/06/12 14:16:45 kls Exp $ + * $Id: recorder.c 2.12 2011/08/07 13:36:05 kls Exp $ */ #include "recorder.h" #include "shutdown.h" -#define RECORDERBUFSIZE MEGABYTE(5) +#define RECORDERBUFSIZE (MEGABYTE(5) / TS_SIZE * TS_SIZE) // multiple of TS_SIZE // The maximum time we wait before assuming that a recorded video data stream // is broken: @@ -88,7 +88,7 @@ bool cRecorder::RunningLowOnDiskSpace(void) bool cRecorder::NextFile(void) { - if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame + if (recordFile) { if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) { recordFile = fileName->NextFile(); fileSize = 0; @@ -119,8 +119,11 @@ void cRecorder::Action(void) time_t t = time(NULL); bool InfoWritten = false; bool FirstIframeSeen = false; - int FileNumber = 0; - off_t FrameOffset = -1; +#define BUFFERSIZE MEGABYTE(1) + bool Buffering = false; + int BufferIndex = 0; + int MaxBufferIndex = 0; + uchar *Buffer = NULL; while (Running()) { int r; uchar *b = ringBuffer->Get(r); @@ -141,16 +144,37 @@ void cRecorder::Action(void) } InfoWritten = true; } - if (frameDetector->NewPayload()) { - FileNumber = fileName->Number(); - FrameOffset = fileSize; + if (frameDetector->NewPayload()) { // We're at the first TS packet of a new payload... + if (Buffering) + esyslog("ERROR: encountered new payload while buffering - dropping some data!"); + if (!frameDetector->NewFrame()) { // ...but the frame type is yet unknown, so we need to buffer packets until we see the frame type + if (!Buffer) { + dsyslog("frame type not in first packet of payload - buffering"); + if (!(Buffer = MALLOC(uchar, BUFFERSIZE))) { + esyslog("ERROR: can't allocate frame type buffer"); + break; + } + } + BufferIndex = 0; + Buffering = true; + } } - if (FirstIframeSeen || frameDetector->IndependentFrame()) { + else if (frameDetector->NewFrame()) // now we know the frame type, so stop buffering + Buffering = false; + if (Buffering) { + if (BufferIndex + Count <= BUFFERSIZE) { + memcpy(Buffer + BufferIndex, b, Count); + BufferIndex += Count; + } + else + esyslog("ERROR: too many bytes for frame type buffer (%d > %d) - dropped %d bytes", BufferIndex + Count, int(BUFFERSIZE), Count); + } + else if (FirstIframeSeen || frameDetector->IndependentFrame()) { FirstIframeSeen = true; // start recording with the first I-frame - if (!NextFile()) + if (frameDetector->IndependentFrame() && !NextFile()) // every file shall start with an independent frame break; if (index && frameDetector->NewFrame()) - index->Write(frameDetector->IndependentFrame(), FileNumber, FrameOffset); + index->Write(frameDetector->IndependentFrame(), fileName->Number(), fileSize); if (frameDetector->IndependentFrame()) { recordFile->Write(patPmtGenerator.GetPat(), TS_SIZE); fileSize += TS_SIZE; @@ -160,6 +184,12 @@ void cRecorder::Action(void) fileSize += TS_SIZE; } } + if (BufferIndex) { + recordFile->Write(Buffer, BufferIndex); // if an error occurs here, the next write below will catch and report it + if (BufferIndex > MaxBufferIndex) + MaxBufferIndex = BufferIndex; + BufferIndex = 0; + } if (recordFile->Write(b, Count) < 0) { LOG_ERROR_STR(fileName->Name()); break; @@ -177,4 +207,8 @@ void cRecorder::Action(void) t = time(NULL); } } + if (Buffer) { + free(Buffer); + dsyslog("frame type buffer used %d bytes", MaxBufferIndex); + } }