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:
parent
d067302bb6
commit
ef4ef632d5
@ -920,6 +920,7 @@ Reinhard Nissl <rnissl@gmx.de>
|
||||
for implementing cDolbyRepacker for better handling of Dolby Digital PES packets
|
||||
for extending some buffer sizes to allow handling HDTV streams
|
||||
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>
|
||||
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
||||
|
2
HISTORY
2
HISTORY
@ -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
|
||||
which the channel display is removed if no key has been pressed (thanks to
|
||||
Olivier Jacques).
|
||||
- Modified cDolbyRepacker to make sure PES packets don't exceed the requested length
|
||||
(thanks to Reinhard Nissl).
|
||||
|
260
remux.c
260
remux.c
@ -11,7 +11,7 @@
|
||||
* The cDolbyRepacker code was originally written by Reinhard Nissl <rnissl@gmx.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"
|
||||
@ -24,12 +24,14 @@
|
||||
|
||||
class cRepacker {
|
||||
protected:
|
||||
int maxPacketSize;
|
||||
uint8_t subStreamId;
|
||||
public:
|
||||
cRepacker(void) { subStreamId = 0; }
|
||||
cRepacker(void) { maxPacketSize = 6 + 65535; subStreamId = 0; }
|
||||
virtual ~cRepacker() {}
|
||||
virtual int Put(cRingBufferLinear *ResultBuffer, 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; }
|
||||
};
|
||||
|
||||
@ -40,6 +42,7 @@ private:
|
||||
static int frameSizes[];
|
||||
uchar fragmentData[6 + 65535];
|
||||
int fragmentLen;
|
||||
int fragmentTodo;
|
||||
uchar pesHeader[6 + 3 + 255 + 4 + 4];
|
||||
int pesHeaderLen;
|
||||
uchar chk1;
|
||||
@ -50,15 +53,21 @@ private:
|
||||
find_77,
|
||||
store_chk1,
|
||||
store_chk2,
|
||||
get_length
|
||||
get_length,
|
||||
output_packet
|
||||
} state;
|
||||
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:
|
||||
cDolbyRepacker(void);
|
||||
virtual int Put(cRingBufferLinear *ResultBuffer, 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[] = {
|
||||
// fs = 48 kHz
|
||||
64, 64, 80, 80, 96, 96, 112, 112, 128, 128, 160, 160, 192, 192, 224, 224,
|
||||
@ -93,17 +102,124 @@ cDolbyRepacker::cDolbyRepacker(void)
|
||||
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[7] = 0x00;
|
||||
pesHeader[8] = 0x00;
|
||||
pesHeaderLen = 9;
|
||||
AppendSubStreamID();
|
||||
}
|
||||
|
||||
void cDolbyRepacker::Reset(void)
|
||||
{
|
||||
ResetPesHeader();
|
||||
state = find_0b;
|
||||
ac3todo = 0;
|
||||
chk1 = 0;
|
||||
chk2 = 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)
|
||||
@ -111,60 +227,27 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
|
||||
// check for MPEG 2
|
||||
if ((Data[6] & 0xC0) != 0x80)
|
||||
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;
|
||||
int done = pesHeaderLen;
|
||||
// skip PES header
|
||||
int done = 6 + 3 + Data[8];
|
||||
int todo = Count - done;
|
||||
|
||||
// finish remainder of ac3 frame
|
||||
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;
|
||||
}
|
||||
|
||||
const uchar *data = Data + done;
|
||||
bool headerCopied = false;
|
||||
|
||||
// look for 0x0B 0x77 <chk1> <chk2> <frameSize>
|
||||
while (todo > 0) {
|
||||
switch (state) {
|
||||
case find_0b:
|
||||
if (*data == 0x0B)
|
||||
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);
|
||||
AppendSubStreamID();
|
||||
}
|
||||
}
|
||||
data++;
|
||||
done++;
|
||||
todo--;
|
||||
@ -191,10 +274,13 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
|
||||
todo--;
|
||||
++(int &)state;
|
||||
continue;
|
||||
case get_length: {
|
||||
case get_length:
|
||||
ac3todo = 2 * frameSizes[*data];
|
||||
// frameSizeCode was invalid => restart searching
|
||||
if (ac3todo <= 0) {
|
||||
// reset PES header instead of using/copying a wrong one
|
||||
ResetPesHeader();
|
||||
headerCopied = true;
|
||||
if (chk1 == 0x0B) {
|
||||
if (chk2 == 0x77) {
|
||||
state = store_chk1;
|
||||
@ -214,62 +300,32 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
|
||||
state = find_0b;
|
||||
continue;
|
||||
}
|
||||
// adjust PES packet length and output packet
|
||||
if (subStreamId) {
|
||||
pesHeader[pesHeaderLen++] = subStreamId;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
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;
|
||||
// append read data to header for common output processing
|
||||
pesHeader[pesHeaderLen++] = 0x0B;
|
||||
pesHeader[pesHeaderLen++] = 0x77;
|
||||
pesHeader[pesHeaderLen++] = chk1;
|
||||
pesHeader[pesHeaderLen++] = chk2;
|
||||
ac3todo -= 4;
|
||||
int bite = pesHeaderLen + 4;
|
||||
// enough data available to put PES packet into buffer?
|
||||
if (ac3todo <= todo) {
|
||||
int n = ResultBuffer->Put(pesHeader, bite);
|
||||
if (bite != n) {
|
||||
Reset();
|
||||
++(int &)state;
|
||||
// fall through to output
|
||||
case output_packet: {
|
||||
int bite = 0;
|
||||
// finish remainder of ac3 frame?
|
||||
if (fragmentTodo > 0) {
|
||||
if (!FinishRemainder(ResultBuffer, data, todo, done, bite))
|
||||
return done;
|
||||
}
|
||||
bite = ac3todo;
|
||||
n = ResultBuffer->Put(data, bite);
|
||||
if (bite != n) {
|
||||
Reset();
|
||||
return done + n;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// copy the fragment into separate buffer for later processing
|
||||
if (fragmentLen + bite > (int)sizeof(fragmentData)) {
|
||||
Reset();
|
||||
// start a new packet
|
||||
if (!StartNewPacket(ResultBuffer, data, todo, done, bite))
|
||||
return done;
|
||||
}
|
||||
memcpy(fragmentData + fragmentLen, pesHeader, bite);
|
||||
fragmentLen += bite;
|
||||
bite = todo;
|
||||
if (fragmentLen + bite > (int)sizeof(fragmentData)) {
|
||||
Reset();
|
||||
return done;
|
||||
}
|
||||
memcpy(fragmentData + fragmentLen, data, bite);
|
||||
fragmentLen += bite;
|
||||
// prepare for next packet
|
||||
ResetPesHeader();
|
||||
}
|
||||
data += bite;
|
||||
done += bite;
|
||||
todo -= 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;
|
||||
// break after ac3 frame?
|
||||
if (data[0] == 0x0B && data[1] == 0x77 && frameSizes[data[4]] > 0)
|
||||
return headerLen + frameSizes[data[4]];
|
||||
return headerLen + 2 * frameSizes[data[4]];
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -392,8 +448,10 @@ cTS2PES::cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t Aud
|
||||
audioCid = AudioCid;
|
||||
subStreamId = SubStreamId;
|
||||
repacker = Repacker;
|
||||
if (repacker)
|
||||
if (repacker) {
|
||||
repacker->SetMaxPacketSize(size);
|
||||
repacker->SetSubStreamId(subStreamId);
|
||||
}
|
||||
|
||||
tsErrors = 0;
|
||||
ccErrors = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user