mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
dashdemux: Implement parsing of moof box
https://bugzilla.gnome.org/show_bug.cgi?id=741104
This commit is contained in:
parent
7d4f6ca0a9
commit
fff814bbe5
3 changed files with 525 additions and 148 deletions
|
@ -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,50 +1757,10 @@ 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;
|
||||
|
||||
if (split_at != available)
|
||||
pending = _gst_buffer_split (buffer, split_at, -1);
|
||||
|
||||
/* Reset, we're now at the start of a new box */
|
||||
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;
|
||||
}
|
||||
|
||||
buffer_offset = dash_stream->isobmff_parser.current_offset;
|
||||
buffer = pending;
|
||||
available = gst_buffer_get_size (buffer);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Always at the start of a box here */
|
||||
g_assert (dash_stream->isobmff_parser.current_size == 0);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -1807,14 +1778,19 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
dash_stream->isobmff_parser.current_size = size;
|
||||
|
||||
/* Do we have the complete box? */
|
||||
if (gst_byte_reader_get_remaining (&reader) < size - header_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);
|
||||
|
@ -1827,75 +1803,72 @@ gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
|
|||
dash_stream->isobmff_parser.current_offset +
|
||||
gst_byte_reader_get_pos (&reader) - header_size, size);
|
||||
|
||||
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MOOF) {
|
||||
GstByteReader sub_reader;
|
||||
GstMoofBox *moof;
|
||||
|
||||
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 {
|
||||
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 */
|
||||
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);
|
||||
} 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);
|
||||
/* 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;
|
||||
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;
|
||||
} else {
|
||||
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;
|
||||
|
||||
/* Not even a complete box, wait */
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Not even a single complete, non-mdat 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;
|
||||
}
|
||||
|
||||
/* Otherwise we pass through mdat, see above */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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) {
|
||||
if (dash_stream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT) {
|
||||
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
|
||||
if (!buffer)
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
g_assert (buffer
|
||||
|| gst_adapter_available (dash_stream->sidx_adapter) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
|
||||
else
|
||||
ret = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue