Hi Reinhard.
Tried the new repacker, but it was not successful : Jul 18 08:42:04 media vdr[4972]: cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed Jul 18 08:42:04 media vdr[4972]: cVideoRepacker: skipped 1545 bytes while syncing on next picture Jul 18 08:42:04 media vdr[4972]: cVideoRepacker: skipped 493 bytes while syncing on next picture Jul 18 08:42:04 media vdr[4972]: cVideoRepacker: skipped 2039 bytes while syncing on next picture Jul 18 08:42:04 media last message repeated 5 times Jul 18 08:42:04 media vdr[4972]: cVideoRepacker: skipped 1398 bytes while syncing on next picture Jul 18 08:42:04 media vdr[4972]: cVideoRepacker: skipped 4 bytes to sync on next picture Jul 18 08:42:04 media vdr[4969]: cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed Jul 18 08:42:04 media vdr[4969]: cVideoRepacker: skipped 1545 bytes while syncing on next picture Jul 18 08:42:04 media vdr[4969]: cVideoRepacker: skipped 493 bytes while syncing on next picture Jul 18 08:42:04 media vdr[4969]: cVideoRepacker: skipped 2039 bytes while syncing on next picture Jul 18 08:42:04 media last message repeated 5 times Jul 18 08:42:04 media vdr[4969]: cVideoRepacker: skipped 1398 bytes while syncing on next picture Jul 18 08:42:04 media vdr[4969]: cVideoRepacker: skipped 4 bytes to sync on next picture Jul 18 08:42:20 media vdr[4970]: ERROR: 1 ring buffer overflow (65 bytes dropped) Jul 18 08:42:26 media vdr[4970]: ERROR: 10022 ring buffer overflows (1884136 bytes dropped) Jul 18 08:42:32 media vdr[4970]: ERROR: 9840 ring buffer overflows (1849920 bytes dropped) Jul 18 08:42:35 media vdr[4968]: ERROR: video data stream broken Jul 18 08:42:35 media vdr[4968]: initiating emergency exit Jul 18 08:42:35 media vdr[4555]: emergency exit requested - shutting down
----- Original Message ----- From: "Reinhard Nissl" rnissl@gmx.de To: "Klaus Schmidinger's VDR" vdr@linuxtv.org Sent: Sunday, July 17, 2005 11:17 AM Subject: [vdr] VDR-1.3.27: updated cVideoRepacker
Hi,
I'd like to invite you to test the attached patch which now also supports MPEG1 video streams (vdr-1.3.27-remux-repacker.patch).
Besides that, a major change has been made in error reporting. Previous versions often reported a buffer overflow (although there was no buffer overflow) just as an indication for not beeing able to handle the data. Most likely this lead to the assumption that the repacker got stuck.
VDR-1.3.28 will also (most likely) receive the second attached patch "vdr-1.3.27-dvbplayer-sequence-end-code.patch". It will cause a still image to be immediately shown by (softdevices like) vdr-xine, e. g. when moving or jumping to cutting marks. Does this patch have any bad impact on FF-devices?
As old recordings (prior to VDR-1.3.26 or 1.3.27 with cVideoRepacker disabled) can have fragmented frames and VDR doesn't handle them correctly when passing still images to a device, it is hardly possible to edit cutting marks (at least) in vdr-xine for such recordings.
The patch http://home.vr-web.de/~rnissl/vdr-1.3.24-dvbplayer.patch is a hack to at least fix the I-frames needed for fast forward, fast rewind, slow rewind and editing cutting marks. As you may see, it collides with the attached dvbplayer patch, so you have to decide whether to use the attached one and just edit new recordings or to use the one taken at version 1.3.24 and be able to edit new and old -- but only MPEG2 -- recordings.
Bye.
Dipl.-Inform. (FH) Reinhard Nissl mailto:rnissl@gmx.de
--------------------------------------------------------------------------------
--- vdr-1.3.27-orig/remux.c 2005-06-19 12:17:00.000000000 +0200 +++ vdr-1.3.27/remux.c 2005-07-16 20:54:47.499277234 +0200 @@ -26,17 +26,92 @@ class cRepacker { protected: int maxPacketSize; uint8_t subStreamId;
- static void DroppedData(const char *Reason, int Count) { esyslog("%s
(dropped %d bytes)", Reason, Count); }
- static int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
Count)
- {
- int n = ResultBuffer->Put(Data, Count);
- if (n != Count)
esyslog("ERROR: result buffer overflow, dropped %d out of %d
byte", Count - n, Count);
- return n;
- }
- static int AnalyzePesHeader(const uchar *Data, int Count, int
&PesPayloadOffset, bool *ContinueationHeader = 0); public: cRepacker(void) { maxPacketSize = 6 + 65535; subStreamId = 0; } virtual ~cRepacker() {} virtual void Reset(void) {}
- virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
Count) = 0;
- virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
int Count) = 0; virtual int BreakAt(const uchar *Data, int Count) = 0; virtual int QuerySnoopSize(void) { return 0; } void SetMaxPacketSize(int MaxPacketSize) { maxPacketSize = MaxPacketSize; } void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; } };
+int cRepacker::AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinueationHeader) +{
- if (Count < 7)
return -1; // too short
- if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
if (Count < 9)
return -1; // too short
PesPayloadOffset = 6 + 3 + Data[8];
if (Count < PesPayloadOffset)
return -1; // too short
if (ContinueationHeader)
*ContinueationHeader = ((Data[6] == 0x80) && !Data[7] &&
!Data[8]);
return 2; // MPEG 2
}
- // check for MPEG 1 ...
- PesPayloadOffset = 6;
- // skip up to 16 stuffing bytes
- for (int i = 0; i < 16; i++) {
if (Data[PesPayloadOffset] != 0xFF)
break;
if (Count <= ++PesPayloadOffset)
return -1; // too short
}
- // skip STD_buffer_scale/size
- if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
PesPayloadOffset += 2;
if (Count <= PesPayloadOffset)
return -1; // too short
}
- if (ContinueationHeader)
*ContinueationHeader = false;
- if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
// skip PTS only
PesPayloadOffset += 5;
}
- else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
// skip PTS and DTS
PesPayloadOffset += 10;
}
- else if (Data[PesPayloadOffset] == 0x0F) {
// continueation header
PesPayloadOffset++;
if (ContinueationHeader)
*ContinueationHeader = true;
}
- else
return 0; // unknown
- if (Count < PesPayloadOffset)
return -1; // too short
- return 1; // MPEG 1
+}
// --- cVideoRepacker --------------------------------------------------------
class cVideoRepacker : public cRepacker { @@ -61,7 +136,7 @@ private: public: cVideoRepacker(void); virtual void Reset(void);
- virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
Count);
- virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
int Count); virtual int BreakAt(const uchar *Data, int Count); virtual int QuerySnoopSize() { return 4; } }; @@ -95,7 +170,7 @@ bool cVideoRepacker::PushOutPacket(cRing // to strip off any partially contained start code. int Bite = fragmentLen + (Count >= 0 ? 0 : Count); // put data into result buffer
int n = ResultBuffer->Put(fragmentData, Bite);
if (n != Bite) { Reset(); return false;int n = Put(ResultBuffer, fragmentData, Bite);
@@ -110,7 +185,7 @@ bool cVideoRepacker::PushOutPacket(cRing // to strip off any partially contained start code. int Bite = pesHeaderLen + (Count >= 0 ? 0 : Count); // put data into result buffer
int n = ResultBuffer->Put(pesHeader, Bite);
if (n != Bite) { Reset(); return false;int n = Put(ResultBuffer, pesHeader, Bite);
@@ -122,7 +197,7 @@ bool cVideoRepacker::PushOutPacket(cRing // amount of data to put into result buffer int Bite = Count; // put data into result buffer
int n = ResultBuffer->Put(Data, Bite);
if (n != Bite) { Reset(); return false;int n = Put(ResultBuffer, Data, Bite);
@@ -132,23 +207,29 @@ bool cVideoRepacker::PushOutPacket(cRing return true; }
-int cVideoRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) +void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) {
- // synchronisation is detected some bytes after frame start.
- const int SkippedBytesLimit = 4;
- // reset local scanner localStart = -1;
// check for MPEG 2
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);
- int pesPayloadOffset = 0;
- bool continueationHeader = false;
- int mpegLevel = AnalyzePesHeader(Data, Count, pesPayloadOffset,
&continueationHeader);
- if (mpegLevel <= 0) {
DroppedData("cVideoRepacker: no valid PES packet header found",
Count);
return;
}
if (!continueationHeader) {
// backup PES header
pesHeaderBackupLen = pesPayloadOffset;
memcpy(pesHeaderBackup, Data, pesHeaderBackupLen);
}
// skip PES header
- int done = 6 + 3 + Data[8];
- int done = pesPayloadOffset; int todo = Count - done; const uchar *data = Data + done; // remember start of the data
@@ -191,15 +272,17 @@ int cVideoRepacker::Put(cRingBufferLinea // the byte count get's negative then the current buffer ends in a // partitial start code that must be stripped off, as it shall be put // in the next packet.
if (!PushOutPacket(ResultBuffer, payload, data - 3 -
payload))
return done - 3;
if (!PushOutPacket(ResultBuffer, payload, data - 3 -
payload)) {
DroppedData("cVideoRepacker: result buffer
overflow", Count - (done - 3));
return;
} // go on with syncing to the next picture state = syncing; } if (state == syncing) { // report that syncing dropped some bytes
if (skippedBytes > 4)
esyslog("cVideoRepacker: skipped %d bytes to sync
on next picture", skippedBytes - 4);
if (skippedBytes > SkippedBytesLimit)
esyslog("cVideoRepacker: skipped %d bytes to sync
on next picture", skippedBytes - SkippedBytesLimit); skippedBytes = 0; // if there is a PES header available, then use it ... if (pesHeaderBackupLen > 0) { @@ -222,9 +305,14 @@ int cVideoRepacker::Put(cRingBufferLinea pesHeader[pesHeaderLen++] = Data[3]; // video stream ID pesHeader[pesHeaderLen++] = 0x00; // length still unknown pesHeader[pesHeaderLen++] = 0x00; // length still unknown
pesHeader[pesHeaderLen++] = 0x80;
pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00;
if (mpegLevel == 2) {
pesHeader[pesHeaderLen++] = 0x80;
pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00;
}
else
pesHeader[pesHeaderLen++] = 0x0F; } // append the first three bytes of the start code pesHeader[pesHeaderLen++] = 0x00;
@@ -299,8 +387,10 @@ int cVideoRepacker::Put(cRingBufferLinea const uchar *excessData = fragmentData + fragmentLen + bite; // a negative byte count means to drop some bytes from the current // fragment's tail, to not exceed the maximum packet size.
if (!PushOutPacket(ResultBuffer, payload, bite))
return done;
if (!PushOutPacket(ResultBuffer, payload, bite)) {
DroppedData("cVideoRepacker: result buffer overflow",
Count - done);
return;
} // create a continuation PES header pesHeaderLen = 0; pesHeader[pesHeaderLen++] = 0x00;
@@ -309,9 +399,15 @@ int cVideoRepacker::Put(cRingBufferLinea pesHeader[pesHeaderLen++] = Data[3]; // video stream ID pesHeader[pesHeaderLen++] = 0x00; // length still unknown pesHeader[pesHeaderLen++] = 0x00; // length still unknown
pesHeader[pesHeaderLen++] = 0x80;
pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00;
if (mpegLevel == 2) {
pesHeader[pesHeaderLen++] = 0x80;
pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00;
}
else
pesHeader[pesHeaderLen++] = 0x0F;
// copy any excess data while (bite++ < 0) { // append the excess data here
@@ -344,22 +440,20 @@ int cVideoRepacker::Put(cRingBufferLinea fragmentLen += bite; } }
- // we've eaten the whole packet ;-)
- return Count;
- // report that syncing dropped some bytes
- if (skippedBytes > SkippedBytesLimit) {
esyslog("cVideoRepacker: skipped %d bytes while syncing on next
picture", skippedBytes - SkippedBytesLimit);
skippedBytes = SkippedBytesLimit;
}
}
int cVideoRepacker::BreakAt(const uchar *Data, int Count) {
- // enough data for test?
- if (Count < 6 + 3)
return -1;
- // check for MPEG 2
- if ((Data[6] & 0xC0) != 0x80)
return -1;
- int headerLen = Data[8] + 6 + 3;
- // enough data for test?
- if (Count < headerLen)
return -1;
- int PesPayloadOffset = 0;
- if (AnalyzePesHeader(Data, Count, PesPayloadOffset) <= 0)
return -1; // not enough data for test
- // just detect end of picture if (state == scanPicture) { // setup local scanner
@@ -368,7 +462,7 @@ int cVideoRepacker::BreakAt(const uchar localStart = 0; } // start where we've stopped at the last run
const uchar *data = Data + headerLen + localStart;
const uchar *limit = Data + Count; // scan data while (data < limit) {const uchar *data = Data + PesPayloadOffset + localStart;
@@ -386,7 +480,7 @@ int cVideoRepacker::BreakAt(const uchar } } // just fill up packet and append next start code
- return headerLen + packetTodo + 4;
- return PesPayloadOffset + packetTodo + 4;
}
// --- cDolbyRepacker -------------------------------------------------------- @@ -412,6 +506,7 @@ private: get_length, output_packet } state;
- int skippedBytes; 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); @@ -419,7 +514,7 @@ private: public: cDolbyRepacker(void); virtual void Reset(void);
- virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
Count);
- virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
int Count); virtual int BreakAt(const uchar *Data, int Count); };
@@ -490,6 +585,7 @@ void cDolbyRepacker::Reset(void) fragmentLen = 0; fragmentTodo = 0; pesHeaderBackupLen = 0;
- skippedBytes = 0;
}
bool cDolbyRepacker::FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite) @@ -499,7 +595,7 @@ bool cDolbyRepacker::FinishRemainder(cRi // output a previous fragment first if (fragmentLen > 0) { Bite = fragmentLen;
int n = ResultBuffer->Put(fragmentData, Bite);
int n = Put(ResultBuffer, fragmentData, Bite); if (Bite != n) { Reset(); return false;
@@ -507,7 +603,7 @@ bool cDolbyRepacker::FinishRemainder(cRi fragmentLen = 0; } Bite = fragmentTodo;
int n = ResultBuffer->Put(Data, Bite);
if (Bite != n) { Reset(); Done += n;int n = Put(ResultBuffer, Data, Bite);
@@ -543,13 +639,13 @@ bool cDolbyRepacker::StartNewPacket(cRin 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;int n = Put(ResultBuffer, pesHeader, Bite);
n = ResultBuffer->Put(Data, Bite);
if (Bite != n) { Reset(); Done += n;n = Put(ResultBuffer, Data, Bite);
@@ -582,11 +678,16 @@ bool cDolbyRepacker::StartNewPacket(cRin return true; }
-int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) +void cDolbyRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) {
- // synchronisation is detected some bytes after frame start.
- const int SkippedBytesLimit = 4;
- // check for MPEG 2
- if ((Data[6] & 0xC0) != 0x80)
return 0;
if ((Data[6] & 0xC0) != 0x80) {
DroppedData("cDolbyRepacker: MPEG 2 PES header expected", Count);
return;
}
// backup PES header if (Data[6] != 0x80 || Data[7] != 0x00 || Data[8] != 0x00) {
@@ -616,6 +717,7 @@ int cDolbyRepacker::Put(cRingBufferLinea data++; done++; todo--;
skippedBytes++; // collect number of skipped bytes while
syncing continue; case find_77: if (*data != 0x77) { @@ -625,18 +727,21 @@ int cDolbyRepacker::Put(cRingBufferLinea data++; done++; todo--;
skippedBytes++; // collect number of skipped bytes while
syncing ++(int &)state; continue; case store_chk1: chk1 = *data++; done++; todo--;
skippedBytes++; // collect number of skipped bytes while
syncing ++(int &)state; continue; case store_chk2: chk2 = *data++; done++; todo--;
skippedBytes++; // collect number of skipped bytes while
syncing ++(int &)state; continue; case get_length: @@ -664,6 +769,10 @@ int cDolbyRepacker::Put(cRingBufferLinea state = find_0b; continue; }
// report that syncing dropped some bytes
if (skippedBytes > SkippedBytesLimit)
esyslog("cDolbyRepacker: skipped %d bytes to sync on
next AC3 frame", skippedBytes - SkippedBytesLimit);
skippedBytes = 0; // append read data to header for common output processing pesHeader[pesHeaderLen++] = 0x0B; pesHeader[pesHeaderLen++] = 0x77;
@@ -676,13 +785,17 @@ int cDolbyRepacker::Put(cRingBufferLinea int bite = 0; // finish remainder of ac3 frame? if (fragmentTodo > 0) {
if (!FinishRemainder(ResultBuffer, data, todo, done,
bite))
return done;
if (!FinishRemainder(ResultBuffer, data, todo, done,
bite)) {
DroppedData("cDolbyRepacker: result buffer
overflow", Count - done);
return;
} } else { // start a new packet
if (!StartNewPacket(ResultBuffer, data, todo, done,
bite))
return done;
if (!StartNewPacket(ResultBuffer, data, todo, done,
bite)) {
DroppedData("cDolbyRepacker: result buffer
overflow", Count - done);
return;
} // prepare for next (continuation) packet ResetPesHeader(state == output_packet); }
@@ -693,7 +806,11 @@ int cDolbyRepacker::Put(cRingBufferLinea } } }
- return Count;
- // report that syncing dropped some bytes
- if (skippedBytes > SkippedBytesLimit) {
esyslog("cDolbyRepacker: skipped %d bytes while syncing on next AC3
frame", skippedBytes - 4);
skippedBytes = SkippedBytesLimit;
}
}
int cDolbyRepacker::BreakAt(const uchar *Data, int Count) @@ -845,9 +962,13 @@ void cTS2PES::Clear(void)
void cTS2PES::store(uint8_t *Data, int Count) {
- int n = repacker ? repacker->Put(resultBuffer, Data, Count) :
resultBuffer->Put(Data, Count);
- if (n != Count)
esyslog("ERROR: result buffer overflow, dropped %d out of %d byte",
Count - n, Count);
- if (repacker)
repacker->Repack(resultBuffer, Data, Count);
- else {
int n = resultBuffer->Put(Data, Count);
if (n != Count)
esyslog("ERROR: result buffer overflow, dropped %d out of %d
byte", Count - n, Count);
}
}
void cTS2PES::reset_ipack(void) @@ -867,7 +988,7 @@ void cTS2PES::reset_ipack(void)
void cTS2PES::send_ipack(void) {
- if (count < 10)
- if (count <= ((mpeg == 2) ? 9 : 7)) // skip empty packets return; buf[3] = (AUDIO_STREAM_S <= cid && cid <= AUDIO_STREAM_E && audioCid) ?
audioCid : cid; buf[4] = (uint8_t)(((count - 6) & 0xFF00) >> 8); @@ -1155,7 +1276,7 @@ cRemux::cRemux(int VPid, const int *APid resultBuffer = new cRingBufferLinear(RESULTBUFFERSIZE, IPACKS, false, "Result"); resultBuffer->SetTimeouts(0, 100); if (VPid) -//#define TEST_cVideoRepacker +#define TEST_cVideoRepacker #ifdef TEST_cVideoRepacker ts2pes[numTracks++] = new cTS2PES(VPid, resultBuffer, IPACKS, 0x00, 0x00, new cVideoRepacker); #else
--------------------------------------------------------------------------------
--- ../vdr-1.3.27-orig/dvbplayer.c 2005-05-22 13:26:51.000000000 +0200 +++ dvbplayer.c 2005-07-16 22:57:43.000000000 +0200 @@ -666,11 +666,34 @@ void cDvbPlayer::Goto(int Index, bool St int FileOffset, Length; Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
uchar b[MAXFRAMESIZE];
uchar b[MAXFRAMESIZE + 4 + 5 + 4]; int r = ReadFrame(replayFile, b, Length, sizeof(b)); if (r > 0) { if (playMode == pmPause) DevicePlay();
// append sequence end code to get the image shown immediately
with softdevices
if (r > 6) { // should be always true
b[r++] = 0x00;
b[r++] = 0x00;
b[r++] = 0x01;
b[r++] = b[3];
if (b[6] & 0x80) { // MPEG 2
b[r++] = 0x00;
b[r++] = 0x07;
b[r++] = 0x80;
b[r++] = 0x00;
b[r++] = 0x00;
}
else { // MPEG 1
b[r++] = 0x00;
b[r++] = 0x05;
b[r++] = 0x0F;
}
b[r++] = 0x00;
b[r++] = 0x00;
b[r++] = 0x01;
b[r++] = 0xB7;
} DeviceStillPicture(b, r); } playMode = pmStill;
--------------------------------------------------------------------------------
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
--------------------------------------------------------------------------------
No virus found in this incoming message. Checked by AVG Anti-Virus. Version: 7.0.323 / Virus Database: 267.9.0/49 - Release Date: 16/07/2005