mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-08 21:28:45 +00:00
qtdemux: parse mfra random access box for fragmented mp4 files
If it's present, and we operate in pull mode.
This commit is contained in:
parent
8a0f4e74e4
commit
e24f903b13
2 changed files with 142 additions and 103 deletions
|
@ -6,7 +6,9 @@
|
||||||
* Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
|
* Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
|
||||||
* Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
|
* Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
|
||||||
* Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
|
* Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
|
||||||
* Copyright (C) <2013> Intel Coroporation
|
* Copyright (C) <2013> Intel Corporation
|
||||||
|
* Copyright (C) <2014> Centricular Ltd
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
|
@ -199,6 +201,13 @@ struct _QtDemuxSegment
|
||||||
|
|
||||||
#define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
|
#define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
|
||||||
|
|
||||||
|
/* Used with fragmented MP4 files (mfra atom) */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GstClockTime ts;
|
||||||
|
guint64 moof_offset;
|
||||||
|
} QtDemuxRandomAccessEntry;
|
||||||
|
|
||||||
struct _QtDemuxStream
|
struct _QtDemuxStream
|
||||||
{
|
{
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
|
@ -347,6 +356,9 @@ struct _QtDemuxStream
|
||||||
gboolean stps_present;
|
gboolean stps_present;
|
||||||
guint32 n_sample_partial_syncs;
|
guint32 n_sample_partial_syncs;
|
||||||
guint32 stps_index;
|
guint32 stps_index;
|
||||||
|
QtDemuxRandomAccessEntry *ra_entries;
|
||||||
|
guint n_ra_entries;
|
||||||
|
|
||||||
/* ctts */
|
/* ctts */
|
||||||
gboolean ctts_present;
|
gboolean ctts_present;
|
||||||
guint32 n_composition_times;
|
guint32 n_composition_times;
|
||||||
|
@ -471,6 +483,8 @@ static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
|
||||||
static void qtdemux_do_allocation (GstQTDemux * qtdemux,
|
static void qtdemux_do_allocation (GstQTDemux * qtdemux,
|
||||||
QtDemuxStream * stream);
|
QtDemuxStream * stream);
|
||||||
|
|
||||||
|
static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_qtdemux_class_init (GstQTDemuxClass * klass)
|
gst_qtdemux_class_init (GstQTDemuxClass * klass)
|
||||||
{
|
{
|
||||||
|
@ -1844,7 +1858,6 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
|
||||||
qtdemux->fragment_start = -1;
|
qtdemux->fragment_start = -1;
|
||||||
qtdemux->fragment_start_offset = -1;
|
qtdemux->fragment_start_offset = -1;
|
||||||
qtdemux->duration = 0;
|
qtdemux->duration = 0;
|
||||||
qtdemux->mfra_offset = 0;
|
|
||||||
qtdemux->moof_offset = 0;
|
qtdemux->moof_offset = 0;
|
||||||
qtdemux->chapters_track_id = 0;
|
qtdemux->chapters_track_id = 0;
|
||||||
qtdemux->have_group_id = FALSE;
|
qtdemux->have_group_id = FALSE;
|
||||||
|
@ -2143,6 +2156,10 @@ gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
|
||||||
stream->redirect_uri = NULL;
|
stream->redirect_uri = NULL;
|
||||||
/* free stbl sub-atoms */
|
/* free stbl sub-atoms */
|
||||||
gst_qtdemux_stbl_free (stream);
|
gst_qtdemux_stbl_free (stream);
|
||||||
|
/* fragments */
|
||||||
|
g_free (stream->ra_entries);
|
||||||
|
stream->ra_entries = NULL;
|
||||||
|
stream->n_ra_entries = 0;
|
||||||
|
|
||||||
stream->sent_eos = FALSE;
|
stream->sent_eos = FALSE;
|
||||||
stream->segment_index = -1;
|
stream->segment_index = -1;
|
||||||
|
@ -2888,44 +2905,53 @@ fail:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* might be used if some day we actually use mfra & co
|
/* might be used if some day we actually use mfra & co
|
||||||
* for random access to fragments,
|
* for random access to fragments,
|
||||||
* but that will require quite some modifications and much less relying
|
* but that will require quite some modifications and much less relying
|
||||||
* on a sample array */
|
* on a sample array */
|
||||||
#if 0
|
#endif
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
|
qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
|
||||||
QtDemuxStream * stream)
|
|
||||||
{
|
{
|
||||||
guint64 time = 0, moof_offset = 0;
|
QtDemuxStream *stream;
|
||||||
guint32 ver_flags, track_id, len, num_entries, i;
|
guint32 ver_flags, track_id, len, num_entries, i;
|
||||||
guint value_size, traf_size, trun_size, sample_size;
|
guint value_size, traf_size, trun_size, sample_size;
|
||||||
|
guint64 time = 0, moof_offset = 0;
|
||||||
|
#if 0
|
||||||
GstBuffer *buf = NULL;
|
GstBuffer *buf = NULL;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
#endif
|
||||||
GstByteReader tfra;
|
GstByteReader tfra;
|
||||||
|
|
||||||
gst_byte_reader_init (&tfra, (guint8 *) tfra_node->data + (4 + 4),
|
gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
|
||||||
QT_UINT32 ((guint8 *) tfra_node->data) - (4 + 4));
|
|
||||||
|
if (!gst_byte_reader_skip (&tfra, 8))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
|
if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!(gst_byte_reader_get_uint32_be (&tfra, &track_id) &&
|
if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
|
||||||
gst_byte_reader_get_uint32_be (&tfra, &len) &&
|
|| !gst_byte_reader_get_uint32_be (&tfra, &len)
|
||||||
gst_byte_reader_get_uint32_be (&tfra, &num_entries)))
|
|| !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux, "id %d == stream id %d ?",
|
GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
|
||||||
track_id, stream->track_id);
|
|
||||||
if (track_id != stream->track_id) {
|
stream = qtdemux_find_stream (qtdemux, track_id);
|
||||||
return FALSE;
|
if (stream == NULL)
|
||||||
}
|
goto unknown_trackid;
|
||||||
|
|
||||||
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;
|
||||||
trun_size = ((len & 12) >> 2) + 1;
|
trun_size = ((len & 12) >> 2) + 1;
|
||||||
traf_size = ((len & 48) >> 4) + 1;
|
traf_size = ((len & 48) >> 4) + 1;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
|
||||||
|
"sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
|
||||||
|
|
||||||
if (num_entries == 0)
|
if (num_entries == 0)
|
||||||
goto no_samples;
|
goto no_samples;
|
||||||
|
|
||||||
|
@ -2933,6 +2959,10 @@ qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
|
||||||
value_size + value_size + traf_size + trun_size + sample_size))
|
value_size + value_size + traf_size + trun_size + sample_size))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
|
g_free (stream->ra_entries);
|
||||||
|
stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
|
||||||
|
stream->n_ra_entries = num_entries;
|
||||||
|
|
||||||
for (i = 0; i < num_entries; i++) {
|
for (i = 0; i < num_entries; i++) {
|
||||||
qt_atom_parser_get_offset (&tfra, value_size, &time);
|
qt_atom_parser_get_offset (&tfra, value_size, &time);
|
||||||
qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
|
qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
|
||||||
|
@ -2940,26 +2970,36 @@ qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node,
|
||||||
qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
|
qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
|
||||||
qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
|
qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux,
|
time = gst_util_uint64_scale (time, GST_SECOND, stream->timescale);
|
||||||
"fragment time: %" GST_TIME_FORMAT " moof_offset: %u",
|
|
||||||
GST_TIME_ARGS (gst_util_uint64_scale (time, GST_SECOND,
|
|
||||||
stream->timescale)), moof_offset);
|
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
|
||||||
|
" moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
|
||||||
|
|
||||||
|
stream->ra_entries[i].ts = time;
|
||||||
|
stream->ra_entries[i].moof_offset = moof_offset;
|
||||||
|
|
||||||
|
/* don't want to go through the entire file and read all moofs at startup */
|
||||||
|
#if 0
|
||||||
ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
|
ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
|
qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
|
||||||
moof_offset, stream);
|
moof_offset, stream);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
unknown_trackid:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
corrupt_file:
|
corrupt_file:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
|
GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
|
||||||
(_("This file is corrupt and cannot be played.")), (NULL));
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
no_samples:
|
no_samples:
|
||||||
|
@ -2970,106 +3010,104 @@ no_samples:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_parse_mfra (GstQTDemux * qtdemux, QtDemuxStream * stream)
|
qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GstMapInfo mfro_map = GST_MAP_INFO_INIT;
|
||||||
|
GstMapInfo mfra_map = GST_MAP_INFO_INIT;
|
||||||
|
GstBuffer *mfro = NULL, *mfra = NULL;
|
||||||
|
GstFlowReturn flow;
|
||||||
|
gboolean ret = FALSE;
|
||||||
GNode *mfra_node, *tfra_node;
|
GNode *mfra_node, *tfra_node;
|
||||||
GstBuffer *buffer;
|
guint64 mfra_offset = 0;
|
||||||
|
guint32 fourcc, mfra_size;
|
||||||
|
gint64 len;
|
||||||
|
|
||||||
if (!qtdemux->mfra_offset)
|
/* query upstream size in bytes */
|
||||||
return FALSE;
|
if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
|
||||||
|
goto size_query_failed;
|
||||||
|
|
||||||
ret = gst_qtdemux_pull_atom (qtdemux, qtdemux->mfra_offset, 0, &buffer);
|
/* mfro box should be at the very end of the file */
|
||||||
if (ret != GST_FLOW_OK)
|
flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
|
||||||
goto corrupt_file;
|
if (flow != GST_FLOW_OK)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
mfra_node = g_node_new ((guint8 *) GST_BUFFER_DATA (buffer));
|
gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
|
||||||
qtdemux_parse_node (qtdemux, mfra_node, GST_BUFFER_DATA (buffer),
|
|
||||||
GST_BUFFER_SIZE (buffer));
|
fourcc = QT_FOURCC (mfro_map.data + 4);
|
||||||
|
if (fourcc != FOURCC_mfro)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (qtdemux, "Found mfro box");
|
||||||
|
if (mfro_map.size < 16)
|
||||||
|
goto invalid_mfro_size;
|
||||||
|
|
||||||
|
mfra_size = QT_UINT32 (mfro_map.data + 12);
|
||||||
|
if (mfra_size >= len)
|
||||||
|
goto invalid_mfra_size;
|
||||||
|
|
||||||
|
mfra_offset = len - mfra_size;
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
|
||||||
|
mfra_offset, mfra_size);
|
||||||
|
|
||||||
|
/* now get and parse mfra box */
|
||||||
|
flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
|
||||||
|
if (flow != GST_FLOW_OK)
|
||||||
|
goto broken_file;
|
||||||
|
|
||||||
|
gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
|
||||||
|
|
||||||
|
mfra_node = g_node_new ((guint8 *) mfra_map.data);
|
||||||
|
qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
|
||||||
|
|
||||||
tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
|
tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
|
||||||
|
|
||||||
while (tfra_node) {
|
while (tfra_node) {
|
||||||
qtdemux_parse_tfra (qtdemux, tfra_node, stream);
|
qtdemux_parse_tfra (qtdemux, tfra_node);
|
||||||
/* iterate all siblings */
|
/* iterate all siblings */
|
||||||
tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
|
tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
|
||||||
}
|
}
|
||||||
g_node_destroy (mfra_node);
|
g_node_destroy (mfra_node);
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
|
|
||||||
return TRUE;
|
GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
|
||||||
|
ret = TRUE;
|
||||||
corrupt_file:
|
|
||||||
{
|
|
||||||
GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
|
|
||||||
(_("This file is corrupt and cannot be played.")), (NULL));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
qtdemux_parse_mfro (GstQTDemux * qtdemux, guint64 * mfra_offset,
|
|
||||||
guint32 * mfro_size)
|
|
||||||
{
|
|
||||||
GstFlowReturn ret = GST_FLOW_ERROR;
|
|
||||||
GstBuffer *mfro = NULL;
|
|
||||||
guint32 fourcc;
|
|
||||||
gint64 len;
|
|
||||||
GstFormat fmt = GST_FORMAT_BYTES;
|
|
||||||
|
|
||||||
if (!gst_pad_peer_query_duration (qtdemux->sinkpad, &fmt, &len)) {
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "upstream size not available; "
|
|
||||||
"can not locate mfro");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
fourcc = QT_FOURCC (GST_BUFFER_DATA (mfro) + 4);
|
|
||||||
if (fourcc != FOURCC_mfro)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (qtdemux, "Found mfro atom: fragmented mp4 container");
|
|
||||||
if (GST_BUFFER_SIZE (mfro) >= 16) {
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "parsing 'mfro' atom");
|
|
||||||
*mfro_size = QT_UINT32 (GST_BUFFER_DATA (mfro) + 12);
|
|
||||||
if (*mfro_size >= len) {
|
|
||||||
GST_WARNING_OBJECT (qtdemux, "mfro.size is invalid");
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
*mfra_offset = len - *mfro_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (mfro)
|
|
||||||
|
if (mfro) {
|
||||||
|
if (mfro_map.memory != NULL)
|
||||||
|
gst_buffer_unmap (mfro, &mfro_map);
|
||||||
gst_buffer_unref (mfro);
|
gst_buffer_unref (mfro);
|
||||||
|
}
|
||||||
|
if (mfra) {
|
||||||
|
if (mfra_map.memory != NULL)
|
||||||
|
gst_buffer_unmap (mfra, &mfra_map);
|
||||||
|
gst_buffer_unref (mfra);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
/* ERRORS */
|
||||||
qtdemux_parse_fragmented (GstQTDemux * qtdemux)
|
size_query_failed:
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
|
||||||
guint32 mfra_size = 0;
|
goto exit;
|
||||||
guint64 mfra_offset = 0;
|
}
|
||||||
|
invalid_mfro_size:
|
||||||
/* default */
|
{
|
||||||
qtdemux->fragmented = FALSE;
|
GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
|
||||||
|
goto exit;
|
||||||
/* We check here if it is a fragmented mp4 container */
|
}
|
||||||
ret = qtdemux_parse_mfro (qtdemux, &mfra_offset, &mfra_size);
|
invalid_mfra_size:
|
||||||
if (ret == GST_FLOW_OK && mfra_size != 0 && mfra_offset != 0) {
|
{
|
||||||
qtdemux->fragmented = TRUE;
|
GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
|
||||||
GST_DEBUG_OBJECT (qtdemux,
|
goto exit;
|
||||||
"mfra atom expected at offset %" G_GUINT64_FORMAT, mfra_offset);
|
}
|
||||||
qtdemux->mfra_offset = mfra_offset;
|
broken_file:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
|
gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
|
||||||
|
@ -3106,6 +3144,9 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
|
||||||
if (!qtdemux->moof_offset) {
|
if (!qtdemux->moof_offset) {
|
||||||
qtdemux->moof_offset = qtdemux->offset;
|
qtdemux->moof_offset = qtdemux->offset;
|
||||||
}
|
}
|
||||||
|
if (qtdemux_pull_mfro_mfra (qtdemux)) {
|
||||||
|
/* FIXME */
|
||||||
|
}
|
||||||
if (qtdemux->got_moov) {
|
if (qtdemux->got_moov) {
|
||||||
GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
|
GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
|
||||||
ret = GST_FLOW_EOS;
|
ret = GST_FLOW_EOS;
|
||||||
|
|
|
@ -79,8 +79,6 @@ struct _GstQTDemux {
|
||||||
guint64 duration;
|
guint64 duration;
|
||||||
|
|
||||||
gboolean fragmented;
|
gboolean fragmented;
|
||||||
/* offset of the mfra atom */
|
|
||||||
guint64 mfra_offset;
|
|
||||||
guint64 moof_offset;
|
guint64 moof_offset;
|
||||||
|
|
||||||
gint state;
|
gint state;
|
||||||
|
|
Loading…
Reference in a new issue