mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 23:48:53 +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)
|
GstDashDemuxStream * dash_stream, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstAdaptiveDemuxStream *stream = (GstAdaptiveDemuxStream *) dash_stream;
|
GstAdaptiveDemuxStream *stream = (GstAdaptiveDemuxStream *) dash_stream;
|
||||||
GstBuffer *outbuf = NULL;
|
|
||||||
gsize available;
|
gsize available;
|
||||||
guint index_header_or_data;
|
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)
|
if (stream->downloading_index)
|
||||||
index_header_or_data = 1;
|
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 = gst_adapter_take_buffer (dash_stream->isobmff_adapter, available);
|
||||||
buffer_offset = dash_stream->isobmff_parser.current_offset;
|
buffer_offset = dash_stream->isobmff_parser.current_offset;
|
||||||
|
|
||||||
/* Are we waiting for the current box to finish and it happens in this
|
/* Always at the start of a box here */
|
||||||
* buffer? Push the current box and parse the remainder */
|
g_assert (dash_stream->isobmff_parser.current_size == 0);
|
||||||
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)
|
/* At the start of a box => Parse it */
|
||||||
pending = _gst_buffer_split (buffer, split_at, -1);
|
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_fourcc = 0;
|
||||||
dash_stream->isobmff_parser.current_size = 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 (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, &header_size,
|
||||||
if (!pending) {
|
&size)) {
|
||||||
GST_BUFFER_OFFSET (outbuf) = buffer_offset;
|
break;
|
||||||
GST_BUFFER_OFFSET_END (outbuf) =
|
|
||||||
buffer_offset + gst_buffer_get_size (outbuf);
|
|
||||||
return outbuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_offset = dash_stream->isobmff_parser.current_offset;
|
dash_stream->isobmff_parser.current_fourcc = fourcc;
|
||||||
buffer = pending;
|
if (size == 0) {
|
||||||
available = gst_buffer_get_size (buffer);
|
/* 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 */
|
dash_stream->isobmff_parser.current_size = size;
|
||||||
if (dash_stream->isobmff_parser.current_size == 0) {
|
|
||||||
GstMapInfo map;
|
|
||||||
GstByteReader reader;
|
|
||||||
guint32 fourcc;
|
|
||||||
guint header_size;
|
|
||||||
guint64 size;
|
|
||||||
|
|
||||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
/* Do we have the complete box or are at MDAT */
|
||||||
gst_byte_reader_init (&reader, map.data, map.size);
|
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 ... */
|
GST_LOG_OBJECT (stream->pad,
|
||||||
dash_stream->isobmff_parser.current_start_offset =
|
"box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
|
||||||
dash_stream->isobmff_parser.current_offset;
|
G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
|
||||||
do {
|
dash_stream->isobmff_parser.current_offset +
|
||||||
dash_stream->isobmff_parser.current_fourcc = 0;
|
gst_byte_reader_get_pos (&reader) - header_size, size);
|
||||||
dash_stream->isobmff_parser.current_size = 0;
|
|
||||||
|
|
||||||
if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, &header_size,
|
if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MOOF) {
|
||||||
&size)) {
|
GstByteReader sub_reader;
|
||||||
break;
|
GstMoofBox *moof;
|
||||||
}
|
|
||||||
|
|
||||||
dash_stream->isobmff_parser.current_fourcc = fourcc;
|
gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size);
|
||||||
if (size == 0) {
|
moof = gst_isoff_moof_box_parse (&sub_reader);
|
||||||
dash_stream->isobmff_parser.current_size = -1;
|
/* TODO: Do something with this */
|
||||||
break;
|
gst_isoff_moof_box_free (moof);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
|
gst_byte_reader_skip (&reader, size - header_size);
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
/* Not even a single complete, non-mdat box, wait */
|
||||||
dash_stream->isobmff_parser.current_offset += gst_buffer_get_size (buffer);
|
dash_stream->isobmff_parser.current_size = 0;
|
||||||
if (outbuf)
|
gst_adapter_push (dash_stream->isobmff_adapter, buffer);
|
||||||
outbuf = gst_buffer_append (outbuf, buffer);
|
|
||||||
else
|
|
||||||
outbuf = buffer;
|
|
||||||
buffer = NULL;
|
|
||||||
|
|
||||||
GST_BUFFER_OFFSET (outbuf) = buffer_offset;
|
return NULL;
|
||||||
GST_BUFFER_OFFSET_END (outbuf) = buffer_offset + gst_buffer_get_size (outbuf);
|
|
||||||
|
|
||||||
return outbuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -1909,9 +1882,25 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
|
||||||
|
|
||||||
if (!gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
|
if (!gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
|
||||||
if (dash_stream->is_isobmff) {
|
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) {
|
||||||
if (!buffer)
|
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, 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);
|
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);
|
dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
|
||||||
|
|
||||||
if (dash_stream->is_isobmff) {
|
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) {
|
||||||
g_assert (buffer || !advance);
|
buffer = gst_dash_demux_parse_isobmff (demux, dash_stream, buffer);
|
||||||
g_assert (buffer
|
|
||||||
|| gst_adapter_available (dash_stream->sidx_adapter) == 0);
|
/* 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) {
|
if (buffer) {
|
||||||
|
@ -2041,13 +2045,27 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
|
||||||
dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
|
dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
|
||||||
|
|
||||||
if (dash_stream->is_isobmff) {
|
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)
|
if (buffer
|
||||||
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
|
&& (ret =
|
||||||
else
|
gst_adaptive_demux_stream_push_buffer (stream,
|
||||||
ret = GST_FLOW_OK;
|
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;
|
return ret;
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
/* gst_isoff_parse_box:
|
/* gst_isoff_parse_box:
|
||||||
* @reader:
|
* @reader:
|
||||||
* @type: type that was found at the current position
|
* @type: type that was found at the current position
|
||||||
|
@ -82,6 +81,272 @@ not_enough_data:
|
||||||
return FALSE;
|
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
|
void
|
||||||
gst_isoff_sidx_parser_init (GstSidxParser * parser)
|
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);
|
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_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_MDAT GST_MAKE_FOURCC('m','d','a','t')
|
||||||
#define GST_ISOFF_FOURCC_SIDX GST_MAKE_FOURCC('s','i','d','x')
|
#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
|
typedef struct _GstSidxBoxEntry
|
||||||
{
|
{
|
||||||
gboolean ref_type;
|
gboolean ref_type;
|
||||||
|
|
Loading…
Reference in a new issue