Fixed detecting frame borders in MPEG-2 streams that have "bottom fields" or varying GOP structures

This commit is contained in:
Klaus Schmidinger 2014-01-25 14:37:05 +01:00
parent 6bd94489de
commit dd95f4ed61
3 changed files with 33 additions and 5 deletions

View File

@ -620,6 +620,8 @@ Helmut Auer <vdr@helmutauer.de>
command line option to be left empty to use the default values if only ENC shall be set command line option to be left empty to use the default values if only ENC shall be set
for reporting an inconsistent behavior between opening the Recordings menu manually for reporting an inconsistent behavior between opening the Recordings menu manually
via the main menu and by pressing the Recordings key via the main menu and by pressing the Recordings key
for helping to debug a problem with frame detection in MPEG-2 streams that have "bottom fields"
or varying GOP structures
Jeremy Hall <jhall@UU.NET> Jeremy Hall <jhall@UU.NET>
for fixing an incomplete initialization of the filter parameters in eit.c for fixing an incomplete initialization of the filter parameters in eit.c
@ -3192,3 +3194,7 @@ Eike Edener <eike@edener.de>
Eike Sauer <EikeSauer@t-online.de> Eike Sauer <EikeSauer@t-online.de>
for reporting a problem with channels that need more than 5 TS packets for detecting for reporting a problem with channels that need more than 5 TS packets for detecting
frame borders frame borders
Christian Paulick <cpaulick@xeatre.tv>
for reporting a problem with frame detection in MPEG-2 streams that have "bottom fields"
or varying GOP structures

View File

@ -7878,4 +7878,6 @@ Video Disk Recorder Revision History
- Increased MIN_TS_PACKETS_FOR_FRAME_DETECTOR to 10 in order to be able to record - Increased MIN_TS_PACKETS_FOR_FRAME_DETECTOR to 10 in order to be able to record
channels that need more than 5 TS packets for detecting frame borders (reported by channels that need more than 5 TS packets for detecting frame borders (reported by
Eike Sauer). Eike Sauer).
- Fixed detecting frame borders in MPEG-2 streams that have "bottom fields" or varying
GOP structures (reported by Christian Paulick, with help from Helmut Auer).
- Fixed a wrong alignment in cCiDateTime::SendDateTime(). - Fixed a wrong alignment in cCiDateTime::SendDateTime().

30
remux.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remux.c 2.75 2013/03/03 10:37:58 kls Exp $ * $Id: remux.c 2.75.1.1 2014/01/25 14:37:05 kls Exp $
*/ */
#include "remux.h" #include "remux.h"
@ -1004,6 +1004,7 @@ protected:
bool debug; bool debug;
bool newFrame; bool newFrame;
bool independentFrame; bool independentFrame;
int iFrameTemporalReferenceOffset;
public: public:
cFrameParser(void); cFrameParser(void);
virtual ~cFrameParser() {}; virtual ~cFrameParser() {};
@ -1017,6 +1018,7 @@ public:
void SetDebug(bool Debug) { debug = Debug; } void SetDebug(bool Debug) { debug = Debug; }
bool NewFrame(void) { return newFrame; } bool NewFrame(void) { return newFrame; }
bool IndependentFrame(void) { return independentFrame; } bool IndependentFrame(void) { return independentFrame; }
int IFrameTemporalReferenceOffset(void) { return iFrameTemporalReferenceOffset; }
}; };
cFrameParser::cFrameParser(void) cFrameParser::cFrameParser(void)
@ -1024,6 +1026,7 @@ cFrameParser::cFrameParser(void)
debug = true; debug = true;
newFrame = false; newFrame = false;
independentFrame = false; independentFrame = false;
iFrameTemporalReferenceOffset = 0;
} }
// --- cAudioParser ---------------------------------------------------------- // --- cAudioParser ----------------------------------------------------------
@ -1056,6 +1059,7 @@ class cMpeg2Parser : public cFrameParser {
private: private:
uint32_t scanner; uint32_t scanner;
bool seenIndependentFrame; bool seenIndependentFrame;
int lastIFrameTemporalReference;
public: public:
cMpeg2Parser(void); cMpeg2Parser(void);
virtual int Parse(const uchar *Data, int Length, int Pid); virtual int Parse(const uchar *Data, int Length, int Pid);
@ -1065,6 +1069,7 @@ cMpeg2Parser::cMpeg2Parser(void)
{ {
scanner = EMPTY_SCANNER; scanner = EMPTY_SCANNER;
seenIndependentFrame = false; seenIndependentFrame = false;
lastIFrameTemporalReference = -1; // invalid
} }
int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid) int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
@ -1089,10 +1094,25 @@ int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
scanner = OldScanner; scanner = OldScanner;
return tsPayload.Used() - TS_SIZE; return tsPayload.Used() - TS_SIZE;
} }
uchar b1 = tsPayload.GetByte();
uchar b2 = tsPayload.GetByte();
int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
uchar FrameType = (b2 >> 3) & 0x07;
if (tsPayload.Find(0x000001B5)) { // Extension start code
if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
tsPayload.GetByte();
uchar PictureStructure = tsPayload.GetByte() & 0x03;
if (PictureStructure == 0x02) // bottom field
break;
}
}
newFrame = true; newFrame = true;
tsPayload.GetByte();
uchar FrameType = (tsPayload.GetByte() >> 3) & 0x07;
independentFrame = FrameType == 1; // I-Frame independentFrame = FrameType == 1; // I-Frame
if (independentFrame) {
if (lastIFrameTemporalReference >= 0)
iFrameTemporalReferenceOffset = TemporalReference - lastIFrameTemporalReference;
lastIFrameTemporalReference = TemporalReference;
}
if (debug) { if (debug) {
seenIndependentFrame |= independentFrame; seenIndependentFrame |= independentFrame;
if (seenIndependentFrame) { if (seenIndependentFrame) {
@ -1457,7 +1477,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
for (int i = 0; i < numPtsValues; i++) for (int i = 0; i < numPtsValues; i++)
ptsValues[i] = ptsValues[i + 1] - ptsValues[i]; ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32); qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
uint32_t Delta = ptsValues[0] / framesPerPayloadUnit; uint32_t Delta = ptsValues[0] / (framesPerPayloadUnit + parser->IFrameTemporalReferenceOffset());
// determine frame info: // determine frame info:
if (isVideo) { if (isVideo) {
if (abs(Delta - 3600) <= 1) if (abs(Delta - 3600) <= 1)
@ -1475,7 +1495,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
} }
else // audio else // audio
framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1); dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
synced = true; synced = true;
parser->SetDebug(false); parser->SetDebug(false);
} }