dashdemux: Implement parsing of moof box

https://bugzilla.gnome.org/show_bug.cgi?id=741104
This commit is contained in:
Sebastian Dröge 2016-04-07 21:33:51 +03:00
parent 7d4f6ca0a9
commit fff814bbe5
3 changed files with 525 additions and 148 deletions

View file

@ -1711,10 +1711,21 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
GstDashDemuxStream * dash_stream, GstBuffer * buffer)
{
GstAdaptiveDemuxStream *stream = (GstAdaptiveDemuxStream *) dash_stream;
GstBuffer *outbuf = NULL;
gsize available;
guint index_header_or_data;
guint64 buffer_offset;
GstMapInfo map;
GstByteReader reader;
guint32 fourcc;
guint header_size;
guint64 size, buffer_offset;
/* This must not be called when we're in the mdat. We only look at the mdat
* header and then stop parsing the boxes as we're only interested in the
* metadata! Handling mdat is the job of the surrounding code, as well as
* stopping or starting the next fragment when mdat is over (=> sidx)
*/
g_assert (dash_stream->isobmff_parser.current_fourcc !=
GST_ISOFF_FOURCC_MDAT);
if (stream->downloading_index)
index_header_or_data = 1;
@ -1746,156 +1757,118 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
buffer = gst_adapter_take_buffer (dash_stream->isobmff_adapter, available);
buffer_offset = dash_stream->isobmff_parser.current_offset;
/* Are we waiting for the current box to finish and it happens in this
* buffer? Push the current box and parse the remainder */
if (dash_stream->isobmff_parser.current_size != 0
&& dash_stream->isobmff_parser.current_size != -1
&& dash_stream->isobmff_parser.current_start_offset +
dash_stream->isobmff_parser.current_size <=
dash_stream->isobmff_parser.current_offset + available) {
GstBuffer *pending = NULL;
guint64 split_at =
(dash_stream->isobmff_parser.current_start_offset +
dash_stream->isobmff_parser.current_size) -
dash_stream->isobmff_parser.current_offset;
/* Always at the start of a box here */
g_assert (dash_stream->isobmff_parser.current_size == 0);
if (split_at != available)
pending = _gst_buffer_split (buffer, split_at, -1);
/* At the start of a box => Parse it */
gst_buffer_map (buffer, &map, GST_MAP_READ);
gst_byte_reader_init (&reader, map.data, map.size);
/* Reset, we're now at the start of a new box */
/* While there are more boxes left to parse ... */
dash_stream->isobmff_parser.current_start_offset =
dash_stream->isobmff_parser.current_offset;
do {
dash_stream->isobmff_parser.current_fourcc = 0;
dash_stream->isobmff_parser.current_size = 0;
dash_stream->isobmff_parser.current_offset += split_at;
dash_stream->isobmff_parser.current_start_offset =
dash_stream->isobmff_parser.current_offset;
outbuf = buffer;
if (!pending) {
GST_BUFFER_OFFSET (outbuf) = buffer_offset;
GST_BUFFER_OFFSET_END (outbuf) =
buffer_offset + gst_buffer_get_size (outbuf);
return outbuf;
if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, &header_size,
&size)) {
break;
}
buffer_offset = dash_stream->isobmff_parser.current_offset;
buffer = pending;
available = gst_buffer_get_size (buffer);
}
dash_stream->isobmff_parser.current_fourcc = fourcc;
if (size == 0) {
/* We assume this is mdat, anything else with "size until end"
* does not seem to make sense */
g_assert (dash_stream->isobmff_parser.current_fourcc ==
GST_ISOFF_FOURCC_MDAT);
dash_stream->isobmff_parser.current_size = -1;
break;
}
/* Are we at the start of a box? Parse it */
if (dash_stream->isobmff_parser.current_size == 0) {
GstMapInfo map;
GstByteReader reader;
guint32 fourcc;
guint header_size;
guint64 size;
dash_stream->isobmff_parser.current_size = size;
gst_buffer_map (buffer, &map, GST_MAP_READ);
gst_byte_reader_init (&reader, map.data, map.size);
/* Do we have the complete box or are at MDAT */
if (gst_byte_reader_get_remaining (&reader) < size - header_size ||
dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT) {
/* Reset byte reader to the beginning of the box */
gst_byte_reader_set_pos (&reader,
gst_byte_reader_get_pos (&reader) - header_size);
break;
}
/* While there are more boxes left to parse ... */
dash_stream->isobmff_parser.current_start_offset =
dash_stream->isobmff_parser.current_offset;
do {
dash_stream->isobmff_parser.current_fourcc = 0;
dash_stream->isobmff_parser.current_size = 0;
GST_LOG_OBJECT (stream->pad,
"box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
dash_stream->isobmff_parser.current_offset +
gst_byte_reader_get_pos (&reader) - header_size, size);
if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, &header_size,
&size)) {
break;
}
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MOOF) {
GstByteReader sub_reader;
GstMoofBox *moof;
dash_stream->isobmff_parser.current_fourcc = fourcc;
if (size == 0) {
dash_stream->isobmff_parser.current_size = -1;
break;
}
dash_stream->isobmff_parser.current_size = size;
/* Do we have the complete box? */
if (gst_byte_reader_get_remaining (&reader) < size - header_size) {
/* Reset byte reader to the beginning of the box */
gst_byte_reader_set_pos (&reader,
gst_byte_reader_get_pos (&reader) - header_size);
break;
}
GST_LOG_OBJECT (stream->pad,
"box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
dash_stream->isobmff_parser.current_offset +
gst_byte_reader_get_pos (&reader) - header_size, size);
gst_byte_reader_skip (&reader, size - header_size);
dash_stream->isobmff_parser.current_fourcc = 0;
dash_stream->isobmff_parser.current_start_offset += size;
dash_stream->isobmff_parser.current_size = 0;
} while (gst_byte_reader_get_remaining (&reader) > 0);
gst_buffer_unmap (buffer, &map);
/* mdat? Push all we have and wait for it to be over */
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT
|| dash_stream->isobmff_parser.current_size == -1) {
/* Nothing here, we just go out */
GST_LOG_OBJECT (stream->pad,
"box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
dash_stream->isobmff_parser.current_offset +
gst_byte_reader_get_pos (&reader) - header_size,
dash_stream->isobmff_parser.current_size);
} else if (gst_byte_reader_get_pos (&reader) != 0) {
GstBuffer *pending;
/* Multiple complete boxes and no mdat? Push them and
* keep the remainder, which is the start of the next box
* if any remainder */
pending =
_gst_buffer_split (buffer, gst_byte_reader_get_pos (&reader), -1);
gst_adapter_push (dash_stream->isobmff_adapter, pending);
dash_stream->isobmff_parser.current_offset +=
gst_byte_reader_get_pos (&reader);
dash_stream->isobmff_parser.current_size = 0;
if (outbuf)
outbuf = gst_buffer_append (outbuf, buffer);
else
outbuf = buffer;
buffer = NULL;
GST_BUFFER_OFFSET (outbuf) = buffer_offset;
GST_BUFFER_OFFSET_END (outbuf) =
buffer_offset + gst_buffer_get_size (outbuf);
return outbuf;
gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size);
moof = gst_isoff_moof_box_parse (&sub_reader);
/* TODO: Do something with this */
gst_isoff_moof_box_free (moof);
} else {
/* Not even a complete box, wait */
dash_stream->isobmff_parser.current_size = 0;
gst_adapter_push (dash_stream->isobmff_adapter, buffer);
if (outbuf) {
GST_BUFFER_OFFSET (outbuf) = buffer_offset;
GST_BUFFER_OFFSET_END (outbuf) =
buffer_offset + gst_buffer_get_size (outbuf);
}
return outbuf;
gst_byte_reader_skip (&reader, size - header_size);
}
/* Otherwise we pass through mdat, see above */
dash_stream->isobmff_parser.current_fourcc = 0;
dash_stream->isobmff_parser.current_start_offset += size;
dash_stream->isobmff_parser.current_size = 0;
} while (gst_byte_reader_get_remaining (&reader) > 0);
gst_buffer_unmap (buffer, &map);
/* mdat? Push all we have and wait for it to be over */
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT) {
GstBuffer *pending;
GST_LOG_OBJECT (stream->pad,
"box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
dash_stream->isobmff_parser.current_offset +
gst_byte_reader_get_pos (&reader) - header_size,
dash_stream->isobmff_parser.current_size);
/* At mdat. Move the start of the mdat to the adapter and have everything
* else be pushed. We parsed all header boxes at this point and are not
* supposed to be called again until the next moof */
pending = _gst_buffer_split (buffer, gst_byte_reader_get_pos (&reader), -1);
gst_adapter_push (dash_stream->isobmff_adapter, pending);
dash_stream->isobmff_parser.current_offset +=
gst_byte_reader_get_pos (&reader);
dash_stream->isobmff_parser.current_size = 0;
GST_BUFFER_OFFSET (buffer) = buffer_offset;
GST_BUFFER_OFFSET_END (buffer) =
buffer_offset + gst_buffer_get_size (buffer);
return buffer;
} else if (gst_byte_reader_get_pos (&reader) != 0) {
GstBuffer *pending;
/* Multiple complete boxes and no mdat? Push them and keep the remainder,
* which is the start of the next box if any remainder */
pending = _gst_buffer_split (buffer, gst_byte_reader_get_pos (&reader), -1);
gst_adapter_push (dash_stream->isobmff_adapter, pending);
dash_stream->isobmff_parser.current_offset +=
gst_byte_reader_get_pos (&reader);
dash_stream->isobmff_parser.current_size = 0;
GST_BUFFER_OFFSET (buffer) = buffer_offset;
GST_BUFFER_OFFSET_END (buffer) =
buffer_offset + gst_buffer_get_size (buffer);
return buffer;
}
/* Passing through mdat here */
dash_stream->isobmff_parser.current_offset += gst_buffer_get_size (buffer);
if (outbuf)
outbuf = gst_buffer_append (outbuf, buffer);
else
outbuf = buffer;
buffer = NULL;
/* Not even a single complete, non-mdat box, wait */
dash_stream->isobmff_parser.current_size = 0;
gst_adapter_push (dash_stream->isobmff_adapter, buffer);
GST_BUFFER_OFFSET (outbuf) = buffer_offset;
GST_BUFFER_OFFSET_END (outbuf) = buffer_offset + gst_buffer_get_size (outbuf);
return outbuf;
return NULL;
}
static GstFlowReturn
@ -1909,9 +1882,25 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
if (!gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
if (dash_stream->is_isobmff) {
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
if (!buffer)
return GST_FLOW_OK;
if (dash_stream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT) {
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
if (buffer
&& (ret =
gst_adaptive_demux_stream_push_buffer (stream,
buffer)) != GST_FLOW_OK)
return ret;
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT
&& gst_adapter_available (dash_stream->isobmff_adapter) > 0) {
buffer =
gst_adapter_take_buffer (dash_stream->isobmff_adapter,
gst_adapter_available (dash_stream->isobmff_adapter));
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
}
return ret;
}
}
return gst_adaptive_demux_stream_push_buffer (stream, buffer);
@ -2010,10 +1999,25 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
if (dash_stream->is_isobmff) {
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
g_assert (buffer || !advance);
g_assert (buffer
|| gst_adapter_available (dash_stream->sidx_adapter) == 0);
if (dash_stream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT) {
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
/* Leftover in the adapter is actual mdat data if any */
if (dash_stream->isobmff_parser.current_fourcc ==
GST_ISOFF_FOURCC_MDAT
&& gst_adapter_available (dash_stream->isobmff_adapter) > 0) {
GstBuffer *buffer2 =
gst_adapter_take_buffer (dash_stream->isobmff_adapter,
gst_adapter_available (dash_stream->isobmff_adapter));
if (buffer)
buffer = gst_buffer_append (buffer, buffer2);
else
buffer = buffer2;
}
g_assert (buffer || !advance);
}
}
if (buffer) {
@ -2041,13 +2045,27 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
if (dash_stream->is_isobmff) {
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
}
if (dash_stream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT) {
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
if (buffer)
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
else
ret = GST_FLOW_OK;
if (buffer
&& (ret =
gst_adaptive_demux_stream_push_buffer (stream,
buffer)) != GST_FLOW_OK)
return ret;
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT
&& gst_adapter_available (dash_stream->isobmff_adapter) > 0) {
buffer =
gst_adapter_take_buffer (dash_stream->isobmff_adapter,
gst_adapter_available (dash_stream->isobmff_adapter));
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
}
return ret;
}
}
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
}
return ret;

