1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Modified cDolbyRepacker to make sure PES packets don't exceed the requested length

This commit is contained in:
Klaus Schmidinger 2005-02-05 11:59:19 +01:00
parent d067302bb6
commit ef4ef632d5
3 changed files with 162 additions and 101 deletions

View File

@ -920,6 +920,7 @@ Reinhard Nissl <rnissl@gmx.de>
for implementing cDolbyRepacker for better handling of Dolby Digital PES packets for implementing cDolbyRepacker for better handling of Dolby Digital PES packets
for extending some buffer sizes to allow handling HDTV streams for extending some buffer sizes to allow handling HDTV streams
for adding substream handling to cDolbyRepacker for adding substream handling to cDolbyRepacker
for modifying cDolbyRepacker to make sure PES packets don't exceed the requested length
Richard Robson <richard_robson@beeb.net> Richard Robson <richard_robson@beeb.net>
for reporting freezing replay if a timer starts while in Transfer Mode from the for reporting freezing replay if a timer starts while in Transfer Mode from the

View File

@ -3362,3 +3362,5 @@ Video Disk Recorder Revision History
- The new setup option "OSD/Channel info time" can be used to define the time after - The new setup option "OSD/Channel info time" can be used to define the time after
which the channel display is removed if no key has been pressed (thanks to which the channel display is removed if no key has been pressed (thanks to
Olivier Jacques). Olivier Jacques).
- Modified cDolbyRepacker to make sure PES packets don't exceed the requested length
(thanks to Reinhard Nissl).

258
remux.c
View File

