mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Fixed distortions that happened when splitting recording into several files
This commit is contained in:
		
							
								
								
									
										9
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								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. | ||||
|   | ||||
							
								
								
									
										56
									
								
								recorder.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								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); | ||||
|      } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user