qtdemux: Use already parsed codec data boxes instead of parsing a second time

And parse common boxes in a central place.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8929>
This commit is contained in:
Sebastian Dröge 2025-05-03 18:07:18 +03:00 committed by GStreamer Marge Bot
parent cba7ce1228
commit 8a30c6b13b

View File

@ -14541,7 +14541,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
GNode *minf; GNode *minf;
GNode *stbl; GNode *stbl;
GNode *stsd; GNode *stsd;
GNode *mp4a;
GNode *esds; GNode *esds;
GNode *tref; GNode *tref;
GNode *udta; GNode *udta;
@ -14805,6 +14804,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
GNode *colr; GNode *colr;
GNode *fiel; GNode *fiel;
GNode *pasp; GNode *pasp;
GNode *btrt;
guint32 version; guint32 version;
gboolean gray; gboolean gray;
gint depth, palette_size, palette_count; gint depth, palette_size, palette_count;
@ -14978,6 +14978,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
pasp = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_pasp); pasp = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_pasp);
colr = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_colr); colr = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_colr);
fiel = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_fiel); fiel = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_fiel);
btrt = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_btrt);
if (pasp) { if (pasp) {
const guint8 *pasp_data = (const guint8 *) pasp->data; const guint8 *pasp_data = (const guint8 *) pasp->data;
@ -15035,87 +15036,18 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
} }
if (esds) { if (btrt) {
gst_qtdemux_handle_esds (qtdemux, stream, entry, esds, const guint8 *data;
stream->stream_tags); guint32 size;
} else {
switch (fourcc) {
case FOURCC_H264:
case FOURCC_avc1:
case FOURCC_avc3:
{
guint32 len = QT_UINT32 (stsd_entry_data);
len = len <= 0x56 ? 0 : len - 0x56;
const guint8 *avc_data = stsd_entry_data + 0x56;
/* find avcC */ data = btrt->data;
while (len >= 8) { size = QT_UINT32 (data);
guint32 size = QT_UINT32 (avc_data);
if (size < 8 || size > len)
break;
switch (QT_FOURCC (avc_data + 4)) {
case FOURCC_avcC:
{
/* parse, if found */
GstBuffer *buf;
if (size < 8 + 1)
break;
GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
/* First 4 bytes are the length of the atom, the next 4 bytes
* are the fourcc, the next 1 byte is the version, and the
* subsequent bytes are profile_tier_level structure like data. */
gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
avc_data + 8 + 1, size - 8 - 1);
buf = gst_buffer_new_and_alloc (size - 8);
gst_buffer_fill (buf, 0, avc_data + 8, size - 8);
gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf);
break;
}
case FOURCC_strf:
{
GstBuffer *buf;
if (size < 8 + 40 + 1)
break;
GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
/* First 4 bytes are the length of the atom, the next 4 bytes
* are the fourcc, next 40 bytes are BITMAPINFOHEADER,
* next 1 byte is the version, and the
* subsequent bytes are sequence parameter set like data. */
gst_codec_utils_h264_caps_set_level_and_profile
(entry->caps, avc_data + 8 + 40 + 1, size - 8 - 40 - 1);
buf = gst_buffer_new_and_alloc (size - 8 - 40);
gst_buffer_fill (buf, 0, avc_data + 8 + 40, size - 8 - 40);
gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf);
break;
}
case FOURCC_btrt:
{
guint avg_bitrate, max_bitrate;
/* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */ /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
if (size < 8 + 12) if (size >= 8 + 12) {
break;
max_bitrate = QT_UINT32 (avc_data + 8 + 4); guint32 max_bitrate = QT_UINT32 (data + 8 + 4);
avg_bitrate = QT_UINT32 (avc_data + 8 + 8); guint32 avg_bitrate = QT_UINT32 (data + 8 + 8);
if (!max_bitrate && !avg_bitrate)
break;
/* Some muxers seem to swap the average and maximum bitrates /* Some muxers seem to swap the average and maximum bitrates
* (I'm looking at you, YouTube), so we swap for sanity. */ * (I'm looking at you, YouTube), so we swap for sanity. */
@ -15125,7 +15057,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
avg_bitrate = max_bitrate; avg_bitrate = max_bitrate;
max_bitrate = temp; max_bitrate = temp;
} }
if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) { if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
gst_tag_list_add (stream->stream_tags, gst_tag_list_add (stream->stream_tags,
GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE, GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
@ -15133,19 +15064,74 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) { if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
gst_tag_list_add (stream->stream_tags, gst_tag_list_add (stream->stream_tags,
GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate, NULL);
NULL); }
}
} }
break; if (esds) {
} gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
stream->stream_tags);
} else {
switch (fourcc) {
case FOURCC_H264:
case FOURCC_avc1:
case FOURCC_avc3:
{
GNode *avcC =
qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_avcC);
GNode *strf =
qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_strf);
default: if (avcC) {
break; const guint8 *data;
} guint32 size;
len -= size; data = avcC->data;
avc_data += size; size = QT_UINT32 (data);
if (size >= 8 + 1) {
GstBuffer *buf;
GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
/* First 4 bytes are the length of the atom, the next 4 bytes
* are the fourcc, the next 1 byte is the version, and the
* subsequent bytes are profile_tier_level structure like data. */
gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
data + 8 + 1, size - 8 - 1);
buf = gst_buffer_new_and_alloc (size - 8);
gst_buffer_fill (buf, 0, data + 8, size - 8);
gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf);
}
} else if (strf) {
const guint8 *data;
guint32 size;
data = strf->data;
size = QT_UINT32 (data);
if (size >= 8 + 40 + 1) {
GstBuffer *buf;
GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
/* First 4 bytes are the length of the atom, the next 4 bytes
* are the fourcc, next 40 bytes are BITMAPINFOHEADER,
* next 1 byte is the version, and the
* subsequent bytes are sequence parameter set like data. */
gst_codec_utils_h264_caps_set_level_and_profile
(entry->caps, data + 8 + 40 + 1, size - 8 - 40 - 1);
buf = gst_buffer_new_and_alloc (size - 8 - 40);
gst_buffer_fill (buf, 0, data + 8 + 40, size - 8 - 40);
gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf);
}
} }
break; break;
@ -15156,46 +15142,33 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_dvh1: case FOURCC_dvh1:
case FOURCC_dvhe: case FOURCC_dvhe:
{ {
guint32 len = QT_UINT32 (stsd_entry_data); GNode *hvcC =
len = len <= 0x56 ? 0 : len - 0x56; qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_hvcC);
const guint8 *hevc_data = stsd_entry_data + 0x56;
/* find hevc */ if (hvcC) {
while (len >= 8) { const guint8 *data;
guint32 size = QT_UINT32 (hevc_data); guint32 size;
if (size < 8 || size > len) data = hvcC->data;
break; size = QT_UINT32 (data);
switch (QT_FOURCC (hevc_data + 4)) { if (size >= 8 + 1) {
case FOURCC_hvcC:
{
/* parse, if found */
GstBuffer *buf; GstBuffer *buf;
if (size < 8 + 1)
break;
GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd"); GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
/* First 4 bytes are the length of the atom, the next 4 bytes /* First 4 bytes are the length of the atom, the next 4 bytes
* are the fourcc, the next 1 byte is the version, and the * are the fourcc, the next 1 byte is the version, and the
* subsequent bytes are sequence parameter set like data. */ * subsequent bytes are sequence parameter set like data. */
gst_codec_utils_h265_caps_set_level_tier_and_profile gst_codec_utils_h265_caps_set_level_tier_and_profile
(entry->caps, hevc_data + 8 + 1, size - 8 - 1); (entry->caps, data + 8 + 1, size - 8 - 1);
buf = gst_buffer_new_and_alloc (size - 8); buf = gst_buffer_new_and_alloc (size - 8);
gst_buffer_fill (buf, 0, hevc_data + 8, size - 8); gst_buffer_fill (buf, 0, data + 8, size - 8);
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL); "codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf); gst_buffer_unref (buf);
break;
} }
default:
break;
}
len -= size;
hevc_data += size;
} }
break; break;
} }
@ -15203,33 +15176,27 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_vvc1: case FOURCC_vvc1:
case FOURCC_vvi1: case FOURCC_vvi1:
{ {
guint len = QT_UINT32 (stsd_entry_data); GNode *vvcC =
len = len <= 0x56 ? 0 : len - 0x56; qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_vvcC);
const guint8 *vvc_data = stsd_entry_data + 0x56;
/* find vvcC, which is a FullBox. */ if (vvcC) {
while (len >= 12) { const guint8 *data;
guint size = QT_UINT32 (vvc_data); guint32 size;
if (size < 12 || size > len) data = vvcC->data;
break; size = QT_UINT32 (data);
switch (QT_FOURCC (vvc_data + 4)) {
case FOURCC_vvcC: if (size >= 12 + 1) {
{
/* parse, if found */
GstBuffer *buf; GstBuffer *buf;
guint8 version; guint8 version;
if (size < 12 + 1)
break;
GST_DEBUG_OBJECT (qtdemux, "found vvcC codec_data in stsd"); GST_DEBUG_OBJECT (qtdemux, "found vvcC codec_data in stsd");
/* First 4 bytes are the length of the atom, the next 4 bytes /* First 4 bytes are the length of the atom, the next 4 bytes
* are the fourcc, the next 1 byte is the version, the next 3 bytes are flags and the * are the fourcc, the next 1 byte is the version, the next 3 bytes are flags and the
* subsequent bytes are the decoder configuration record. */ * subsequent bytes are the decoder configuration record. */
version = vvc_data[8]; version = data[8];
if (version != 0) { if (version != 0) {
GST_ERROR_OBJECT (qtdemux, GST_ERROR_OBJECT (qtdemux,
"Unsupported vvcC version %u. Only version 0 is supported", "Unsupported vvcC version %u. Only version 0 is supported",
@ -15238,20 +15205,14 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
gst_codec_utils_h266_caps_set_level_tier_and_profile gst_codec_utils_h266_caps_set_level_tier_and_profile
(entry->caps, vvc_data + 12, size - 12); (entry->caps, data + 12, size - 12);
buf = gst_buffer_new_and_alloc (size - 12); buf = gst_buffer_new_and_alloc (size - 12);
gst_buffer_fill (buf, 0, vvc_data + 12, size - 12); gst_buffer_fill (buf, 0, data + 12, size - 12);
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL); "codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf); gst_buffer_unref (buf);
break;
} }
default:
break;
}
len -= size;
vvc_data += size;
} }
break; break;
} }
@ -15291,7 +15252,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_mjp2: case FOURCC_mjp2:
{ {
/* see annex I of the jpeg2000 spec */ /* see annex I of the jpeg2000 spec */
GNode *jp2h, *ihdr, *colr, *mjp2, *prefix, *cmap, *cdef; GNode *jp2h, *ihdr, *colr, *prefix, *cmap, *cdef;
const guint8 *data; const guint8 *data;
const gchar *colorspace = NULL; const gchar *colorspace = NULL;
gint ncomp = 0; gint ncomp = 0;
@ -15303,10 +15264,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
GST_DEBUG_OBJECT (qtdemux, "found mjp2"); GST_DEBUG_OBJECT (qtdemux, "found mjp2");
/* some required atoms */ /* some required atoms */
mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index); jp2h = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_jp2h);
if (!mjp2)
break;
jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
if (!jp2h) if (!jp2h)
break; break;
@ -15453,7 +15411,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
/* some optional atoms */ /* some optional atoms */
prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x); prefix = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_jp2x);
/* add codec_data if provided */ /* add codec_data if provided */
if (prefix) { if (prefix) {
@ -15519,8 +15477,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_WRLE: case FOURCC_WRLE:
{ {
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66), "depth", G_TYPE_INT, entry->bits_per_sample, NULL);
NULL);
break; break;
} }
case FOURCC_XiTh: case FOURCC_XiTh:
@ -15575,16 +15532,12 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
case FOURCC_ovc1: case FOURCC_ovc1:
{ {
GNode *ovc1;
guint8 *ovc1_data; guint8 *ovc1_data;
guint ovc1_len; guint ovc1_len;
GstBuffer *buf; GstBuffer *buf;
GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header"); GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index); ovc1_data = stsd_entry->data;
if (!ovc1)
break;
ovc1_data = ovc1->data;
ovc1_len = QT_UINT32 (ovc1_data); ovc1_len = QT_UINT32 (ovc1_data);
if (ovc1_len <= 198) { if (ovc1_len <= 198) {
GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping"); GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
@ -15599,55 +15552,37 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
case FOURCC_vc_1: case FOURCC_vc_1:
{ {
guint32 len = QT_UINT32 (stsd_entry_data); GNode *dvc1;
len = len <= 0x56 ? 0 : len - 0x56;
const guint8 *vc1_data = stsd_entry_data + 0x56;
/* find dvc1 */ dvc1 =
while (len >= 8) { qtdemux_tree_get_child_by_type (stsd_entry,
guint32 size = QT_UINT32 (vc1_data); GST_MAKE_FOURCC ('d', 'v', 'c', '1'));
if (dvc1) {
guint32 size = QT_UINT32 (dvc1->data);
if (size < 8 || size > len) if (size >= 8) {
break;
switch (QT_FOURCC (vc1_data + 4)) {
case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
{
GstBuffer *buf; GstBuffer *buf;
GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd"); GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
buf = gst_buffer_new_and_alloc (size - 8); buf = gst_buffer_new_and_alloc (size - 8);
gst_buffer_fill (buf, 0, vc1_data + 8, size - 8); gst_buffer_fill (buf, 0, (const guint8 *) dvc1->data + 8,
gst_caps_set_simple (entry->caps, size - 8);
"codec_data", GST_TYPE_BUFFER, buf, NULL); gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
buf, NULL);
gst_buffer_unref (buf); gst_buffer_unref (buf);
break;
} }
default:
break;
}
len -= size;
vc1_data += size;
} }
break; break;
} }
case FOURCC_av01: case FOURCC_av01:
{ {
guint32 len = QT_UINT32 (stsd_entry_data); GNode *av1C;
len = len <= 0x56 ? 0 : len - 0x56;
const guint8 *av1_data = stsd_entry_data + 0x56;
/* find av1C */ av1C = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_av1C);
while (len >= 8) { if (av1C) {
guint32 size = QT_UINT32 (av1_data); const guint8 *data = av1C->data;
guint32 size = QT_UINT32 (data);
if (size < 8 || size > len)
break;
switch (QT_FOURCC (av1_data + 4)) {
case FOURCC_av1C:
{
/* parse, if found */
GstBuffer *buf; GstBuffer *buf;
GST_DEBUG_OBJECT (qtdemux, GST_DEBUG_OBJECT (qtdemux,
@ -15688,7 +15623,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
* rest: OBUs. * rest: OBUs.
*/ */
switch (av1_data[8]) { switch (data[8]) {
case 0x81:{ case 0x81:{
guint8 pres_delay_field; guint8 pres_delay_field;
@ -15696,7 +15631,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
* av1parse and only include the presentation delay here * av1parse and only include the presentation delay here
* if present */ * if present */
/* We skip initial_presentation_delay* for now */ /* We skip initial_presentation_delay* for now */
pres_delay_field = *(av1_data + 11); pres_delay_field = *(data + 11);
if (pres_delay_field & (1 << 5)) { if (pres_delay_field & (1 << 5)) {
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"presentation-delay", G_TYPE_INT, "presentation-delay", G_TYPE_INT,
@ -15705,50 +15640,30 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
buf = gst_buffer_new_and_alloc (size - 8); buf = gst_buffer_new_and_alloc (size - 8);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
gst_buffer_fill (buf, 0, av1_data + 8, size - 8); gst_buffer_fill (buf, 0, data + 8, size - 8);
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL); "codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf); gst_buffer_unref (buf);
break; break;
} }
default: default:
GST_WARNING ("Unknown version 0x%02x of av1C box", GST_WARNING ("Unknown version 0x%02x of av1C box", data[8]);
av1_data[8]);
break; break;
} }
break;
}
default:
break;
}
len -= size;
av1_data += size;
} }
break; break;
} }
/* TODO: Need to parse vpcC for VP8 codec too. case FOURCC_vp08:
* Note that VPCodecConfigurationBox (vpcC) is defined for
* vp08, vp09, and vp10 fourcc. */
case FOURCC_vp09: case FOURCC_vp09:
{ {
guint32 len = QT_UINT32 (stsd_entry_data); GNode *vpcC;
len = len <= 0x56 ? 0 : len - 0x56;
const guint8 *vpcc_data = stsd_entry_data + 0x56;
/* find vpcC */ vpcC = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_vpcC);
while (len >= 8) { if (vpcC) {
guint32 size = QT_UINT32 (vpcc_data); const guint8 *data = vpcC->data;
guint32 size = QT_UINT32 (data);
if (size < 8 || size > len)
break;
switch (QT_FOURCC (vpcc_data + 4)) {
case FOURCC_vpcC:
{
const gchar *profile_str = NULL; const gchar *profile_str = NULL;
const gchar *chroma_format_str = NULL; const gchar *chroma_format_str = NULL;
guint8 profile; guint8 profile;
@ -15782,13 +15697,13 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
* rest: codecIntializationData (not used for vp8 and vp9) * rest: codecIntializationData (not used for vp8 and vp9)
*/ */
if (vpcc_data[8] != 1) { if (data[8] != 1) {
GST_WARNING_OBJECT (qtdemux, GST_WARNING_OBJECT (qtdemux,
"unknown vpcC version %d", vpcc_data[8]); "unknown vpcC version %d", data[8]);
break; break;
} }
profile = vpcc_data[12]; profile = data[12];
switch (profile) { switch (profile) {
case 0: case 0:
profile_str = "0"; profile_str = "0";
@ -15815,14 +15730,14 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
* but webm spec define various ones. Add level to caps * but webm spec define various ones. Add level to caps
* if we really need it then */ * if we really need it then */
bitdepth = (vpcc_data[14] & 0xf0) >> 4; bitdepth = (data[14] & 0xf0) >> 4;
if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) { if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"bit-depth-luma", G_TYPE_UINT, bitdepth, "bit-depth-luma", G_TYPE_UINT, bitdepth,
"bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL); "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
} }
chroma_format = (vpcc_data[14] & 0xe) >> 1; chroma_format = (data[14] & 0xe) >> 1;
switch (chroma_format) { switch (chroma_format) {
case 0: case 0:
case 1: case 1:
@ -15840,20 +15755,16 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
if (chroma_format_str) { if (chroma_format_str) {
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"chroma-format", G_TYPE_STRING, chroma_format_str, "chroma-format", G_TYPE_STRING, chroma_format_str, NULL);
NULL);
} }
if ((vpcc_data[14] & 0x1) != 0) if ((data[14] & 0x1) != 0)
cinfo.range = GST_VIDEO_COLOR_RANGE_0_255; cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
else else
cinfo.range = GST_VIDEO_COLOR_RANGE_16_235; cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
cinfo.primaries = cinfo.primaries = gst_video_color_primaries_from_iso (data[15]);
gst_video_color_primaries_from_iso (vpcc_data[15]); cinfo.transfer = gst_video_transfer_function_from_iso (data[16]);
cinfo.transfer = cinfo.matrix = gst_video_color_matrix_from_iso (data[17]);
gst_video_transfer_function_from_iso (vpcc_data[16]);
cinfo.matrix =
gst_video_color_matrix_from_iso (vpcc_data[17]);
if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN && if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN && cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
@ -15862,20 +15773,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
* might overwrite valid ones parsed from other color box */ * might overwrite valid ones parsed from other color box */
CUR_STREAM (stream)->colorimetry = cinfo; CUR_STREAM (stream)->colorimetry = cinfo;
} }
}
break; break;
} }
default:
break;
}
len -= size;
vpcc_data += size;
}
break;
}
default:
break;
} }
} }
@ -15884,7 +15784,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
GST_FOURCC_ARGS (fourcc), entry->caps); GST_FOURCC_ARGS (fourcc), entry->caps);
} else if (stream->subtype == FOURCC_soun) { } else if (stream->subtype == FOURCC_soun) {
GNode *wave; GNode *wave, *btrt;
guint version, samplesize; guint version, samplesize;
guint16 compression_id; guint16 compression_id;
gboolean amrwb = FALSE; gboolean amrwb = FALSE;
@ -16120,19 +16020,19 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_fl64: case FOURCC_fl64:
{ {
GNode *enda; GNode *enda;
GNode *fmt;
fmt = qtdemux_tree_get_child_by_type (stsd, fourcc); enda = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_enda);
enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
if (!enda) { if (!enda) {
wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave); wave = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_wave);
if (wave) if (wave)
enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda); enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
} }
if (enda) { if (enda) {
int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
const gchar *format_str; const gchar *format_str;
guint32 enda_len = QT_UINT32 (enda->data);
if (enda_len >= 9) {
guint16 enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
switch (fourcc) { switch (fourcc) {
case FOURCC_in24: case FOURCC_in24:
@ -16154,6 +16054,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"format", G_TYPE_STRING, format_str, NULL); "format", G_TYPE_STRING, format_str, NULL);
} }
}
break; break;
} }
case FOURCC_owma: case FOURCC_owma:
@ -16225,9 +16126,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
case FOURCC_wma_: case FOURCC_wma_:
{ {
guint32 len = QT_UINT32 (stsd_entry_data);
len = len <= offset ? 0 : len - offset;
const guint8 *wfex_data = stsd_entry_data + offset;
const gchar *codec_name = NULL; const gchar *codec_name = NULL;
gint version = 1; gint version = 1;
/* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */ /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
@ -16244,23 +16142,22 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
gint16 cbSize; gint16 cbSize;
} WAVEFORMATEX; } WAVEFORMATEX;
WAVEFORMATEX wfex; WAVEFORMATEX wfex;
GNode *wfex_node;
/* FIXME: unify with similar wavformatex parsing code above */ /* FIXME: unify with similar wavformatex parsing code above */
GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex"); GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
/* find wfex */ wfex_node =
while (len >= 8) { qtdemux_tree_get_child_by_type (stsd_entry, GST_MAKE_FOURCC ('w',
guint32 size = QT_UINT32 (wfex_data); 'f', 'e', 'x'));
if (size < 8 || size > len) if (wfex_node) {
break; const guint8 *wfex_data = wfex_node->data;
guint32 wfex_size = QT_UINT32 (wfex_data);
switch (QT_FOURCC (wfex_data + 4)) {
case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
{
GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd"); GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
if (size < 8 + 18) if (wfex_size < 8 + 18)
break; break;
wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0); wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
@ -16298,12 +16195,12 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
"width", G_TYPE_INT, wfex.wBitsPerSample, "width", G_TYPE_INT, wfex.wBitsPerSample,
"depth", G_TYPE_INT, wfex.wBitsPerSample, NULL); "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
if (size > 8 + wfex.cbSize) { if (wfex_size > 8 + wfex.cbSize) {
GstBuffer *buf; GstBuffer *buf;
buf = gst_buffer_new_and_alloc (size - 8 - wfex.cbSize); buf = gst_buffer_new_and_alloc (wfex_size - 8 - wfex.cbSize);
gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize, gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
size - 8 - wfex.cbSize); wfex_size - 8 - wfex.cbSize);
gst_caps_set_simple (entry->caps, gst_caps_set_simple (entry->caps,
"codec_data", GST_TYPE_BUFFER, buf, NULL); "codec_data", GST_TYPE_BUFFER, buf, NULL);
gst_buffer_unref (buf); gst_buffer_unref (buf);
@ -16317,12 +16214,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
break; break;
} }
default:
break;
}
len -= size;
wfex_data += size;
}
break; break;
} }
case FOURCC_opus: case FOURCC_opus:
@ -16335,16 +16226,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
guint8 coupled_count; guint8 coupled_count;
guint8 i; guint8 i;
GNode *opus;
GNode *dops; GNode *dops;
opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus); dops = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_dops);
if (opus == NULL) {
GST_WARNING_OBJECT (qtdemux, "Opus Sample Entry not found");
goto corrupt_file;
}
dops = qtdemux_tree_get_child_by_type (opus, FOURCC_dops);
if (dops == NULL) { if (dops == NULL) {
GST_WARNING_OBJECT (qtdemux, "Opus Specific Box not found"); GST_WARNING_OBJECT (qtdemux, "Opus Specific Box not found");
goto corrupt_file; goto corrupt_file;
@ -16428,12 +16312,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_ipcm: case FOURCC_ipcm:
case FOURCC_fpcm: case FOURCC_fpcm:
{ {
GNode *fmt;
GNode *pcmC; GNode *pcmC;
fmt = qtdemux_tree_get_child_by_type (stsd, fourcc); pcmC = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_pcmC);
pcmC = qtdemux_tree_get_child_by_type (fmt, FOURCC_pcmC);
if (pcmC) { if (pcmC) {
const guint8 *data = pcmC->data; const guint8 *data = pcmC->data;
gsize len = QT_UINT32 (data); gsize len = QT_UINT32 (data);
@ -16530,29 +16411,46 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
esds = NULL; esds = NULL;
mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index); wave = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_wave);
if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
if (stream->protected) {
if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
}
if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
mp4a = NULL;
}
} else {
mp4a = NULL;
}
}
wave = NULL;
if (mp4a) {
wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
if (wave) if (wave)
esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds); esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
if (!esds) if (!esds)
esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds); esds = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_esds);
}
btrt = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_btrt);
if (btrt) {
const guint8 *data;
guint32 size;
data = btrt->data;
size = QT_UINT32 (data);
/* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
if (size >= 8 + 12) {
guint32 max_bitrate = QT_UINT32 (data + 8 + 4);
guint32 avg_bitrate = QT_UINT32 (data + 8 + 8);
/* Some muxers seem to swap the average and maximum bitrates
* (I'm looking at you, YouTube), so we swap for sanity. */
if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
guint temp = avg_bitrate;
avg_bitrate = max_bitrate;
max_bitrate = temp;
}
if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
gst_tag_list_add (stream->stream_tags,
GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
max_bitrate, NULL);
}
if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
gst_tag_list_add (stream->stream_tags,
GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate, NULL);
}
}
}
/* If the fourcc's bottom 16 bits gives 'sm', then the top /* If the fourcc's bottom 16 bits gives 'sm', then the top
16 bits is a byte-swapped wave-style codec identifier, 16 bits is a byte-swapped wave-style codec identifier,
@ -16643,19 +16541,15 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
} }
case FOURCC_alac: case FOURCC_alac:
{ {
GNode *alac, *wave = NULL; GNode *alac;
/* apparently, m4a has this atom appended directly in the stsd entry, /* apparently, m4a has this atom appended directly in the stsd entry,
* while mov has it in a wave atom */ * while mov has it in a wave atom */
alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
if (alac) {
/* alac now refers to stsd entry atom */ /* alac now refers to stsd entry atom */
wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
if (wave) if (wave)
alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac); alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
else else
alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac); alac = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_alac);
}
if (alac) { if (alac) {
const guint8 *alac_data = alac->data; const guint8 *alac_data = alac->data;
gint len = QT_UINT32 (alac->data); gint len = QT_UINT32 (alac->data);
@ -16686,13 +16580,10 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_fLaC: case FOURCC_fLaC:
{ {
/* The codingname of the sample entry is 'fLaC' */ /* The codingname of the sample entry is 'fLaC' */
GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
if (flac) {
/* The 'dfLa' box is added to the sample entry to convey /* The 'dfLa' box is added to the sample entry to convey
initializing information for the decoder. */ initializing information for the decoder. */
const GNode *dfla = const GNode *dfla =
qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa); qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_dfLa);
if (dfla) { if (dfla) {
const guint32 len = QT_UINT32 (dfla->data); const guint32 len = QT_UINT32 (dfla->data);
@ -16782,7 +16673,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
(QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF; (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
} }
} }
}
break; break;
} }
case FOURCC_sawb: case FOURCC_sawb:
@ -16859,12 +16749,11 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
case FOURCC_fl32: case FOURCC_fl32:
case FOURCC_fl64: case FOURCC_fl64:
case FOURCC_s16l:{ case FOURCC_s16l:{
GNode *fmt, *chnl, *chan; GNode *chnl, *chan;
// Parse channel layout information for raw PCM // Parse channel layout information for raw PCM
fmt = qtdemux_tree_get_child_by_type (stsd, fourcc); chnl = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_chnl);
chnl = qtdemux_tree_get_child_by_type (fmt, FOURCC_chnl); chan = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_chan);
chan = qtdemux_tree_get_child_by_type (fmt, FOURCC_chan);
if (chnl) { if (chnl) {
const guint8 *data = chnl->data; const guint8 *data = chnl->data;
@ -16939,13 +16828,10 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak, guint32 * mvhd_matrix)
switch (fourcc) { switch (fourcc) {
case FOURCC_mp4s: case FOURCC_mp4s:
{ {
GNode *mp4s = NULL;
GNode *esds = NULL; GNode *esds = NULL;
/* look for palette in a stsd->mp4s->esds sub-atom */ /* look for palette in a stsd->mp4s->esds sub-atom */
mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s); esds = qtdemux_tree_get_child_by_type (stsd_entry, FOURCC_esds);
if (mp4s)
esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
if (esds == NULL) { if (esds == NULL) {
/* Invalid STSD */ /* Invalid STSD */
GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child"); GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");