@@ -104,6 +104,7 @@ public:
virtual int QuerySnoopSize(void) { return 0; }
void SetMaxPacketSize(int MaxPacketSize) { maxPacketSize = MaxPacketSize; }
void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; }
+ virtual void LogTSPacket(const uchar *Data) {}
};
int cRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded)
@@ -142,7 +143,7 @@ void cCommonRepacker::Reset(void)
{
cRepacker::Reset();
skippedBytes = 0;
- packetTodo = maxPacketSize - 6 - 3;
+ packetTodo = 0;
fragmentLen = 0;
pesHeaderLen = 0;
pesHeaderBackupLen = 0;
@@ -361,7 +362,7 @@ void cVideoRepacker::Repack(cRingBufferL
done++;
todo--;
// do we have to start a new packet as there is no more space left?
- if (--packetTodo <= 0) {
+ if (state != syncing && --packetTodo <= 0) {
// we connot start a new packet here if the current might end in a start
// code and this start code shall possibly be put in the next packet. So
// overfill the current packet until we can safely detect that we won't
@@ -468,6 +469,9 @@ void cVideoRepacker::Repack(cRingBufferL
int cVideoRepacker::BreakAt(const uchar *Data, int Count)
{
+ if (initiallySyncing)
+ return -1; // fill the packet buffer completely until we have synced once
+
int PesPayloadOffset = 0;
if (AnalyzePesHeader(Data, Count, PesPayloadOffset) <= phInvalid)
@@ -502,6 +506,60 @@ int cVideoRepacker::BreakAt(const uchar
return PesPayloadOffset + packetTodo + 4;
}
+// --- cTSLogger -------------------------------------------------------------
+
+class cTSLogger
+{
+ uchar *buffer;
+ int size;
+ int fill;
+ int64_t count;
+ int dumps;
+ int cid;
+
+public:
+ cTSLogger(int Cid);
+ ~cTSLogger();
+ void Put(const uchar *Data);
+ void Dump();
+};
+
+cTSLogger::cTSLogger(int Cid)
+{
+ size = 100; // number of TS packets to log
+ buffer = new uchar[size * 188];
+ fill = 0;
+ count = 0;
+ dumps = 0;
+ cid = Cid;
+}
+
+cTSLogger::~cTSLogger()
+{
+ delete [] buffer;
+}
+
+void cTSLogger::Put(const uchar *Data)
+{
+ memcpy(&buffer[(count++ % size) * 188], Data, 188);
+ if (fill < size)
+ fill++;
+}
+
+void cTSLogger::Dump()
+{
+ char name[200];
+ sprintf(name, "/video/ts_%d_%ld_0x%02X_%03d_%lld_%d.log", getpid(), pthread_self(), cid, dumps++, count, fill);
+ esyslog("cTSLogger: dumping to file '%s'", name);
+
+ FILE *f = fopen(name, "wb");
+ for (int64_t n = count - fill; n < count; n++)
+ fwrite(&buffer[(n % size) * 188], 188, 1, f);
+ fclose(f);
+
+ fill = 0;
+}
+
// --- cAudioRepacker --------------------------------------------------------
class cAudioRepacker : public cCommonRepacker {
@@ -513,9 +571,12 @@ private:
} state;
int frameTodo;
int frameSize;
- static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL);
+ int cid;
+ /* static */ bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL);
+ cTSLogger tsLogger;
+ virtual void LogTSPacket(const uchar *Data) { tsLogger.Put(Data); }
public:
- cAudioRepacker(void);
+ cAudioRepacker(int Cid);
virtual void Reset(void);
virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
virtual int BreakAt(const uchar *Data, int Count);
@@ -536,8 +597,10 @@ int cAudioRepacker::bitRates[2][3][16] =
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1
};
-cAudioRepacker::cAudioRepacker(void)
+cAudioRepacker::cAudioRepacker(int Cid)
+ : tsLogger(Cid)
{
+ cid = Cid;
Reset();
}
@@ -566,23 +629,41 @@ bool cAudioRepacker::IsValidAudioHeader(
//int orignal_copy = (Header & 0x00000004) >> 2;
int emphasis = (Header & 0x00000003);
- if (syncword != 0xFFF)
+ if (syncword != 0xFFF) {
+ if (FrameSize)
+ esyslog("cAudioRepacker(0x%02X): invalid audio header 0x%08X: syncword", cid, Header);
return false;
+ }
- if (id == 0 && !Mpeg2) // reserved in MPEG 1
+ if (id == 0 && !Mpeg2) { // reserved in MPEG 1
+ if (FrameSize)
+ esyslog("cAudioRepacker(0x%02X): invalid audio header 0x%08X: id", cid, Header);
return false;
+ }
- if (layer == 0) // reserved
+ if (layer == 0) { // reserved
+ if (FrameSize)
+ esyslog("cAudioRepacker(0x%02X): invalid audio header 0x%08X: layer", cid, Header);
return false;
+ }
- if (bitrate_index == 0xF) // forbidden
+ if (bitrate_index == 0xF) { // forbidden
+ if (FrameSize)
+ esyslog("cAudioRepacker(0x%02X): invalid audio header 0x%08X: bitrate_index", cid, Header);
return false;
+ }
- if (sampling_frequency == 3) // reserved
+ if (sampling_frequency == 3) { // reserved
+ if (FrameSize)
+ esyslog("cAudioRepacker(0x%02X): invalid audio header 0x%08X: sampling_frequency", cid, Header);
return false;
+ }
- if (emphasis == 2) // reserved
+ if (emphasis == 2) { // reserved
+ if (FrameSize)
+ esyslog("cAudioRepacker(0x%02X): invalid audio header 0x%08X: emphasis", cid, Header);
return false;
+ }
if (FrameSize) {
if (bitrate_index == 0)
@@ -649,12 +730,9 @@ void cAudioRepacker::Repack(cRingBufferL
const uchar *payload = data;
while (todo > 0) {
- // collect number of skipped bytes while syncing
- if (state <= syncing)
- skippedBytes++;
- else if (frameTodo > 0) {
- frameTodo--;
- if (frameTodo == 0 && state == scanFrame) {
+ // do we have to start a new packet as the current is done?
+ if (frameTodo > 0) {
+ if (--frameTodo == 0) {
// the current audio frame is is done now. So push out the packet to
// start a new packet for the next audio frame.
PushOutPacket(ResultBuffer, payload, data - payload);
@@ -662,11 +740,15 @@ void cAudioRepacker::Repack(cRingBufferL
state = syncing;
}
}
+ // collect number of skipped bytes while syncing
+ if (state <= syncing)
+ skippedBytes++;
// did we reach an audio frame header?
scanner <<= 8;
scanner |= *data;
if ((scanner & 0xFFF00000) == 0xFFF00000) {
- if (frameTodo <= 0 && IsValidAudioHeader(scanner, mpegLevel == phMPEG2, &frameSize)) {
+ int LastFrameSize = frameSize;
+ if (frameTodo <= 0 && (frameSize == 0 || skippedBytes >= 4) && IsValidAudioHeader(scanner, mpegLevel == phMPEG2, &frameSize)) {
if (state == scanFrame) {
// As a new audio frame starts here, the previous one is done. So push
// out the packet to start a new packet for the next audio frame. If
@@ -678,10 +760,16 @@ void cAudioRepacker::Repack(cRingBufferL
state = syncing;
}
if (state == syncing) {
+ // report a change of frame size
+ if (!initiallySyncing && LastFrameSize != frameSize)
+ esyslog("cAudioRepacker(0x%02X): frame size changes from %d to %d", cid, LastFrameSize, frameSize);
if (initiallySyncing) // omit report for the typical initial case
initiallySyncing = false;
- else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes
- esyslog("cAudioRepacker: skipped %d bytes to sync on next audio frame", skippedBytes - SkippedBytesLimit);
+ else if (skippedBytes > SkippedBytesLimit) { // report that syncing dropped some bytes
+ esyslog("cAudioRepacker(0x%02X): skipped %d bytes to sync on next audio frame", cid, skippedBytes - SkippedBytesLimit);
+ esyslog("cAudioRepacker(0x%02X): synchronization based on this header: 0x%08X, frame size: %d", cid, scanner, frameSize);
+ tsLogger.Dump();
+ }
skippedBytes = 0;
// if there is a PES header available, then use it ...
if (pesHeaderBackupLen > 0) {
@@ -728,11 +816,15 @@ void cAudioRepacker::Repack(cRingBufferL
}
}
}
+ else if (skippedBytes == SkippedBytesLimit) {
+ esyslog("cAudioRepacker(0x%02X): no valid audio frame header (0x%08X) at expected location", cid, scanner);
+ tsLogger.Dump();
+ }
data++;
done++;
todo--;
// do we have to start a new packet as there is no more space left?
- if (--packetTodo <= 0) {
+ if (state != syncing && --packetTodo <= 0) {
// We connot start a new packet here if the current might end in an audio
// frame header and this header shall possibly be put in the next packet. So
// overfill the current packet until we can safely detect that we won't
@@ -829,13 +921,16 @@ void cAudioRepacker::Repack(cRingBufferL
// report that syncing dropped some bytes
if (skippedBytes > SkippedBytesLimit) {
if (!initiallySyncing) // omit report for the typical initial case
- esyslog("cAudioRepacker: skipped %d bytes while syncing on next audio frame", skippedBytes - SkippedBytesLimit);
+ esyslog("cAudioRepacker(0x%02X): skipped %d bytes while syncing on next audio frame", cid, skippedBytes - SkippedBytesLimit);
skippedBytes = SkippedBytesLimit;
}
}
int cAudioRepacker::BreakAt(const uchar *Data, int Count)
{
+ if (initiallySyncing)
+ return -1; // fill the packet buffer completely until we have synced once
+
int PesPayloadOffset = 0;
ePesHeader MpegLevel = AnalyzePesHeader(Data, Count, PesPayloadOffset);
@@ -1189,6 +1284,9 @@ void cDolbyRepacker::Repack(cRingBufferL
int cDolbyRepacker::BreakAt(const uchar *Data, int Count)
{
+ if (initiallySyncing)
+ return -1; // fill the packet buffer completely until we have synced once
+
// enough data for test?
if (Count < 6 + 3)
return -1;
@@ -1514,8 +1612,10 @@ void cTS2PES::instant_repack(const uint8
}
if (mpeg == 1) {
if (flag1 == 0xFF) { // MPEG1 stuffing
- if (++mpeg1_stuffing > 16)
+ if (++mpeg1_stuffing > 16) {
found = 0; // invalid MPEG1 header
+ esyslog("instant_repack: invalid MPEG1 header: stuffing");
+ }
else { // ignore stuffing
found--;
if (plength > 0)
@@ -1524,8 +1624,10 @@ void cTS2PES::instant_repack(const uint8
}
else if ((flag1 & 0xC0) == 0x40) // STD_buffer_scale/size
mpeg1_required += 2;
- else if (flag1 != 0x0F && (flag1 & 0xF0) != 0x20 && (flag1 & 0xF0) != 0x30)
+ else if (flag1 != 0x0F && (flag1 & 0xF0) != 0x20 && (flag1 & 0xF0) != 0x30) {
found = 0; // invalid MPEG1 header
+ esyslog("instant_repack: invalid MPEG1 header: required 7");
+ }
else {
flag2 = 0;
hlength = 0;
@@ -1543,8 +1645,10 @@ void cTS2PES::instant_repack(const uint8
if (!done && (mpeg == 2 || mpeg1_required > 7)) {
hlength = Buf[c++];
found++;
- if (mpeg == 1 && hlength != 0x0F && (hlength & 0xF0) != 0x20 && (hlength & 0xF0) != 0x30)
+ if (mpeg == 1 && hlength != 0x0F && (hlength & 0xF0) != 0x20 && (hlength & 0xF0) != 0x30) {
found = 0; // invalid MPEG1 header
+ esyslog("instant_repack: invalid MPEG1 header: required 9");
+ }
}
break;
default:
@@ -1625,6 +1729,9 @@ void cTS2PES::ts_to_pes(const uint8_t *B
if (!Buf)
return;
+ if (repacker)
+ repacker->LogTSPacket(Buf);
+
if (Buf[1] & TS_ERROR)
tsErrors++;
if ((Buf[3] ^ ccCounter) & CONT_CNT_MASK) {
@@ -1685,13 +1792,15 @@ cRemux::cRemux(int VPid, const int *APid
#endif
if (APids) {
int n = 0;
- while (*APids && numTracks < MAXTRACKS && n < MAXAPIDS)
+ while (*APids && numTracks < MAXTRACKS && n < MAXAPIDS) {
#define TEST_cAudioRepacker
#ifdef TEST_cAudioRepacker
- ts2pes[numTracks++] = new cTS2PES(*APids++, resultBuffer, IPACKS, 0xC0 + n++, 0x00, new cAudioRepacker);
+ ts2pes[numTracks++] = new cTS2PES(*APids++, resultBuffer, IPACKS, 0xC0 + n, 0x00, new cAudioRepacker(0xC0 + n));
+ n++;
#else
ts2pes[numTracks++] = new cTS2PES(*APids++, resultBuffer, IPACKS, 0xC0 + n++);
#endif
+ }
}
if (DPids) {
int n = 0;