@ -11,7 +11,7 @@
* The cDolbyRepacker code was originally written by Reinhard Nissl <rnissl@gmx.de>, * The cDolbyRepacker code was originally written by Reinhard Nissl <rnissl@gmx.de>,
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de. * and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
* *
* $Id: remux.c 1.27 2005/01/23 12:56:39 kls Exp $ * $Id: remux.c 1.28 2005/02/05 11:56:42 kls Exp $
*/ */
#include "remux.h" #include "remux.h"
@ -24,12 +24,14 @@
class cRepacker { class cRepacker {
protected: protected:
int maxPacketSize;
uint8_t subStreamId; uint8_t subStreamId;
public: public:
cRepacker(void) { subStreamId = 0; } cRepacker(void) { maxPacketSize = 6 + 65535; subStreamId = 0; }
virtual ~cRepacker() {} virtual ~cRepacker() {}
virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) = 0; virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) = 0;
virtual int BreakAt(const uchar *Data, int Count) = 0; virtual int BreakAt(const uchar *Data, int Count) = 0;
void SetMaxPacketSize(int MaxPacketSize) { maxPacketSize = MaxPacketSize; }
void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; } void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; }
}; };
@ -40,6 +42,7 @@ private:
static int frameSizes[]; static int frameSizes[];
uchar fragmentData[6 + 65535]; uchar fragmentData[6 + 65535];
int fragmentLen; int fragmentLen;
int fragmentTodo;
uchar pesHeader[6 + 3 + 255 + 4 + 4]; uchar pesHeader[6 + 3 + 255 + 4 + 4];
int pesHeaderLen; int pesHeaderLen;
uchar chk1; uchar chk1;
@ -50,15 +53,21 @@ private:
find_77, find_77,
store_chk1, store_chk1,
store_chk2, store_chk2,
get_length get_length,
output_packet
} state; } state;
void Reset(void); void Reset(void);
void ResetPesHeader(void);
void AppendSubStreamID(void);
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: public:
cDolbyRepacker(void); cDolbyRepacker(void);
virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count); virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
virtual int BreakAt(const uchar *Data, int Count); virtual int BreakAt(const uchar *Data, int Count);
}; };
// frameSizes are in words, i. e. multiply them by 2 to get bytes
int cDolbyRepacker::frameSizes[] = { int cDolbyRepacker::frameSizes[] = {
// fs = 48 kHz // fs = 48 kHz
64, 64, 80, 80, 96, 96, 112, 112, 128, 128, 160, 160, 192, 192, 224, 224, 64, 64, 80, 80, 96, 96, 112, 112, 128, 128, 160, 160, 192, 192, 224, 224,
@ -93,17 +102,124 @@ cDolbyRepacker::cDolbyRepacker(void)
Reset(); Reset();
} }
void cDolbyRepacker::Reset() void cDolbyRepacker::AppendSubStreamID(void)
{
if (subStreamId) {
pesHeader[pesHeaderLen++] = subStreamId;
pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00;
}
}
void cDolbyRepacker::ResetPesHeader(void)
{ {
state = find_0b;
pesHeader[6] = 0x80; pesHeader[6] = 0x80;
pesHeader[7] = 0x00; pesHeader[7] = 0x00;
pesHeader[8] = 0x00; pesHeader[8] = 0x00;
pesHeaderLen = 9; pesHeaderLen = 9;
AppendSubStreamID();
}
void cDolbyRepacker::Reset(void)
{
ResetPesHeader();
state = find_0b;
ac3todo = 0; ac3todo = 0;
chk1 = 0; chk1 = 0;
chk2 = 0; chk2 = 0;
fragmentLen = 0; fragmentLen = 0;
fragmentTodo = 0;
}
bool cDolbyRepacker::FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite)
{
// enough data available to put PES packet into buffer?
if (fragmentTodo <= Todo) {
// output a previous fragment first
if (fragmentLen > 0) {
Bite = fragmentLen;
int n = ResultBuffer->Put(fragmentData, Bite);
if (Bite != n) {
Reset();
return false;
}
fragmentLen = 0;
}
Bite = fragmentTodo;
int n = ResultBuffer->Put(Data, Bite);
if (Bite != n) {
Reset();
Done += n;
return false;
}
fragmentTodo = 0;
// ac3 frame completely processed?
if (Bite >= ac3todo)
state = find_0b; // go on with finding start of next packet
}
else {
// copy the fragment into separate buffer for later processing
Bite = Todo;
if (fragmentLen + Bite > (int)sizeof(fragmentData)) {
Reset();
return false;
}
memcpy(fragmentData + fragmentLen, Data, Bite);
fragmentLen += Bite;
fragmentTodo -= Bite;
}
return true;
}
bool cDolbyRepacker::StartNewPacket(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite)
{
int packetLen = pesHeaderLen + ac3todo;
// limit packet to maximum size
if (packetLen > maxPacketSize)
packetLen = maxPacketSize;
pesHeader[4] = (packetLen - 6) >> 8;
pesHeader[5] = (packetLen - 6) & 0xFF;
Bite = pesHeaderLen;
// enough data available to put PES packet into buffer?
if (packetLen - pesHeaderLen <= Todo) {
int n = ResultBuffer->Put(pesHeader, Bite);
if (Bite != n) {
Reset();
return false;
}
Bite = packetLen - pesHeaderLen;
n = ResultBuffer->Put(Data, Bite);
if (Bite != n) {
Reset();
Done += n;
return false;
}
// ac3 frame completely processed?
if (Bite >= ac3todo)
state = find_0b; // go on with finding start of next packet
}
else {
fragmentTodo = packetLen;
// copy the pesheader into separate buffer for later processing
if (fragmentLen + Bite > (int)sizeof(fragmentData)) {
Reset();
return false;
}
memcpy(fragmentData + fragmentLen, pesHeader, Bite);
fragmentLen += Bite;
fragmentTodo -= Bite;
// copy the fragment into separate buffer for later processing
Bite = Todo;
if (fragmentLen + Bite > (int)sizeof(fragmentData)) {
Reset();
return false;
}
memcpy(fragmentData + fragmentLen, Data, Bite);
fragmentLen += Bite;
fragmentTodo -= Bite;
}
return true;
} }
int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
@ -111,60 +227,27 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
// check for MPEG 2 // check for MPEG 2
if ((Data[6] & 0xC0) != 0x80) if ((Data[6] & 0xC0) != 0x80)
return 0; return 0;
// copy header information for later use
if (Data[6] != 0x80 || Data[7] != 0x00 || Data[8] != 0x00) {
pesHeaderLen = Data[8] + 6 + 3;
memcpy(pesHeader, Data, pesHeaderLen);
}
const uchar *data = Data + pesHeaderLen; // skip PES header
int done = pesHeaderLen; int done = 6 + 3 + Data[8];
int todo = Count - done; int todo = Count - done;
const uchar *data = Data + done;
// finish remainder of ac3 frame bool headerCopied = false;
if (ac3todo > 0) {
int bite;
// enough data available to put PES packet into buffer?
if (ac3todo <= todo) {
// output a previous fragment first
if (fragmentLen > 0) {
bite = fragmentLen;
int n = ResultBuffer->Put(fragmentData, bite);
if (bite != n) {
Reset();
return done;
}
fragmentLen = 0;
}
bite = ac3todo;
int n = ResultBuffer->Put(data, bite);
if (bite != n) {
Reset();
return done + n;
}
}
else {
// copy the fragment into separate buffer for later processing
bite = todo;
if (fragmentLen + bite > (int)sizeof(fragmentData)) {
Reset();
return done;
}
memcpy(fragmentData + fragmentLen, data, bite);
fragmentLen += bite;
}
data += bite;
done += bite;
todo -= bite;
ac3todo -= bite;
}
// look for 0x0B 0x77 <chk1> <chk2> <frameSize> // look for 0x0B 0x77 <chk1> <chk2> <frameSize>
while (todo > 0) { while (todo > 0) {
switch (state) { switch (state) {
case find_0b: case find_0b:
if (*data == 0x0B) if (*data == 0x0B) {
++(int &)state; ++(int &)state;
// copy header information once for later use
if (!headerCopied) {
headerCopied = true;
pesHeaderLen = 6 + 3 + Data[8];
memcpy(pesHeader, Data, pesHeaderLen);
AppendSubStreamID();
}
}
data++; data++;
done++; done++;
todo--; todo--;
@ -191,10 +274,13 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
todo--; todo--;
++(int &)state; ++(int &)state;
continue; continue;
case get_length: { case get_length:
ac3todo = 2 * frameSizes[*data]; ac3todo = 2 * frameSizes[*data];
// frameSizeCode was invalid => restart searching // frameSizeCode was invalid => restart searching
if (ac3todo <= 0) { if (ac3todo <= 0) {
// reset PES header instead of using/copying a wrong one
ResetPesHeader();
headerCopied = true;
if (chk1 == 0x0B) { if (chk1 == 0x0B) {
if (chk2 == 0x77) { if (chk2 == 0x77) {
state = store_chk1; state = store_chk1;
@ -214,62 +300,32 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
state = find_0b; state = find_0b;
continue; continue;
} }
// adjust PES packet length and output packet // append read data to header for common output processing
if (subStreamId) { pesHeader[pesHeaderLen++] = 0x0B;
pesHeader[pesHeaderLen++] = subStreamId; pesHeader[pesHeaderLen++] = 0x77;
pesHeader[pesHeaderLen++] = 0x00; pesHeader[pesHeaderLen++] = chk1;
pesHeader[pesHeaderLen++] = 0x00; pesHeader[pesHeaderLen++] = chk2;
pesHeader[pesHeaderLen++] = 0x00;
}
int packetLen = pesHeaderLen - 6 + ac3todo;
pesHeader[4] = packetLen >> 8;
pesHeader[5] = packetLen & 0xFF;
pesHeader[pesHeaderLen + 0] = 0x0B;
pesHeader[pesHeaderLen + 1] = 0x77;
pesHeader[pesHeaderLen + 2] = chk1;
pesHeader[pesHeaderLen + 3] = chk2;
ac3todo -= 4; ac3todo -= 4;
int bite = pesHeaderLen + 4; ++(int &)state;
// enough data available to put PES packet into buffer? // fall through to output
if (ac3todo <= todo) { case output_packet: {
int n = ResultBuffer->Put(pesHeader, bite); int bite = 0;
if (bite != n) { // finish remainder of ac3 frame?
Reset(); if (fragmentTodo > 0) {
if (!FinishRemainder(ResultBuffer, data, todo, done, bite))
return done; return done;
} }
bite = ac3todo;
n = ResultBuffer->Put(data, bite);
if (bite != n) {
Reset();
return done + n;
}
}
else { else {
// copy the fragment into separate buffer for later processing // start a new packet
if (fragmentLen + bite > (int)sizeof(fragmentData)) { if (!StartNewPacket(ResultBuffer, data, todo, done, bite))
Reset();
return done; return done;
} // prepare for next packet
memcpy(fragmentData + fragmentLen, pesHeader, bite); ResetPesHeader();
fragmentLen += bite;
bite = todo;
if (fragmentLen + bite > (int)sizeof(fragmentData)) {
Reset();
return done;
}
memcpy(fragmentData + fragmentLen, data, bite);
fragmentLen += bite;
} }
data += bite; data += bite;
done += bite; done += bite;
todo -= bite; todo -= bite;
ac3todo -= bite; ac3todo -= bite;
// prepare for next packet
pesHeader[6] = 0x80;
pesHeader[7] = 0x00;
pesHeader[8] = 0x00;
pesHeaderLen = 9;
state = find_0b;
} }
} }
} }
@ -294,7 +350,7 @@ int cDolbyRepacker::BreakAt(const uchar *Data, int Count)
const uchar *data = Data + headerLen; const uchar *data = Data + headerLen;
// break after ac3 frame? // break after ac3 frame?
if (data[0] == 0x0B && data[1] == 0x77 && frameSizes[data[4]] > 0) if (data[0] == 0x0B && data[1] == 0x77 && frameSizes[data[4]] > 0)
return headerLen + frameSizes[data[4]]; return headerLen + 2 * frameSizes[data[4]];
return -1; return -1;
} }
@ -392,8 +448,10 @@ cTS2PES::cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t Aud
audioCid = AudioCid; audioCid = AudioCid;
subStreamId = SubStreamId; subStreamId = SubStreamId;
repacker = Repacker; repacker = Repacker;
if (repacker) if (repacker) {
repacker->SetMaxPacketSize(size);
repacker->SetSubStreamId(subStreamId); repacker->SetSubStreamId(subStreamId);
}
tsErrors = 0; tsErrors = 0;
ccErrors = 0; ccErrors = 0;