mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Modified cFrameDetector::Analyze() to minimize file I/O overhead during recording
This commit is contained in:
		@@ -2426,3 +2426,6 @@ Derek Kelly (user.vdr@gmail.com)
 | 
			
		||||
 | 
			
		||||
Marcel Unbehaun <frostworks@gmx.de>
 | 
			
		||||
 for adding cRecordingInfo::GetEvent()
 | 
			
		||||
 | 
			
		||||
G<EFBFBD>nter Niedermeier <linuxtv@ncs-online.de>
 | 
			
		||||
 for reporting a problem with file I/O overhead during recording in TS format
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								HISTORY
									
									
									
									
									
								
							@@ -6003,3 +6003,6 @@ Video Disk Recorder Revision History
 | 
			
		||||
- Adapted cFrameDetector::Analyze() to HD NTSC broadcasts that split frames over
 | 
			
		||||
  several payload units (thanks to Derek Kelly for reporting this and helping in
 | 
			
		||||
  testing).
 | 
			
		||||
- Modified cFrameDetector::Analyze() to make it process whole frames at once, so
 | 
			
		||||
  that file I/O overhead is minimized during recording (reported by G<>nter
 | 
			
		||||
  Niedermeier).
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										261
									
								
								remux.c
									
									
									
									
									
								
							
							
						
						
									
										261
									
								
								remux.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: remux.c 2.15 2009/03/27 13:32:11 kls Exp $
 | 
			
		||||
 * $Id: remux.c 2.16 2009/03/27 13:49:58 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "remux.h"
 | 
			
		||||
@@ -697,137 +697,142 @@ static int CmpUint32(const void *p1, const void *p2)
 | 
			
		||||
 | 
			
		||||
