From d2948bb259ac070dbbb8ca1e1b0341e39ce1d87a Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 7 Dec 2010 17:19:00 +0100 Subject: [PATCH] qtdemux: fragmented support; fix offset handling and relax error raising In particular, accept unknown stream in track fragment, and only error out if that raises problems later on with respect to offset tracking. Fixes #620283. --- gst/qtdemux/qtdemux.c | 61 +++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 3d5498e80b..b174ac7636 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -1983,7 +1983,7 @@ static gboolean qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size, guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length, - gint64 * base_offset) + gint64 * base_offset, gint64 * running_offset) { guint64 timestamp; gint32 data_offset = 0; @@ -2016,7 +2016,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, GST_LOG_OBJECT (qtdemux, "base_offset at moof"); *base_offset = moof_offset; } - *base_offset += data_offset; + *running_offset = *base_offset + data_offset; } else { /* if no offset at all, that would mean data starts at moof start, * which is a bit wrong and is ismv crappy way, so compensate @@ -2026,10 +2026,12 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof"); ismv = TRUE; } + if (*running_offset == -1) + *running_offset = *base_offset; } - GST_LOG_OBJECT (qtdemux, "base offset now %" G_GINT64_FORMAT, *base_offset); - + GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT, + *running_offset); GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d", data_offset, flags, samples_count); @@ -2135,7 +2137,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, data += entry_size; /* fill the sample information */ - sample->offset = *base_offset; + sample->offset = *running_offset; sample->pts_offset = ct; sample->size = size; sample->timestamp = timestamp; @@ -2144,7 +2146,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe, * now idea how it relates to bitfield other than massive LE/BE confusion */ sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000); - *base_offset += size; + *running_offset += size; timestamp += dur; sample++; } @@ -2220,10 +2222,8 @@ qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd, goto invalid_track; *stream = qtdemux_find_stream (qtdemux, track_id); - if (G_UNLIKELY (!*stream)) { - GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd"); - goto invalid_track; - } + if (G_UNLIKELY (!*stream)) + goto unknown_stream; if (flags & TF_BASE_DATA_OFFSET) if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset)) @@ -2254,9 +2254,14 @@ qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd, invalid_track: { - GST_WARNING_OBJECT (qtdemux, "invalid track header"); + GST_WARNING_OBJECT (qtdemux, "invalid track fragment header"); return FALSE; } +unknown_stream: + { + GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd"); + return TRUE; + } } static gboolean @@ -2266,7 +2271,7 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, GNode *moof_node, *traf_node, *tfhd_node, *trun_node; GstByteReader trun_data, tfhd_data; guint32 ds_size = 0, ds_duration = 0, ds_flags = 0; - gint64 base_offset; + gint64 base_offset, running_offset; /* NOTE @stream ignored */ @@ -2275,7 +2280,7 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, qtdemux_node_dump (qtdemux, moof_node); /* unknown base_offset to start with */ - base_offset = -1; + base_offset = running_offset = -1; traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf); while (traf_node) { /* Fragment Header node */ @@ -2287,18 +2292,31 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration, &ds_size, &ds_flags, &base_offset)) goto missing_tfhd; + if (G_UNLIKELY (!stream)) { + /* we lost track of offset, we'll need to regain it, + * but can delay complaining until later or avoid doing so altogether */ + base_offset = -2; + goto next; + } + if (G_UNLIKELY (base_offset < -1)) + goto lost_offset; /* Track Run node */ trun_node = qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun, &trun_data); while (trun_node) { qtdemux_parse_trun (qtdemux, &trun_data, stream, - ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset); + ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset, + &running_offset); /* iterate all siblings */ trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun, &trun_data); } - + /* if no new base_offset provided for next traf, + * base is end of current traf */ + base_offset = running_offset; + running_offset = -1; + next: /* iterate all siblings */ traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf); } @@ -2306,11 +2324,20 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, return TRUE; missing_tfhd: + { + GST_DEBUG_OBJECT (qtdemux, "missing tfhd box"); + goto fail; + } +lost_offset: + { + GST_DEBUG_OBJECT (qtdemux, "lost offset"); + goto fail; + } +fail: { g_node_destroy (moof_node); GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, - (_("This file is corrupt and cannot be played.")), - ("missing tfhd box")); + (_("This file is corrupt and cannot be played.")), (NULL)); return FALSE; } }