The attached patch reactivates some of the frame detecting code that was already in VDR 1.7.16, and adds a method of determining whether the current video stream consists of separate "fields" instead of complete frames. If this is the case, it puts two subsequent fields together to one frame in the index file. I know that the way this is detected (by counting the number of "frames" between two I-frames) is "guesswork", but until I see a case where this fails I'd say it still beats having a complete H.264 parser in there ;-) Please test the patch (which is against VDR 1.7.17) by recording all kinds of streams (SD and HD) available to you and verify that, when replaying such a recording - the current and total time in the replay progress display is correct. - fast forward/rewind works properly - setting an editing mark, jumping to it and moving it around updates the picture accordingly The patch activates 'DebugFrames', so whenever a recording starts VDR prints something like this to stderr: /50 /50 /50 /50 /30 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /10 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /30 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /10 Delta = 1800 FPS = 50.00 FPPU = 1 NF = 32 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /30 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /50 /10 * If you encounter a channel where one of the above tests fails, please send me the data VDR has printed to stderr when the recording started. Maybe it can help to further fine tune this. Please do all testing with newly created recordings that have been done with a VDR that has this patch applied. Klaus
=================================================================== RCS file: ./RCS/remux.c retrieving revision 2.52 diff -u -b -r2.52 ./remux.c --- ./remux.c 2011/03/13 13:57:09 2.52 +++ ./remux.c 2011/03/20 10:05:34 @@ -17,7 +17,7 @@ // Set these to 'true' for debug output: static bool DebugPatPmt = false; -static bool DebugFrames = false; +static bool DebugFrames = true;//XXX false; #define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a) #define dbgframes(a...) if (DebugFrames) fprintf(stderr, a) @@ -783,9 +783,11 @@ synced = false; newFrame = independentFrame = false; numPtsValues = 0; + numFrames = 0; numIFrames = 0; framesPerSecond = 0; framesInPayloadUnit = framesPerPayloadUnit = 0; + payloadUnitOfFrame = 0; scanning = false; scanner = EMPTY_SCANNER; } @@ -807,6 +809,7 @@ void cFrameDetector::Reset(void) { newFrame = independentFrame = false; + payloadUnitOfFrame = 0; scanning = false; scanner = EMPTY_SCANNER; } @@ -844,6 +847,7 @@ dbgframes("#"); numPtsValues = 0; numIFrames = 0; + numFrames = 0; } else numPtsValues++; @@ -863,9 +867,22 @@ framesPerSecond = 25.0; else if (Delta % 3003 == 0) framesPerSecond = 30.0 / 1.001; - else if (abs(Delta - 1800) <= 1) + else if (abs(Delta - 1800) <= 1) { + if (numFrames > 50) { + // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame" + framesPerSecond = 25.0; + framesPerPayloadUnit = -2; + } + else framesPerSecond = 50.0; + } else if (Delta == 1501) + if (numFrames > 50) { + // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame" + framesPerSecond = 30.0 / 1.001; + framesPerPayloadUnit = -2; + } + else framesPerSecond = 60.0 / 1.001; else { framesPerSecond = 25.0; @@ -874,7 +891,7 @@ } else // audio framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing - dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d\n", Delta, framesPerSecond, framesPerPayloadUnit); + dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames); } } scanner = EMPTY_SCANNER; @@ -909,6 +926,8 @@ framesInPayloadUnit++; if (independentFrame) numIFrames++; + if (numIFrames == 1) + numFrames++; dbgframes("%d ", (Data[i + 2] >> 3) & 0x07); } if (synced) @@ -923,6 +942,13 @@ 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; } @@ -930,6 +956,8 @@ framesInPayloadUnit++; if (independentFrame) numIFrames++; + if (numIFrames == 1) + numFrames++; dbgframes("%02X ", Data[i + 1]); } if (synced) @@ -955,7 +983,7 @@ } if (!synced && framesPerSecond > 0.0 && independentFrame) { synced = true; - dbgframes("*"); + dbgframes("*\n"); Reset(); return Processed + TS_SIZE; } =================================================================== RCS file: ./RCS/remux.h retrieving revision 2.27 diff -u -b -r2.27 ./remux.h --- ./remux.h 2010/11/01 11:24:20 2.27 +++ ./remux.h 2011/03/19 16:52:46 @@ -345,12 +345,15 @@ bool independentFrame; uint32_t ptsValues[MaxPtsValues]; // 32 bit is enough - we only need the delta int numPtsValues; + int numFrames; int numIFrames; bool isVideo; double framesPerSecond; int framesInPayloadUnit; int framesPerPayloadUnit; // Some broadcasters send one frame per payload unit (== 1), - // while others put an entire GOP into one payload unit (> 1). + // some put an entire GOP into one payload unit (> 1), and + // some spread a single frame over several payload units (< 0). + int payloadUnitOfFrame; bool scanning; uint32_t scanner; public:
_______________________________________________ vdr mailing list vdr@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr