mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 22:36:33 +00:00
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.
This commit is contained in:
parent
6f8ce30c20
commit
d2948bb259
1 changed files with 44 additions and 17 deletions
|
@ -1983,7 +1983,7 @@ static gboolean
|
||||||
qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
|
qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
|
||||||
QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
|
QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
|
||||||
guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
|
guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
|
||||||
gint64 * base_offset)
|
gint64 * base_offset, gint64 * running_offset)
|
||||||
{
|
{
|
||||||
guint64 timestamp;
|
guint64 timestamp;
|
||||||
gint32 data_offset = 0;
|
gint32 data_offset = 0;
|
||||||
|
@ -2016,7 +2016,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
|
||||||
GST_LOG_OBJECT (qtdemux, "base_offset at moof");
|
GST_LOG_OBJECT (qtdemux, "base_offset at moof");
|
||||||
*base_offset = moof_offset;
|
*base_offset = moof_offset;
|
||||||
}
|
}
|
||||||
*base_offset += data_offset;
|
*running_offset = *base_offset + data_offset;
|
||||||
} else {
|
} else {
|
||||||
/* if no offset at all, that would mean data starts at moof start,
|
/* 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
|
* 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");
|
GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
|
||||||
ismv = TRUE;
|
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",
|
GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
|
||||||
data_offset, flags, samples_count);
|
data_offset, flags, samples_count);
|
||||||
|
|
||||||
|
@ -2135,7 +2137,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
|
||||||
data += entry_size;
|
data += entry_size;
|
||||||
|
|
||||||
/* fill the sample information */
|
/* fill the sample information */
|
||||||
sample->offset = *base_offset;
|
sample->offset = *running_offset;
|
||||||
sample->pts_offset = ct;
|
sample->pts_offset = ct;
|
||||||
sample->size = size;
|
sample->size = size;
|
||||||
sample->timestamp = timestamp;
|
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,
|
/* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
|
||||||
* now idea how it relates to bitfield other than massive LE/BE confusion */
|
* now idea how it relates to bitfield other than massive LE/BE confusion */
|
||||||
sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
|
sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
|
||||||
*base_offset += size;
|
*running_offset += size;
|
||||||
timestamp += dur;
|
timestamp += dur;
|
||||||
sample++;
|
sample++;
|
||||||
}
|
}
|
||||||
|
@ -2220,10 +2222,8 @@ qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
|
||||||
goto invalid_track;
|
goto invalid_track;
|
||||||
|
|
||||||
*stream = qtdemux_find_stream (qtdemux, track_id);
|
*stream = qtdemux_find_stream (qtdemux, track_id);
|
||||||
if (G_UNLIKELY (!*stream)) {
|
if (G_UNLIKELY (!*stream))
|
||||||
GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
|
goto unknown_stream;
|
||||||
goto invalid_track;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & TF_BASE_DATA_OFFSET)
|
if (flags & TF_BASE_DATA_OFFSET)
|
||||||
if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_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:
|
invalid_track:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (qtdemux, "invalid track header");
|
GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
unknown_stream:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
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;
|
GNode *moof_node, *traf_node, *tfhd_node, *trun_node;
|
||||||
GstByteReader trun_data, tfhd_data;
|
GstByteReader trun_data, tfhd_data;
|
||||||
guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
|
guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
|
||||||
gint64 base_offset;
|
gint64 base_offset, running_offset;
|
||||||
|
|
||||||
/* NOTE @stream ignored */
|
/* NOTE @stream ignored */
|
||||||
|
|
||||||
|
@ -2275,7 +2280,7 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
|
||||||
qtdemux_node_dump (qtdemux, moof_node);
|
qtdemux_node_dump (qtdemux, moof_node);
|
||||||
|
|
||||||
/* unknown base_offset to start with */
|
/* 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);
|
traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
|
||||||
while (traf_node) {
|
while (traf_node) {
|
||||||
/* Fragment Header 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,
|
if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
|
||||||
&ds_size, &ds_flags, &base_offset))
|
&ds_size, &ds_flags, &base_offset))
|
||||||
goto missing_tfhd;
|
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 */
|
/* Track Run node */
|
||||||
trun_node =
|
trun_node =
|
||||||
qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
|
qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
|
||||||
&trun_data);
|
&trun_data);
|
||||||
while (trun_node) {
|
while (trun_node) {
|
||||||
qtdemux_parse_trun (qtdemux, &trun_data, stream,
|
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 */
|
/* iterate all siblings */
|
||||||
trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
|
trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
|
||||||
&trun_data);
|
&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 */
|
/* iterate all siblings */
|
||||||
traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
|
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;
|
return TRUE;
|
||||||
|
|
||||||
missing_tfhd:
|
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);
|
g_node_destroy (moof_node);
|
||||||
GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
|
GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
|
||||||
(_("This file is corrupt and cannot be played.")),
|
(_("This file is corrupt and cannot be played.")), (NULL));
|
||||||
("missing tfhd box"));
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue