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 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
|
||||||
|
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
|
- 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
258
remux.c
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user