From fff814bbe5c13bdf1df2a5fb5e331feb42cf2ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 7 Apr 2016 21:33:51 +0300 Subject: [PATCH] dashdemux: Implement parsing of moof box https://bugzilla.gnome.org/show_bug.cgi?id=741104 --- ext/dash/gstdashdemux.c | 312 +++++++++++++++++++++------------------- ext/dash/gstisoff.c | 267 +++++++++++++++++++++++++++++++++- ext/dash/gstisoff.h | 94 ++++++++++++ 3 files changed, 525 insertions(+), 148 deletions(-) diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 03f477d8a7..61d43ff2c3 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -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; diff --git a/ext/dash/gstisoff.c b/ext/dash/gstisoff.c index fafbc0fd2a..38e3ddc6b1 100644 --- a/ext/dash/gstisoff.c +++ b/ext/dash/gstisoff.c @@ -27,7 +27,6 @@ #include - /* 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) { diff --git a/ext/dash/gstisoff.h b/ext/dash/gstisoff.h index 8931640678..ca7663a197 100644 --- a/ext/dash/gstisoff.h +++ b/ext/dash/gstisoff.h @@ -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;