int cFrameDetector::Analyze(const uchar *Data, int Length)
 | 
			
		||||
{
 | 
			
		||||
  int Processed = 0;
 | 
			
		||||
  newFrame = independentFrame = false;
 | 
			
		||||
  if (Length >= TS_SIZE) {
 | 
			
		||||
     if (TsHasPayload(Data) && !TsIsScrambled(Data) && TsPid(Data) == pid) {
 | 
			
		||||
        if (TsPayloadStart(Data)) {
 | 
			
		||||
           if (!frameDuration) {
 | 
			
		||||
              // frame duration unknown, so collect a sequenece of PTS values:
 | 
			
		||||
              if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
 | 
			
		||||
                 const uchar *Pes = Data + TsPayloadOffset(Data);
 | 
			
		||||
                 if (PesHasPts(Pes)) {
 | 
			
		||||
                    ptsValues[numPtsValues] = PesGetPts(Pes);
 | 
			
		||||
                    // check for rollover:
 | 
			
		||||
                    if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
 | 
			
		||||
                       dbgframes("#");
 | 
			
		||||
                       numPtsValues = 0;
 | 
			
		||||
                       numIFrames = 0;
 | 
			
		||||
                       }
 | 
			
		||||
                    else
 | 
			
		||||
                       numPtsValues++;
 | 
			
		||||
                    }
 | 
			
		||||
                 }
 | 
			
		||||
              else {
 | 
			
		||||
                 // find the smallest PTS delta:
 | 
			
		||||
                 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
 | 
			
		||||
                 numPtsValues--;
 | 
			
		||||
                 for (int i = 0; i < numPtsValues; i++)
 | 
			
		||||
                     ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
 | 
			
		||||
                 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
 | 
			
		||||
                 uint32_t Delta = ptsValues[0];
 | 
			
		||||
                 // determine frame info:
 | 
			
		||||
                 if (isVideo) {
 | 
			
		||||
                    if (Delta % 3600 == 0)
 | 
			
		||||
                       frameDuration = 3600; // PAL, 25 fps
 | 
			
		||||
                    else if (Delta % 3003 == 0)
 | 
			
		||||
                       frameDuration = 3003; // NTSC, 29.97 fps
 | 
			
		||||
                    else if (Delta == 1501) {
 | 
			
		||||
                       frameDuration = 3003; // NTSC, 29.97 fps
 | 
			
		||||
                       framesPerPayloadUnit = -2;
 | 
			
		||||
                       }
 | 
			
		||||
                    else {
 | 
			
		||||
                       frameDuration = 3600; // unknown, assuming 25 fps
 | 
			
		||||
                       dsyslog("unknown frame duration (%d), assuming 25 fps", Delta);
 | 
			
		||||
                       }
 | 
			
		||||
                    }
 | 
			
		||||
                 else // audio
 | 
			
		||||
                    frameDuration = Delta; // PTS of audio frames is always increasing
 | 
			
		||||
                 dbgframes("\nframe duration = %d  FPS = %5.2f  FPPU = %d\n", frameDuration, 90000.0 / frameDuration, framesPerPayloadUnit);
 | 
			
		||||
                 }
 | 
			
		||||
              }
 | 
			
		||||
           scanner = 0;
 | 
			
		||||
           scanning = true;
 | 
			
		||||
           }
 | 
			
		||||
        if (scanning) {
 | 
			
		||||
           int PayloadOffset = TsPayloadOffset(Data);
 | 
			
		||||
  while (Length >= TS_SIZE) {
 | 
			
		||||
        if (TsHasPayload(Data) && !TsIsScrambled(Data) && TsPid(Data) == pid) {
 | 
			
		||||
           if (TsPayloadStart(Data)) {
 | 
			
		||||
              PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
 | 
			
		||||
              if (!framesPerPayloadUnit)
 | 
			
		||||
                 framesPerPayloadUnit = framesInPayloadUnit;
 | 
			
		||||
              if (DebugFrames && !synced)
 | 
			
		||||
                 dbgframes("/");
 | 
			
		||||
              }
 | 
			
		||||
           for (int i = PayloadOffset; i < TS_SIZE; i++) {
 | 
			
		||||
               scanner <<= 8;
 | 
			
		||||
               scanner |= Data[i];
 | 
			
		||||
               switch (type) {
 | 
			
		||||
                 case 0x02: // MPEG 2 video
 | 
			
		||||
                      if (scanner == 0x00000100) { // Picture Start Code
 | 
			
		||||
                         newFrame = true;
 | 
			
		||||
                         independentFrame = ((Data[i + 2] >> 3) & 0x07) == 1; // I-Frame
 | 
			
		||||
                         if (synced) {
 | 
			
		||||
                            if (framesPerPayloadUnit <= 1) {
 | 
			
		||||
                               scanning = false;
 | 
			
		||||
                               return TS_SIZE;
 | 
			
		||||
                               }
 | 
			
		||||
                            }
 | 
			
		||||
                         else {
 | 
			
		||||
                            framesInPayloadUnit++;
 | 
			
		||||
                            if (independentFrame)
 | 
			
		||||
                               numIFrames++;
 | 
			
		||||
                            dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
 | 
			
		||||
                            }
 | 
			
		||||
                         scanner = 0;
 | 
			
		||||
                         }
 | 
			
		||||
                      break;
 | 
			
		||||
                 case 0x1B: // MPEG 4 video
 | 
			
		||||
                      if (scanner == 0x00000109) { // Access Unit Delimiter
 | 
			
		||||
                         newFrame = true;
 | 
			
		||||
                         independentFrame = Data[i + 1] == 0x10;
 | 
			
		||||
                         if (synced) {
 | 
			
		||||
                            if (framesPerPayloadUnit < 0) {
 | 
			
		||||
                               payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
 | 
			
		||||
                               if (payloadUnitOfFrame != 0 && independentFrame)
 | 
			
		||||
                                  payloadUnitOfFrame = 0;
 | 
			
		||||
                               if (payloadUnitOfFrame)
 | 
			
		||||
                                  newFrame = false;
 | 
			
		||||
                               }
 | 
			
		||||
                            if (framesPerPayloadUnit <= 1) {
 | 
			
		||||
                               scanning = false;
 | 
			
		||||
                               return TS_SIZE;
 | 
			
		||||
                               }
 | 
			
		||||
                            }
 | 
			
		||||
                         else {
 | 
			
		||||
                            framesInPayloadUnit++;
 | 
			
		||||
                            if (independentFrame)
 | 
			
		||||
                               numIFrames++;
 | 
			
		||||
                            dbgframes("%02X ", Data[i + 1]);
 | 
			
		||||
                            }
 | 
			
		||||
                         scanner = 0;
 | 
			
		||||
                         }
 | 
			
		||||
                      break;
 | 
			
		||||
                 case 0x04: // MPEG audio
 | 
			
		||||
                 case 0x06: // AC3 audio
 | 
			
		||||
                      newFrame = true;
 | 
			
		||||
                      independentFrame = true;
 | 
			
		||||
                      if (synced)
 | 
			
		||||
                         scanning = false;
 | 
			
		||||
                      else {
 | 
			
		||||
                         framesInPayloadUnit = 1;
 | 
			
		||||
                         numIFrames++;
 | 
			
		||||
                         }
 | 
			
		||||
                      break;
 | 
			
		||||
                 default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
 | 
			
		||||
                          pid = 0; // let's just ignore any further data
 | 
			
		||||
              if (!frameDuration) {
 | 
			
		||||
                 // frame duration unknown, so collect a sequenece of PTS values:
 | 
			
		||||
                 if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
 | 
			
		||||
                    const uchar *Pes = Data + TsPayloadOffset(Data);
 | 
			
		||||
                    if (PesHasPts(Pes)) {
 | 
			
		||||
                       ptsValues[numPtsValues] = PesGetPts(Pes);
 | 
			
		||||
                       // check for rollover:
 | 
			
		||||
                       if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
 | 
			
		||||
                          dbgframes("#");
 | 
			
		||||
                          numPtsValues = 0;
 | 
			
		||||
                          numIFrames = 0;
 | 
			
		||||
                          }
 | 
			
		||||
                       else
 | 
			
		||||
                          numPtsValues++;
 | 
			
		||||
                       }
 | 
			
		||||
                    }
 | 
			
		||||
                 else {
 | 
			
		||||
                    // find the smallest PTS delta:
 | 
			
		||||
                    qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
 | 
			
		||||
                    numPtsValues--;
 | 
			
		||||
                    for (int i = 0; i < numPtsValues; i++)
 | 
			
		||||
                        ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
 | 
			
		||||
                    qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
 | 
			
		||||
                    uint32_t Delta = ptsValues[0];
 | 
			
		||||
                    // determine frame info:
 | 
			
		||||
                    if (isVideo) {
 | 
			
		||||
                       if (Delta % 3600 == 0)
 | 
			
		||||
                          frameDuration = 3600; // PAL, 25 fps
 | 
			
		||||
                       else if (Delta % 3003 == 0)
 | 
			
		||||
                          frameDuration = 3003; // NTSC, 29.97 fps
 | 
			
		||||
                       else if (Delta == 1501) {
 | 
			
		||||
                          frameDuration = 3003; // NTSC, 29.97 fps
 | 
			
		||||
                          framesPerPayloadUnit = -2;
 | 
			
		||||
                          }
 | 
			
		||||
                       else {
 | 
			
		||||
                          frameDuration = 3600; // unknown, assuming 25 fps
 | 
			
		||||
                          dsyslog("unknown frame duration (%d), assuming 25 fps", Delta);
 | 
			
		||||
                          }
 | 
			
		||||
                       }
 | 
			
		||||
                    else // audio
 | 
			
		||||
                       frameDuration = Delta; // PTS of audio frames is always increasing
 | 
			
		||||
                    dbgframes("\nframe duration = %d  FPS = %5.2f  FPPU = %d\n", frameDuration, 90000.0 / frameDuration, framesPerPayloadUnit);
 | 
			
		||||
                    }
 | 
			
		||||
                 }
 | 
			
		||||
              scanner = 0;
 | 
			
		||||
              scanning = true;
 | 
			
		||||
              }
 | 
			
		||||
           if (scanning) {
 | 
			
		||||
              int PayloadOffset = TsPayloadOffset(Data);
 | 
			
		||||
              if (TsPayloadStart(Data)) {
 | 
			
		||||
                 PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
 | 
			
		||||
                 if (!framesPerPayloadUnit)
 | 
			
		||||
                    framesPerPayloadUnit = framesInPayloadUnit;
 | 
			
		||||
                 if (DebugFrames && !synced)
 | 
			
		||||
                    dbgframes("/");
 | 
			
		||||
                 }
 | 
			
		||||
              for (int i = PayloadOffset; i < TS_SIZE; i++) {
 | 
			
		||||
                  scanner <<= 8;
 | 
			
		||||
                  scanner |= Data[i];
 | 
			
		||||
                  switch (type) {
 | 
			
		||||
                    case 0x02: // MPEG 2 video
 | 
			
		||||
                         if (scanner == 0x00000100) { // Picture Start Code
 | 
			
		||||
                            if (synced && Processed)
 | 
			
		||||
                               return Processed;
 | 
			
		||||
                            newFrame = true;
 | 
			
		||||
                            independentFrame = ((Data[i + 2] >> 3) & 0x07) == 1; // I-Frame
 | 
			
		||||
                            if (synced) {
 | 
			
		||||
                               if (framesPerPayloadUnit <= 1)
 | 
			
		||||
                                  scanning = false;
 | 
			
		||||
                               }
 | 
			
		||||
                            else {
 | 
			
		||||
                               framesInPayloadUnit++;
 | 
			
		||||
                               if (independentFrame)
 | 
			
		||||
                                  numIFrames++;
 | 
			
		||||
                               dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
 | 
			
		||||
                               }
 | 
			
		||||
                            scanner = 0;
 | 
			
		||||
                            }
 | 
			
		||||
                         break;
 | 
			
		||||
                    case 0x1B: // MPEG 4 video
 | 
			
		||||
                         if (scanner == 0x00000109) { // Access Unit Delimiter
 | 
			
		||||
                            if (synced && Processed)
 | 
			
		||||
                               return Processed;
 | 
			
		||||
                            newFrame = true;
 | 
			
		||||
                            independentFrame = Data[i + 1] == 0x10;
 | 
			
		||||
                            if (synced) {
 | 
			
		||||
                               if (framesPerPayloadUnit < 0) {
 | 
			
		||||
                                  payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
 | 
			
		||||
                                  if (payloadUnitOfFrame != 0 && independentFrame)
 | 
			
		||||
                                     payloadUnitOfFrame = 0;
 | 
			
		||||
                                  if (payloadUnitOfFrame)
 | 
			
		||||
                                     newFrame = false;
 | 
			
		||||
                                  }
 | 
			
		||||
                               if (framesPerPayloadUnit <= 1)
 | 
			
		||||
                                  scanning = false;
 | 
			
		||||
                               }
 | 
			
		||||
                            else {
 | 
			
		||||
                               framesInPayloadUnit++;
 | 
			
		||||
                               if (independentFrame)
 | 
			
		||||
                                  numIFrames++;
 | 
			
		||||
                               dbgframes("%02X ", Data[i + 1]);
 | 
			
		||||
                               }
 | 
			
		||||
                            scanner = 0;
 | 
			
		||||
                            }
 | 
			
		||||
                         break;
 | 
			
		||||
                    case 0x04: // MPEG audio
 | 
			
		||||
                    case 0x06: // AC3 audio
 | 
			
		||||
                         if (synced && Processed)
 | 
			
		||||
                            return Processed;
 | 
			
		||||
                         newFrame = true;
 | 
			
		||||
                         independentFrame = true;
 | 
			
		||||
                         if (synced)
 | 
			
		||||
                            scanning = false;
 | 
			
		||||
                         else {
 | 
			
		||||
                            framesInPayloadUnit = 1;
 | 
			
		||||
                            numIFrames++;
 | 
			
		||||
                            }
 | 
			
		||||
                         break;
 | 
			
		||||
                    default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
 | 
			
		||||
                             pid = 0; // let's just ignore any further data
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
              if (!synced && frameDuration && independentFrame) {
 | 
			
		||||
                 synced = true;
 | 
			
		||||
                 dbgframes("*");
 | 
			
		||||
                 }
 | 
			
		||||
               }
 | 
			
		||||
           if (!synced && frameDuration && independentFrame) {
 | 
			
		||||
              synced = true;
 | 
			
		||||
              dbgframes("*");
 | 
			
		||||
              }
 | 
			
		||||
           }
 | 
			
		||||
        Data += TS_SIZE;
 | 
			
		||||
        Length -= TS_SIZE;
 | 
			
		||||
        Processed += TS_SIZE;
 | 
			
		||||
        }
 | 
			
		||||
     return TS_SIZE;
 | 
			
		||||
     }
 | 
			
		||||
  return 0;
 | 
			
		||||
  return Processed;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user