View file

@ -27,7 +27,6 @@
#include <string.h>
/* gst_isoff_parse_box:
* @reader:
* @type: type that was found at the current position
@ -82,6 +81,272 @@ not_enough_data:
return FALSE;
}
static void
gst_isoff_trun_box_clear (GstTrunBox * trun)
{
if (trun->samples)
g_array_free (trun->samples, TRUE);
}
static void
gst_isoff_traf_box_clear (GstTrafBox * traf)
{
if (traf->trun)
g_array_free (traf->trun, TRUE);
}
static gboolean
gst_isoff_mfhd_box_parse (GstMfhdBox * mfhd, GstByteReader * reader)
{
guint8 version;
guint32 flags;
if (gst_byte_reader_get_remaining (reader) != 8)
return FALSE;
version = gst_byte_reader_get_uint8_unchecked (reader);
if (version != 0)
return FALSE;
flags = gst_byte_reader_get_uint24_be_unchecked (reader);
if (flags != 0)
return FALSE;
mfhd->sequence_number = gst_byte_reader_get_uint32_be_unchecked (reader);
return TRUE;
}
static gboolean
gst_isoff_tfhd_box_parse (GstTfhdBox * tfhd, GstByteReader * reader)
{
memset (tfhd, 0, sizeof (*tfhd));
if (gst_byte_reader_get_remaining (reader) < 4)
return FALSE;
tfhd->version = gst_byte_reader_get_uint8_unchecked (reader);
if (tfhd->version != 0)
return FALSE;
tfhd->flags = gst_byte_reader_get_uint24_be_unchecked (reader);
if (!gst_byte_reader_get_uint32_be (reader, &tfhd->track_id))
return FALSE;
if ((tfhd->flags & GST_TFHD_FLAGS_BASE_DATA_OFFSET_PRESENT) &&
!gst_byte_reader_get_uint64_be (reader, &tfhd->base_data_offset))
return FALSE;
if ((tfhd->flags & GST_TFHD_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &tfhd->sample_description_index))
return FALSE;
if ((tfhd->flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &tfhd->default_sample_duration))
return FALSE;
if ((tfhd->flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &tfhd->default_sample_size))
return FALSE;
if ((tfhd->flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &tfhd->default_sample_flags))
return FALSE;
return TRUE;
}
static gboolean
gst_isoff_trun_box_parse (GstTrunBox * trun, GstByteReader * reader)
{
gint i;
memset (trun, 0, sizeof (*trun));
if (gst_byte_reader_get_remaining (reader) < 4)
return FALSE;
trun->version = gst_byte_reader_get_uint8_unchecked (reader);
if (trun->version != 0 && trun->version != 1)
return FALSE;
trun->flags = gst_byte_reader_get_uint24_be_unchecked (reader);
if (!gst_byte_reader_get_uint32_be (reader, &trun->sample_count))
return FALSE;
trun->samples =
g_array_sized_new (FALSE, FALSE, sizeof (GstTrunSample),
trun->sample_count);
if ((trun->flags & GST_TRUN_FLAGS_DATA_OFFSET_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, (guint32 *) & trun->data_offset))
return FALSE;
if ((trun->flags & GST_TRUN_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &trun->first_sample_flags))
return FALSE;
for (i = 0; i < trun->sample_count; i++) {
GstTrunSample sample = { 0, };
if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_DURATION_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &sample.sample_duration))
goto error;
if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_SIZE_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &sample.sample_size))
goto error;
if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_FLAGS_PRESENT) &&
!gst_byte_reader_get_uint32_be (reader, &sample.sample_flags))
goto error;
if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSETS_PRESENT)
&& !gst_byte_reader_get_uint32_be (reader,
&sample.sample_composition_time_offset.u))
goto error;
g_array_append_val (trun->samples, sample);
}
return TRUE;
error:
gst_isoff_trun_box_clear (trun);
return FALSE;
}
static gboolean
gst_isoff_traf_box_parse (GstTrafBox * traf, GstByteReader * reader)
{
gboolean had_tfhd = FALSE;
memset (traf, 0, sizeof (*traf));
traf->trun = g_array_new (FALSE, FALSE, sizeof (GstTrunBox));
g_array_set_clear_func (traf->trun,
(GDestroyNotify) gst_isoff_trun_box_clear);
while (gst_byte_reader_get_remaining (reader) > 0) {
guint32 fourcc;
guint header_size;
guint64 size;
if (!gst_isoff_parse_box_header (reader, &fourcc, NULL, &header_size,
&size))
goto error;
if (gst_byte_reader_get_remaining (reader) < size - header_size)
goto error;
switch (fourcc) {
case GST_ISOFF_FOURCC_TFHD:{
GstByteReader sub_reader;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_tfhd_box_parse (&traf->tfhd, &sub_reader))
goto error;
had_tfhd = TRUE;
break;
}
case GST_ISOFF_FOURCC_TRUN:{
GstByteReader sub_reader;
GstTrunBox trun;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_trun_box_parse (&trun, &sub_reader))
goto error;
g_array_append_val (traf->trun, trun);
break;
}
default:
gst_byte_reader_skip (reader, size - header_size);
break;
}
}
if (!had_tfhd)
goto error;
return TRUE;
error:
gst_isoff_traf_box_clear (traf);
return FALSE;
}
GstMoofBox *
gst_isoff_moof_box_parse (GstByteReader * reader)
{
GstMoofBox *moof;
gboolean had_mfhd = FALSE;
moof = g_new0 (GstMoofBox, 1);
moof->traf = g_array_new (FALSE, FALSE, sizeof (GstTrafBox));
g_array_set_clear_func (moof->traf,
(GDestroyNotify) gst_isoff_traf_box_clear);
while (gst_byte_reader_get_remaining (reader) > 0) {
guint32 fourcc;
guint header_size;
guint64 size;
if (!gst_isoff_parse_box_header (reader, &fourcc, NULL, &header_size,
&size))
goto error;
if (gst_byte_reader_get_remaining (reader) < size - header_size)
goto error;
switch (fourcc) {
case GST_ISOFF_FOURCC_MFHD:{
GstByteReader sub_reader;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_mfhd_box_parse (&moof->mfhd, &sub_reader))
goto error;
had_mfhd = TRUE;
break;
}
case GST_ISOFF_FOURCC_TRAF:{
GstByteReader sub_reader;
GstTrafBox traf;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_traf_box_parse (&traf, &sub_reader))
goto error;
g_array_append_val (moof->traf, traf);
break;
}
default:
gst_byte_reader_skip (reader, size - header_size);
break;
}
}
if (!had_mfhd)
goto error;
return moof;
error:
gst_isoff_moof_box_free (moof);
return NULL;
}
void
gst_isoff_moof_box_free (GstMoofBox * moof)
{
g_array_free (moof->traf, TRUE);
g_free (moof);
}
void
gst_isoff_sidx_parser_init (GstSidxParser * parser)
{

View file

@ -40,9 +40,103 @@ typedef enum {
gboolean gst_isoff_parse_box_header (GstByteReader * reader, guint32 * type, guint8 extended_type[16], guint * header_size, guint64 * size);
#define GST_ISOFF_FOURCC_UUID GST_MAKE_FOURCC('u','u','i','d')
#define GST_ISOFF_FOURCC_MOOF GST_MAKE_FOURCC('m','o','o','f')
#define GST_ISOFF_FOURCC_MFHD GST_MAKE_FOURCC('m','f','h','d')
#define GST_ISOFF_FOURCC_TFHD GST_MAKE_FOURCC('t','f','h','d')
#define GST_ISOFF_FOURCC_TRUN GST_MAKE_FOURCC('t','r','u','n')
#define GST_ISOFF_FOURCC_TRAF GST_MAKE_FOURCC('t','r','a','f')
#define GST_ISOFF_FOURCC_MDAT GST_MAKE_FOURCC('m','d','a','t')
#define GST_ISOFF_FOURCC_SIDX GST_MAKE_FOURCC('s','i','d','x')
#define GST_ISOFF_SAMPLE_FLAGS_IS_LEADING(flags) (((flags) >> 26) & 0x03)
#define GST_ISOFF_SAMPLE_FLAGS_SAMPLE_DEPENDS_ON(flags) (((flags) >> 24) & 0x03)
#define GST_ISOFF_SAMPLE_FLAGS_SAMPLE_IS_DEPENDED_ON(flags) (((flags) >> 22) & 0x03)
#define GST_ISOFF_SAMPLE_FLAGS_SAMPLE_HAS_REDUNDANCY(flags) (((flags) >> 20) & 0x03)
#define GST_ISOFF_SAMPLE_FLAGS_SAMPLE_PADDING_VALUE(flags) (((flags) >> 17) & 0x07)
#define GST_ISOFF_SAMPLE_FLAGS_SAMPLE_IS_NON_SYNC_SAMPLE(flags) (((flags) >> 16) & 0x01)
#define GST_ISOFF_SAMPLE_FLAGS_SAMPLE_DEGRADATION_PRIORITY(flags) (((flags) >> 0) & 0x0f)
typedef struct _GstMfhdBox
{
guint32 sequence_number;
} GstMfhdBox;
typedef enum
{
GST_TFHD_FLAGS_BASE_DATA_OFFSET_PRESENT = 0x000001,
GST_TFHD_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT = 0x000002,
GST_TFHD_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT = 0x000008,
GST_TFHD_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT = 0x000010,
GST_TFHD_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT = 0x000020,
GST_TFHD_FLAGS_DURATION_IS_EMPTY = 0x010000,
GST_TFHD_FLAGS_DEFAULT_BASE_IS_MOOF = 0x020000
} GstTfhdFlags;
typedef struct _GstTfhdBox
{
guint8 version;
GstTfhdFlags flags;
guint32 track_id;
/* optional */
guint64 base_data_offset;
guint32 sample_description_index;
guint32 default_sample_duration;
guint32 default_sample_size;
guint32 default_sample_flags;
} GstTfhdBox;
typedef enum
{
GST_TRUN_FLAGS_DATA_OFFSET_PRESENT = 0x000001,
GST_TRUN_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT = 0x000004,
GST_TRUN_FLAGS_SAMPLE_DURATION_PRESENT = 0x000100,
GST_TRUN_FLAGS_SAMPLE_SIZE_PRESENT = 0x000200,
GST_TRUN_FLAGS_SAMPLE_FLAGS_PRESENT = 0x000400,
GST_TRUN_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSETS_PRESENT = 0x000800
} GstTrunFlags;
typedef struct _GstTrunBox
{
guint8 version;
GstTrunFlags flags;
guint32 sample_count;
/* optional */
gint32 data_offset;
guint32 first_sample_flags;
GArray *samples;
} GstTrunBox;
typedef struct _GstTrunSample
{
guint32 sample_duration;
guint32 sample_size;
guint32 sample_flags;
union {
guint32 u; /* version 0 */
gint32 s; /* others */
} sample_composition_time_offset;
} GstTrunSample;
typedef struct _GstTrafBox
{
GstTfhdBox tfhd;
GArray *trun;
} GstTrafBox;
typedef struct _GstMoofBox
{
GstMfhdBox mfhd;
GArray *traf;
} GstMoofBox;
GstMoofBox * gst_isoff_moof_box_parse (GstByteReader *reader);
void gst_isoff_moof_box_free (GstMoofBox *moof);
typedef struct _GstSidxBoxEntry
{
gboolean ref_type;