ac3 of old (pre1.3.19) cannot detected/decoded with ffmpeg
Commit Message
Hi,
software decoding/detection of old ac3 streams seems to be impossible
with ffmpeg. To fix this I made a modification so that recognition works.
Can someone with more ac3 stream knowledge can have a look at this
diff ? This vdr-1.3.22 apply with some offset to vdr-1.3.32 and still works.
Comments
Hi,
Stefan Lucke wrote:
> software decoding/detection of old ac3 streams seems to be impossible
> with ffmpeg. To fix this I made a modification so that recognition works.
>
> Can someone with more ac3 stream knowledge can have a look at this
> diff ? This vdr-1.3.22 apply with some offset to vdr-1.3.32 and still works.
>
> + Length += 4;
> + *e++ = 0x80; //substream id
> + *e++ = 0x00; // nr of ac3 frames (sea AppendSubStream
> + *e++ = 0x00;
> + *e++ = 0x00; //??
The first byte (byte 0) is correct: 0x80 means the first dolby track.
Then, to be precise, byte 1 specifies the number of AC3 frames starting
in this packet. It must at least be 0x01, even if there is no AC3 frame
starting (see below), i. e. the packet contains just continuation data
of the current large AC3 frame which was started in a previous packet.
Byte 2 and 3 specifiy the offset in bytes from the last byte of the
substream header to the first byte of a starting AC3 frame in this
packet. I. e., 0x00 0x01 specifies, that byte 4 (the first byte
following the substream header) will be 0x0b (the first byte of the
syncword, which starts a new AC3 frame). A value of 0x00 0x00 means,
that no AC3 frame starts in this packet (i. e., just continuation data,
see above).
So, to create a proper substream header, one must "read" the stream,
find sync words, use the frame size and calculate frame count and
offset, which is a not a trivial task.
A further problem may arise by enlarging the packets to be able to
append the substream header: VDR's packets should never be larger than
IPACKS (= 2048 bytes). This means, each packet which is larger than 2044
bytes needs to be split into two packets to enforce this rule.
Maybe the code of cDolbyRepacker could be reused to transform these old
streams into the new format on the fly. Just feed it's Repack() method
with the original PES packets and you'll find the repacked packets in
the specified result buffer. BTW: whenever a DeviceClear() happens,
cDolbyRepacker should be Reset(), too.
Bye.
@@ -895,12 +905,41 @@
return -1;
}
+// 0 1 2 3 4 5 6 7 8 9
+// 00 00 01 BD ph pl xx xx hd si
+//
+// ph packet length high
+// pl packet length low
+// hd header length
+// si substream id
+// 00 00 01 bd 07 fa 84 80 05 23 cc 3d 21 df 0b 77
+// 00 00 01 bd 07 fa 80 00 00 60 6a 67 c9 7f c5 d3
+// 00 00 01 bd 00 20 80 00 05 80 01 00 01 60 6a 67
+// 00 00 01 bd 07 fa 80 00 00 94 6b 98 e8 b3 81 18
+// 00 00 01 bd 00 20 80 00 f9 80 01 00 01 94 6b 98
+// 00 00 01 bd 07 fa 80 00 00 c4 0e ca 39 4a 34 37
+// 00 00 01 bd 00 20 80 00 f9 80 01 00 01 c4 0e ca
+// 00 00 01 bd 03 2c 80 00 00 8d 88 e5 b8 6a c9 c9
+// 00 00 01 bd 00 04 80 00 0f 80 01 00 01 8d 88 e5
+// 00 00 01 bd 07 fa 84 80 05 23 cc 3d 92 5f 0b 77
+// 00 00 01 bd 07 fa 80 00 00 1a bb a5 4f 61 be 7b
+
+// pro7 ac3 2.0:
+// 00 00 01 bd 07 0c 84 81 05 2f 96 ed 89 1f 80 00 00 00 0b 77 2e 8c 1e 30 42 ff 70 80 01 00 00 7e
+// 00 00 01 bd 07 07 80 00 00 80 00 00 00 0b 77 5e c1 1e 30 42 ff 70 80 01 00 00 7e fb fb 86 0a 63
+// 00 00 01 bd 07 07 80 00 00 80 00 00 00 0b 77 bb 8c 1e 30 42 ff 70 80 01 00 00 7e fb ff 86 0d 29
+// 00 00 01 bd 07 07 80 00 00 80 00 00 00 0b 77 8c 6e 1e 30 42 ff 70 80 01 00 00 7e fb f5 86 0b 17
+// 00 00 01 bd 07 07 80 00 00 80 00 00 00 0b 77 fa 28 1e 30 42 ff 70 80 01 00 00 7e fb f5 86 0a c7
+// 00 00 01 bd 07 0c 84 81 05 2f 96 ed f9 9f 80 00 00 00 0b 77 9c c8 1e 30 42 ff 70 80 01 00 00 7e
+
int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
{
bool FirstLoop = true;
uchar c = Data[3];
const uchar *Start = Data;
const uchar *End = Start + Length;
+ uchar *fixData = NULL;
+
while (Start < End) {
int d = End - Start;
int w = d;
@@ -922,10 +961,40 @@
uchar SubStreamId = Data[PayloadOffset];
uchar SubStreamType = SubStreamId & 0xF0;
uchar SubStreamIndex = SubStreamId & 0x1F;
-
// Compatibility mode for old VDR recordings, where 0xBD was only AC3:
pre_1_3_19_PrivateStreamDeteced:
if (pre_1_3_19_PrivateStream) {
+ if (FirstLoop) {
+ if (!fixData && (fixData = (uchar *) malloc (Length+4))) {
+ uchar *e = fixData;
+ const uchar *s = Data;
+ int l = Length, i, k;
+
+ k = (Data[4] << 8) + Data[5];
+ k += 4;
+ memcpy (e, s, 8);
+ e += 8;
+ s += 8;
+ l -= 8;
+ i = (*s) + 1;
+ memcpy (e, s, i);
+ e += i;
+ s += i;
+ l -= i;
+ fixData[4] = k >> 8;
+ fixData[5] = k & 0x00ff;
+ Length += 4;
+ *e++ = 0x80; //substream id
+ *e++ = 0x00; // nr of ac3 frames (sea AppendSubStream
+ *e++ = 0x00;
+ *e++ = 0x00; //??
+ memcpy (e, s, l);
+ Start = Data = (const uchar *) fixData;
+ End = Start + Length;
+ d = End - Start;
+ w = d;
+ }
+ }
SubStreamId = c;
SubStreamType = 0x80;
SubStreamIndex = 0;
@@ -971,10 +1040,17 @@
else {
if (Start != Data)
esyslog("ERROR: incomplete PES packet write!");
+ if (fixData)
+ free(fixData);
return Start == Data ? w : Start - Data;
}
FirstLoop = false;
}
+ if (fixData) {
+ free(fixData);
+ Length -=4;
+ }
+
return Length;
}