From patchwork Tue Mar 15 22:13:52 2005 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reinhard Nissl X-Patchwork-Id: 11807 Received: from mail.gmx.net ([213.165.64.20]) by www.linuxtv.org with smtp (Exim 4.34) id 1DBKIr-0005Ff-JI for vdr@linuxtv.org; Tue, 15 Mar 2005 23:14:17 +0100 Received: (qmail invoked by alias); 15 Mar 2005 22:13:53 -0000 Received: from dialin-145-254-244-185.arcor-ip.net (EHLO [192.168.101.15]) (145.254.244.185) by mail.gmx.net (mp012) with SMTP; 15 Mar 2005 23:13:53 +0100 X-Authenticated: #527675 Message-ID: <42375E20.3000308@gmx.de> Date: Tue, 15 Mar 2005 23:13:52 +0100 From: Reinhard Nissl User-Agent: Mozilla Thunderbird 1.0 (X11/20041206) X-Accept-Language: en-us, en MIME-Version: 1.0 To: "Dr. Werner Fink" Subject: Re: [vdr] bitstreamout 0.70 and vdr 1.3.22 References: <20050314161558.GA18188@boole.suse.de> <20050314175314.GA19599@boole.suse.de> <4235F64A.2090002@gmx.de> <20050315103218.GA1389@wotan.suse.de> In-Reply-To: <20050315103218.GA1389@wotan.suse.de> X-Y-GMX-Trusted: 0 Cc: Klaus Schmidinger's VDR X-BeenThere: vdr@linuxtv.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Klaus Schmidinger's VDR List-Id: Klaus Schmidinger's VDR List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Mar 2005 22:14:17 -0000 Status: O X-Status: X-Keywords: X-UID: 779 Hi, Dr. Werner Fink wrote: >>I've just had a closer look into xine's sources (demux_mpeg_block.c) and >>it seems that my substream header is wrong most of the time. >> >>Byte 0: substream id => correct >>Byte 1: number of AC3 frames starting in this PES packet => wrong >>Byte 2+3: offset to first AC3 frame relative to PES payload => wrong Reading xine's source documenation again, it looks like I've interpreted it wrong. I've no idea why offset should be 5 for the first AC3 frame in a DVD's PES packet!? Anyway, source documentation doesn't match the code and actually they ignore offset completely and rely on "number of AC3 frames" to assign PTS to the correct AC3 frame. > Hmmm ..this is what I've from http://mpucoder.kewlhair.com/DVD/ > > [...] > > Audio Substream Headers > ----------------------- > All substreams in private stream 1 begin with the substream number. > The header described here immediately follows the substream number. > This header is not part of either MPEG or the respective audio > format standard. These are unique to DVD. > > All methods > ----------- > +-------------------+-------------------------------------------+ > |byte 0 | byte 1 byte 2 | > |-------------------+-------------------------------------------+ > |7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | > |-------------------+-------------------------------------------+ > | FrmCnt | FirstAccUnit | > | number of frames | offset to frame which corresponds to PTS | > | which begin in | value offset 0 is the last byte of | > | this packet | FirstAccUnit. The value 0000 indicates | > | | there is no first access unit | > +-------------------+-------------------------------------------+ > > AC3 specific > ------------ > AC3 has no additional information which is DVD specific. > > > example > ------- > > +--------+-------+------------------------------------------------------------+ > | offset | value | meaning | > +--------+-------+------------------------------------------------------------+ > | 01f | 80h | AC3 substream number (audio stream 0) | > | 020 | 02 | this packet contains the beginning of 2 audio frames | > | 021 | 0001 | the frame corresponding to PTS begins at packet offset 023 | > | 023 | 0B77 | AC3 frame begins here (0B77 = AC3 sync word) | > +--------+-------+------------------------------------------------------------+ > > [...] > >>As cDolbyRepacker assures that 1 frame is put into 1 PES packet, byte 1 >>should be 1 and byte 3 should be 4. > > Byte 1 (or in the description above byte 0) should have 1, but the > byte 3 and 4 (or in the description above byte 1 and 2) should have > exactly 1 because the next byte is the first of an AC3 frame. > Don't ask me why the specs writer do begin to count with 0 as normal > programmers do :^) > > I've added a check now for the value 0 (simply adding 1 and checking > for the magic AC3 bytes 0x0b 0x77 at position 1), this because with > a real value 0 there is no beginning AC3 frame after the sub audio > header. > >>But what about extremely large AC3 frames, e. g. 1920 words = 3840 >>bytes. By assuring that PES packets don't get larger than 2048 bytes it >>can happen that such a PES packet contains just the "middle" of an AC3 >>frame. How should bytes 1 to 3 be set in such a case? > > This should also work, because then you have to set 0 for the offset > and it is very unlikly to find a 0x0b 0x77 within the middle of an > AC3 data frame. Thank you very much for this explanation. The attached patch against VDR-1.3.22 fixes all known issues of cDolbyRepacker so far. Bye. --- ../vdr-1.3.22-orig/remux.c 2005-02-13 15:36:23.000000000 +0100 +++ remux.c 2005-03-15 22:04:45.660015460 +0100 @@ -46,6 +46,8 @@ private: int fragmentTodo; uchar pesHeader[6 + 3 + 255 + 4 + 4]; int pesHeaderLen; + uchar pesHeaderBackup[6 + 3 + 255]; + int pesHeaderBackupLen; uchar chk1; uchar chk2; int ac3todo; @@ -57,8 +59,8 @@ private: get_length, output_packet } state; - void ResetPesHeader(void); - void AppendSubStreamID(void); + void ResetPesHeader(bool ContinuationFrame = false); + void AppendSubStreamID(bool ContinuationFrame = false); bool FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite); bool StartNewPacket(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite); public: @@ -103,23 +105,26 @@ cDolbyRepacker::cDolbyRepacker(void) Reset(); } -void cDolbyRepacker::AppendSubStreamID(void) +void cDolbyRepacker::AppendSubStreamID(bool ContinuationFrame) { if (subStreamId) { pesHeader[pesHeaderLen++] = subStreamId; + // number of ac3 frames "starting" in this packet (1 by design). + pesHeader[pesHeaderLen++] = 0x01; + // offset to start of first ac3 frame (0 means "no ac3 frame starting" + // so 1 (by design) addresses the first byte after the next two bytes). pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x00; + pesHeader[pesHeaderLen++] = (ContinuationFrame ? 0x00 : 0x01); } } -void cDolbyRepacker::ResetPesHeader(void) +void cDolbyRepacker::ResetPesHeader(bool ContinuationFrame) { pesHeader[6] = 0x80; pesHeader[7] = 0x00; pesHeader[8] = 0x00; pesHeaderLen = 9; - AppendSubStreamID(); + AppendSubStreamID(ContinuationFrame); } void cDolbyRepacker::Reset(void) @@ -131,6 +136,7 @@ void cDolbyRepacker::Reset(void) chk2 = 0; fragmentLen = 0; fragmentTodo = 0; + pesHeaderBackupLen = 0; } bool cDolbyRepacker::FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite) @@ -229,12 +235,17 @@ int cDolbyRepacker::Put(cRingBufferLinea if ((Data[6] & 0xC0) != 0x80) return 0; + // backup PES header + if (Data[6] != 0x80 || Data[7] != 0x00 || Data[8] != 0x00) { + pesHeaderBackupLen = 6 + 3 + Data[8]; + memcpy(pesHeaderBackup, Data, pesHeaderBackupLen); + } + // skip PES header int done = 6 + 3 + Data[8]; int todo = Count - done; const uchar *data = Data + done; - bool headerCopied = false; - + // look for 0x0B 0x77 while (todo > 0) { switch (state) { @@ -242,10 +253,10 @@ int cDolbyRepacker::Put(cRingBufferLinea if (*data == 0x0B) { ++(int &)state; // copy header information once for later use - if (!headerCopied) { - headerCopied = true; - pesHeaderLen = 6 + 3 + Data[8]; - memcpy(pesHeader, Data, pesHeaderLen); + if (pesHeaderBackupLen > 0) { + pesHeaderLen = pesHeaderBackupLen; + pesHeaderBackupLen = 0; + memcpy(pesHeader, pesHeaderBackup, pesHeaderLen); AppendSubStreamID(); } } @@ -279,9 +290,8 @@ int cDolbyRepacker::Put(cRingBufferLinea ac3todo = 2 * frameSizes[*data]; // frameSizeCode was invalid => restart searching if (ac3todo <= 0) { - // reset PES header instead of using/copying a wrong one + // reset PES header instead of using a wrong one ResetPesHeader(); - headerCopied = true; if (chk1 == 0x0B) { if (chk2 == 0x77) { state = store_chk1; @@ -320,8 +330,8 @@ int cDolbyRepacker::Put(cRingBufferLinea // start a new packet if (!StartNewPacket(ResultBuffer, data, todo, done, bite)) return done; - // prepare for next packet - ResetPesHeader(); + // prepare for next (continuation) packet + ResetPesHeader(state == output_packet); } data += bite; done += bite;