mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-08 21:28:45 +00:00
qtdemux: fragmented support; code cleanups and optimizations in atom parsing
Avoid extra allocation in _parse_trun, add more checks for parsing errors, add or adjust some debug statement, fix comments, sprinkle some branch prediction.
This commit is contained in:
parent
4f62f49a17
commit
30065f8f01
2 changed files with 151 additions and 121 deletions
|
@ -348,6 +348,8 @@ static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
|
||||||
static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
|
static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
|
||||||
guint32 fourcc, GstByteReader * parser);
|
guint32 fourcc, GstByteReader * parser);
|
||||||
static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
|
static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
|
||||||
|
static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
|
||||||
|
guint32 fourcc, GstByteReader * parser);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_qtdemux_sink_template =
|
static GstStaticPadTemplate gst_qtdemux_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
@ -513,7 +515,7 @@ gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
|
||||||
{
|
{
|
||||||
GstFlowReturn flow;
|
GstFlowReturn flow;
|
||||||
|
|
||||||
if (size == 0) {
|
if (G_UNLIKELY (size == 0)) {
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
GstBuffer *tmp = NULL;
|
GstBuffer *tmp = NULL;
|
||||||
|
|
||||||
|
@ -522,7 +524,7 @@ gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
size = QT_UINT32 (GST_BUFFER_DATA (tmp));
|
size = QT_UINT32 (GST_BUFFER_DATA (tmp));
|
||||||
GST_DEBUG ("size 0x%08" G_GINT64_MODIFIER "x", size);
|
GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
|
||||||
|
|
||||||
gst_buffer_unref (tmp);
|
gst_buffer_unref (tmp);
|
||||||
}
|
}
|
||||||
|
@ -1859,49 +1861,50 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
|
||||||
{
|
{
|
||||||
guint64 timestamp;
|
guint64 timestamp;
|
||||||
guint32 flags, data_offset;
|
guint32 flags, data_offset;
|
||||||
guint32 *samples_size, *samples_duration;
|
|
||||||
gint i;
|
gint i;
|
||||||
|
guint8 *data;
|
||||||
|
guint entry_size, dur_offset, size_offset;
|
||||||
|
QtDemuxSample *sample;
|
||||||
|
|
||||||
if (!gst_byte_reader_skip (trun, 1) ||
|
if (!gst_byte_reader_skip (trun, 1) ||
|
||||||
!gst_byte_reader_get_uint24_be (trun, &flags))
|
!gst_byte_reader_get_uint24_be (trun, &flags))
|
||||||
return FALSE;
|
goto fail;
|
||||||
|
|
||||||
|
if (!gst_byte_reader_get_uint32_be (trun, samples_count))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (!gst_byte_reader_get_uint32_be (trun, &(*samples_count)))
|
|
||||||
return FALSE;
|
|
||||||
else {
|
|
||||||
samples_size = (guint32 *) malloc (*samples_count * sizeof (guint32));
|
|
||||||
samples_duration = (guint32 *) malloc (*samples_count * sizeof (guint32));
|
|
||||||
}
|
|
||||||
/*FIXME: handle this flag properly */
|
/*FIXME: handle this flag properly */
|
||||||
if (flags & TR_DATA_OFFSET) {
|
if (flags & TR_DATA_OFFSET) {
|
||||||
if (!gst_byte_reader_get_uint32_be (trun, &data_offset))
|
if (!gst_byte_reader_get_uint32_be (trun, &data_offset))
|
||||||
return FALSE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & TR_FIRST_SAMPLE_FLAGS)
|
if (flags & TR_FIRST_SAMPLE_FLAGS)
|
||||||
gst_byte_reader_skip (trun, 4);
|
if (!gst_byte_reader_skip (trun, 4))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
for (i = 0; i < *samples_count; i++) {
|
/* FIXME ? spec says other bits should also be checked to determine
|
||||||
/* get the sample duration if present or use the default one */
|
* entry size (and prefix size for that matter) */
|
||||||
|
entry_size = 0;
|
||||||
|
dur_offset = size_offset = 0;
|
||||||
if (flags & TR_SAMPLE_DURATION) {
|
if (flags & TR_SAMPLE_DURATION) {
|
||||||
if (!gst_byte_reader_get_uint32_be (trun, &(samples_duration[i])))
|
dur_offset = entry_size;
|
||||||
return FALSE;
|
entry_size += 4;
|
||||||
} else
|
|
||||||
samples_duration[i] = d_sample_duration;
|
|
||||||
|
|
||||||
if (flags & TR_SAMPLE_SIZE) {
|
|
||||||
if (!gst_byte_reader_get_uint32_be (trun, &(samples_size[i])))
|
|
||||||
return FALSE;
|
|
||||||
} else
|
|
||||||
samples_size[i] = d_sample_size;
|
|
||||||
|
|
||||||
/* FIXME: Handle these flags properly */
|
|
||||||
if (flags & TR_SAMPLE_FLAGS)
|
|
||||||
gst_byte_reader_skip (trun, 4);
|
|
||||||
|
|
||||||
if (flags & TR_COMPOSITION_TIME_OFFSETS)
|
|
||||||
gst_byte_reader_skip (trun, 4);
|
|
||||||
}
|
}
|
||||||
|
if (flags & TR_SAMPLE_SIZE) {
|
||||||
|
size_offset = entry_size;
|
||||||
|
entry_size += 4;
|
||||||
|
}
|
||||||
|
if (flags & TR_SAMPLE_FLAGS) {
|
||||||
|
entry_size += 4;
|
||||||
|
}
|
||||||
|
if (flags & TR_COMPOSITION_TIME_OFFSETS) {
|
||||||
|
entry_size += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qt_atom_parser_has_chunks (trun, *samples_count, entry_size))
|
||||||
|
goto fail;
|
||||||
|
data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
|
||||||
|
|
||||||
data_offset = mdat_offset + 8;
|
data_offset = mdat_offset + 8;
|
||||||
|
|
||||||
|
@ -1922,53 +1925,65 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
|
||||||
if (stream->samples == NULL)
|
if (stream->samples == NULL)
|
||||||
goto out_of_memory;
|
goto out_of_memory;
|
||||||
|
|
||||||
for (i = 0; i < *samples_count; i++) {
|
|
||||||
if (G_UNLIKELY (stream->n_samples == 0)) {
|
if (G_UNLIKELY (stream->n_samples == 0)) {
|
||||||
/* the timestamp of the first sample is also provided by the tfra entry
|
/* the timestamp of the first sample is also provided by the tfra entry
|
||||||
* but we shouldn't rely on it as it is at the end of files */
|
* but we shouldn't rely on it as it is at the end of files */
|
||||||
timestamp = 0;
|
timestamp = 0;
|
||||||
} else {
|
} else {
|
||||||
/* a track run documents a contiguous set of samples */
|
/* subsequent fragments extend stream */
|
||||||
timestamp =
|
timestamp =
|
||||||
stream->samples[i + stream->n_samples - 1].timestamp +
|
stream->samples[stream->n_samples - 1].timestamp +
|
||||||
stream->samples[i + stream->n_samples - 1].duration;
|
stream->samples[stream->n_samples - 1].duration;
|
||||||
}
|
}
|
||||||
/* fill the sample information */
|
sample = stream->samples + stream->n_samples;
|
||||||
stream->samples[i + stream->n_samples].offset = data_offset;
|
for (i = 0; i < *samples_count; i++) {
|
||||||
stream->samples[i + stream->n_samples].pts_offset = 0;
|
guint32 dur, size;
|
||||||
stream->samples[i + stream->n_samples].size = samples_size[i];
|
|
||||||
stream->samples[i + stream->n_samples].timestamp = timestamp;
|
|
||||||
stream->samples[i + stream->n_samples].duration = samples_duration[i];
|
|
||||||
stream->samples[i + stream->n_samples].keyframe = (i == 0);
|
|
||||||
data_offset += samples_size[i];
|
|
||||||
|
|
||||||
/* Get the duration of the first frame used later to get the media fps */
|
/* first read sample data */
|
||||||
if (G_UNLIKELY (stream->min_duration == 0)) {
|
if (flags & TR_SAMPLE_DURATION) {
|
||||||
stream->min_duration = samples_duration[i];
|
dur = QT_UINT32 (data + dur_offset);
|
||||||
|
} else {
|
||||||
|
dur = d_sample_duration;
|
||||||
}
|
}
|
||||||
|
if (flags & TR_SAMPLE_SIZE) {
|
||||||
|
size = QT_UINT32 (data + size_offset);
|
||||||
|
} else {
|
||||||
|
size = d_sample_size;
|
||||||
|
}
|
||||||
|
data += entry_size;
|
||||||
|
|
||||||
|
/* fill the sample information */
|
||||||
|
sample->offset = data_offset;
|
||||||
|
sample->pts_offset = 0;
|
||||||
|
sample->size = size;
|
||||||
|
sample->timestamp = timestamp;
|
||||||
|
sample->duration = dur;
|
||||||
|
sample->keyframe = (i == 0);
|
||||||
|
data_offset += size;
|
||||||
|
timestamp += dur;
|
||||||
|
sample++;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->n_samples += *samples_count;
|
stream->n_samples += *samples_count;
|
||||||
free (samples_size);
|
|
||||||
free (samples_duration);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
out_of_memory:
|
out_of_memory:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
|
GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
|
||||||
stream->n_samples);
|
stream->n_samples);
|
||||||
free (samples_size);
|
|
||||||
free (samples_duration);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
index_too_big:
|
index_too_big:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
|
GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
|
||||||
"be larger than %uMB (broken file?)", stream->n_samples,
|
"be larger than %uMB (broken file?)", stream->n_samples,
|
||||||
QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
|
QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
|
||||||
free (samples_size);
|
|
||||||
free (samples_duration);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1984,35 +1999,39 @@ qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
|
||||||
!gst_byte_reader_get_uint24_be (tfhd, &flags))
|
!gst_byte_reader_get_uint24_be (tfhd, &flags))
|
||||||
goto invalid_track;
|
goto invalid_track;
|
||||||
|
|
||||||
if (!gst_byte_reader_get_uint32_be (tfhd, &(*track_id)))
|
if (!gst_byte_reader_get_uint32_be (tfhd, track_id))
|
||||||
goto invalid_track;
|
goto invalid_track;
|
||||||
|
|
||||||
/* FIXME: Handle TF_BASE_DATA_OFFSET properly */
|
/* FIXME: Handle TF_BASE_DATA_OFFSET properly */
|
||||||
if (flags & TF_BASE_DATA_OFFSET)
|
if (flags & TF_BASE_DATA_OFFSET)
|
||||||
gst_byte_reader_skip (tfhd, 4);
|
if (!gst_byte_reader_skip (tfhd, 4))
|
||||||
|
goto invalid_track;
|
||||||
|
|
||||||
/* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
|
/* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
|
||||||
if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
|
if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
|
||||||
gst_byte_reader_skip (tfhd, 4);
|
if (!gst_byte_reader_skip (tfhd, 4))
|
||||||
|
goto invalid_track;
|
||||||
|
|
||||||
if (flags & TF_DEFAULT_SAMPLE_DURATION)
|
if (flags & TF_DEFAULT_SAMPLE_DURATION)
|
||||||
gst_byte_reader_get_uint32_be (tfhd, &(*default_sample_duration));
|
if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
|
||||||
|
goto invalid_track;
|
||||||
|
|
||||||
if (flags & TF_DEFAULT_SAMPLE_SIZE)
|
if (flags & TF_DEFAULT_SAMPLE_SIZE)
|
||||||
gst_byte_reader_get_uint32_be (tfhd, &(*default_sample_size));
|
if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
|
||||||
|
goto invalid_track;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
invalid_track:
|
invalid_track:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (qtdemux, "invalid track header, skipping", *track_id);
|
GST_WARNING_OBJECT (qtdemux, "invalid track header");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
|
qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
|
||||||
guint32 moof_offset, QtDemuxStream * stream)
|
guint64 moof_offset, QtDemuxStream * stream)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
@ -2034,8 +2053,9 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
|
||||||
&tfhd_data);
|
&tfhd_data);
|
||||||
if (!tfhd_node)
|
if (!tfhd_node)
|
||||||
goto missing_tfhd;
|
goto missing_tfhd;
|
||||||
qtdemux_parse_tfhd (qtdemux, &tfhd_data, &id, &default_sample_duration,
|
if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &id, &default_sample_duration,
|
||||||
&default_sample_size);
|
&default_sample_size))
|
||||||
|
goto missing_tfhd;
|
||||||
/* skip trun atoms that don't match the track ID */
|
/* skip trun atoms that don't match the track ID */
|
||||||
if (id != stream->track_id)
|
if (id != stream->track_id)
|
||||||
goto next;
|
goto next;
|
||||||
|
@ -2047,7 +2067,8 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
|
||||||
qtdemux_parse_trun (qtdemux, &trun_data, stream, mdat_offset,
|
qtdemux_parse_trun (qtdemux, &trun_data, stream, mdat_offset,
|
||||||
default_sample_duration, default_sample_size, &samples_count);
|
default_sample_duration, default_sample_size, &samples_count);
|
||||||
/* iterate all siblings */
|
/* iterate all siblings */
|
||||||
trun_node = qtdemux_tree_get_sibling_by_type (trun_node, FOURCC_trun);
|
trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
|
||||||
|
&trun_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
next:
|
next:
|
||||||
|
@ -2089,8 +2110,11 @@ qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
|
||||||
gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
|
gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (track_id != stream->track_id)
|
GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
|
||||||
|
track_id, stream->track_id);
|
||||||
|
if (track_id != stream->track_id) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
|
value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
|
||||||
sample_size = (len & 3) + 1;
|
sample_size = (len & 3) + 1;
|
||||||
|
@ -2179,74 +2203,66 @@ corrupt_file:
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
qtdemux_parse_mfro (GstQTDemux * qtdemux, gint32 length,
|
qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
|
||||||
guint64 * mfra_offset, guint32 * mfro_size)
|
guint32 * mfro_size)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret = GST_FLOW_ERROR;
|
||||||
GstBuffer *mfro;
|
GstBuffer *mfro = NULL;
|
||||||
GNode *mfro_node;
|
|
||||||
GstQuery *query;
|
|
||||||
GstPad *sinkpad_peer_pad;
|
|
||||||
GstElement *sinkpad_peer;
|
|
||||||
guint32 fourcc;
|
guint32 fourcc;
|
||||||
gint64 len;
|
gint64 len;
|
||||||
gboolean r;
|
GstFormat fmt = GST_FORMAT_BYTES;
|
||||||
|
|
||||||
sinkpad_peer_pad = gst_pad_get_peer (qtdemux->sinkpad);
|
if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &fmt, &len)) {
|
||||||
sinkpad_peer = gst_pad_get_parent_element (sinkpad_peer_pad);
|
GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
|
||||||
gst_object_unref (sinkpad_peer_pad);
|
"can not locate mfro");
|
||||||
|
goto exit;
|
||||||
query = gst_query_new_duration (GST_FORMAT_BYTES);
|
|
||||||
r = gst_element_query (sinkpad_peer, query);
|
|
||||||
gst_object_unref (sinkpad_peer);
|
|
||||||
if (!r) {
|
|
||||||
GST_WARNING_OBJECT (qtdemux, "Cannot query duration to locate mfro");
|
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
}
|
||||||
gst_query_parse_duration (query, NULL, &len);
|
|
||||||
gst_query_unref (query);
|
|
||||||
|
|
||||||
ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
|
ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
return ret;
|
goto exit;
|
||||||
|
|
||||||
fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
|
fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
|
||||||
if (fourcc == FOURCC_mfro)
|
if (fourcc != FOURCC_mfro)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
|
GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
|
||||||
else
|
if (GST_BUFFER_SIZE (mfro) >= 16) {
|
||||||
return GST_FLOW_OK;
|
|
||||||
mfro_node = g_node_new ((guint8 *) GST_BUFFER_DATA (mfro));
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
|
GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
|
||||||
qtdemux_parse_node (qtdemux, mfro_node, GST_BUFFER_DATA (mfro), length);
|
*mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
|
||||||
*mfro_size = QT_UINT32 ((guint8 *) mfro_node->data + 12);
|
if (*mfro_size >= len) {
|
||||||
*mfra_offset = len - *mfro_size;
|
|
||||||
if (*mfro_size + 16 >= len) {
|
|
||||||
GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
|
GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
|
||||||
return GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
g_node_destroy (mfro_node);
|
*mfra_offset = len - *mfro_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (mfro)
|
||||||
gst_buffer_unref (mfro);
|
gst_buffer_unref (mfro);
|
||||||
return GST_FLOW_OK;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
qtdemux_parse_fragmented (GstQTDemux * qtdemux, guint32 length)
|
qtdemux_parse_fragmented (GstQTDemux * qtdemux)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint32 mfra_size = 0;
|
guint32 mfra_size = 0;
|
||||||
guint64 mfra_offset = 0;
|
guint64 mfra_offset = 0;
|
||||||
|
|
||||||
/* We check here if it is a fragmented mp4 container */
|
/* default */
|
||||||
ret = qtdemux_parse_mfro (qtdemux, length, &mfra_offset, &mfra_size);
|
|
||||||
if (ret != GST_FLOW_OK) {
|
|
||||||
qtdemux->fragmented = FALSE;
|
qtdemux->fragmented = FALSE;
|
||||||
return FALSE;
|
|
||||||
}
|
/* We check here if it is a fragmented mp4 container */
|
||||||
if (mfra_size != 0 && mfra_offset != 0) {
|
ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
|
||||||
|
if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
|
||||||
qtdemux->fragmented = TRUE;
|
qtdemux->fragmented = TRUE;
|
||||||
|
GST_DEBUG_OBJECT (qtdemux,
|
||||||
|
"mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
|
||||||
qtdemux->mfra_offset = mfra_offset;
|
qtdemux->mfra_offset = mfra_offset;
|
||||||
}
|
}
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2341,7 +2357,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
|
||||||
}
|
}
|
||||||
qtdemux->offset += length;
|
qtdemux->offset += length;
|
||||||
|
|
||||||
qtdemux_parse_fragmented (qtdemux, length);
|
qtdemux_parse_fragmented (qtdemux);
|
||||||
qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
|
qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
|
||||||
qtdemux_node_dump (qtdemux, qtdemux->moov_node);
|
qtdemux_node_dump (qtdemux, qtdemux->moov_node);
|
||||||
|
|
||||||
|
@ -4419,11 +4435,12 @@ qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GNode *
|
static GNode *
|
||||||
qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
|
qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
|
||||||
|
GstByteReader * parser)
|
||||||
{
|
{
|
||||||
GNode *child;
|
GNode *child;
|
||||||
guint8 *buffer;
|
guint8 *buffer;
|
||||||
guint32 child_fourcc;
|
guint32 child_fourcc, child_len;
|
||||||
|
|
||||||
for (child = g_node_next_sibling (node); child;
|
for (child = g_node_next_sibling (node); child;
|
||||||
child = g_node_next_sibling (child)) {
|
child = g_node_next_sibling (child)) {
|
||||||
|
@ -4432,12 +4449,25 @@ qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
|
||||||
child_fourcc = QT_FOURCC (buffer + 4);
|
child_fourcc = QT_FOURCC (buffer + 4);
|
||||||
|
|
||||||
if (child_fourcc == fourcc) {
|
if (child_fourcc == fourcc) {
|
||||||
|
if (parser) {
|
||||||
|
child_len = QT_UINT32 (buffer);
|
||||||
|
if (G_UNLIKELY (child_len < (4 + 4)))
|
||||||
|
return NULL;
|
||||||
|
/* FIXME: must verify if atom length < parent atom length */
|
||||||
|
gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
|
||||||
|
}
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GNode *
|
||||||
|
qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
|
||||||
|
{
|
||||||
|
return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_qtdemux_add_stream (GstQTDemux * qtdemux,
|
gst_qtdemux_add_stream (GstQTDemux * qtdemux,
|
||||||
QtDemuxStream * stream, GstTagList * list)
|
QtDemuxStream * stream, GstTagList * list)
|
||||||
|
|
|
@ -62,7 +62,7 @@ enum TfFlags
|
||||||
TF_DEFAULT_SAMPLE_DURATION = 0x000008, /* default-sample-duration-present */
|
TF_DEFAULT_SAMPLE_DURATION = 0x000008, /* default-sample-duration-present */
|
||||||
TF_DEFAULT_SAMPLE_SIZE = 0x000010, /* default-sample-size-present */
|
TF_DEFAULT_SAMPLE_SIZE = 0x000010, /* default-sample-size-present */
|
||||||
TF_DEFAULT_SAMPLE_FLAGS = 0x000020, /* default-sample-flags-present */
|
TF_DEFAULT_SAMPLE_FLAGS = 0x000020, /* default-sample-flags-present */
|
||||||
TF_DURATION_IS_EMPTY = 0x100000 /* sample-composition-time-offsets-presents */
|
TF_DURATION_IS_EMPTY = 0x100000 /* duration-is-empty */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TrFlags
|
enum TrFlags
|
||||||
|
|
Loading…
Reference in a new issue