summaryrefslogtreecommitdiff
path: root/gst-libs/gst/isoff
diff options
context:
space:
mode:
authorSeungha Yang <sh.yang@lge.com>2017-05-25 18:14:09 +0900
committerReynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>2017-08-25 17:21:04 -0700
commit7d06ecb3a4f1344a1ea146c818c73a83ce137661 (patch)
treee1342a3d5afc088ff70f2b03629746f83f538277 /gst-libs/gst/isoff
parent4686dc47e4f145a2a50a57fa85fc6c0c5f8464d6 (diff)
downloadgstreamer-plugins-bad-7d06ecb3a4f1344a1ea146c818c73a83ce137661.tar.gz
isoff: Move isoff to gst-libs
Also rename unit test dash_isoff to isoff https://bugzilla.gnome.org/show_bug.cgi?id=777825
Diffstat (limited to 'gst-libs/gst/isoff')
-rw-r--r--gst-libs/gst/isoff/Makefile.am24
-rw-r--r--gst-libs/gst/isoff/gstisoff.c545
-rw-r--r--gst-libs/gst/isoff/gstisoff.h195
-rw-r--r--gst-libs/gst/isoff/meson.build22
4 files changed, 786 insertions, 0 deletions
diff --git a/gst-libs/gst/isoff/Makefile.am b/gst-libs/gst/isoff/Makefile.am
new file mode 100644
index 000000000..b99acaed6
--- /dev/null
+++ b/gst-libs/gst/isoff/Makefile.am
@@ -0,0 +1,24 @@
+lib_LTLIBRARIES = libgstisoff-@GST_API_VERSION@.la
+
+libgstisoff_@GST_API_VERSION@_la_SOURCES = \
+ gstisoff.c
+
+libgstisoff_@GST_API_VERSION@includedir = \
+ $(includedir)/gstreamer-@GST_API_VERSION@/gst/isoff
+
+libgstisoff_@GST_API_VERSION@include_HEADERS = \
+ gstisoff.h
+
+libgstisoff_@GST_API_VERSION@_la_CFLAGS = \
+ $(GST_PLUGINS_BAD_CFLAGS) \
+ -DGST_USE_UNSTABLE_API \
+ $(GST_CFLAGS)
+
+libgstisoff_@GST_API_VERSION@_la_LIBADD = \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS)
+
+libgstisoff_@GST_API_VERSION@_la_LDFLAGS = \
+ $(GST_LIB_LDFLAGS) \
+ $(GST_ALL_LDFLAGS) \
+ $(GST_LT_LDFLAGS)
diff --git a/gst-libs/gst/isoff/gstisoff.c b/gst-libs/gst/isoff/gstisoff.c
new file mode 100644
index 000000000..efb997407
--- /dev/null
+++ b/gst-libs/gst/isoff/gstisoff.c
@@ -0,0 +1,545 @@
+/*
+ * ISO File Format parsing library
+ *
+ * gstisoff.h
+ *
+ * Copyright (C) 2015 Samsung Electronics. All rights reserved.
+ * Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library (COPYING); if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstisoff.h"
+#include <gst/base/gstbytereader.h>
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY (gst_isoff_debug);
+#define GST_CAT_DEFAULT gst_isoff_debug
+
+static gboolean initialized = FALSE;
+
+#define INITIALIZE_DEBUG_CATEGORY \
+ if (!initialized) { \
+ GST_DEBUG_CATEGORY_INIT (gst_isoff_debug, "isoff", 0, \
+ "ISO File Format parsing library"); \
+ initialized = TRUE; \
+ }
+
+/* gst_isoff_parse_box_header:
+ * @reader:
+ * @type: type that was found at the current position
+ * @extended_type: (allow-none): extended type if type=='uuid'
+ * @header_size: (allow-none): size of the box header (type, extended type and size)
+ * @size: size of the complete box including type, extended type and size
+ *
+ * Advances the byte reader to the start of the box content. To skip
+ * over the complete box, skip size - header_size bytes.
+ *
+ * Returns: TRUE if a box header could be parsed, FALSE if more data is needed
+ */
+gboolean
+gst_isoff_parse_box_header (GstByteReader * reader, guint32 * type,
+ guint8 extended_type[16], guint * header_size, guint64 * size)
+{
+ guint header_start_offset;
+ guint32 size_field;
+
+ INITIALIZE_DEBUG_CATEGORY;
+ header_start_offset = gst_byte_reader_get_pos (reader);
+
+ if (gst_byte_reader_get_remaining (reader) < 8)
+ goto not_enough_data;
+
+ size_field = gst_byte_reader_get_uint32_be_unchecked (reader);
+ *type = gst_byte_reader_get_uint32_le_unchecked (reader);
+
+ if (size_field == 1) {
+ if (gst_byte_reader_get_remaining (reader) < 8)
+ goto not_enough_data;
+ *size = gst_byte_reader_get_uint64_be_unchecked (reader);
+ } else {
+ *size = size_field;
+ }
+
+ if (*type == GST_ISOFF_FOURCC_UUID) {
+ if (gst_byte_reader_get_remaining (reader) < 16)
+ goto not_enough_data;
+
+ if (extended_type)
+ memcpy (extended_type, gst_byte_reader_get_data_unchecked (reader, 16),
+ 16);
+ }
+
+ if (header_size)
+ *header_size = gst_byte_reader_get_pos (reader) - header_start_offset;
+
+ return TRUE;
+
+not_enough_data:
+ gst_byte_reader_set_pos (reader, header_start_offset);
+ 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;
+
+
+ INITIALIZE_DEBUG_CATEGORY;
+ 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)
+{
+ parser->status = GST_ISOFF_SIDX_PARSER_INIT;
+ parser->cumulative_entry_size = 0;
+ parser->sidx.entries = NULL;
+ parser->sidx.entries_count = 0;
+}
+
+void
+gst_isoff_sidx_parser_clear (GstSidxParser * parser)
+{
+ g_free (parser->sidx.entries);
+ memset (parser, 0, sizeof (*parser));
+
+ gst_isoff_sidx_parser_init (parser);
+}
+
+static void
+gst_isoff_parse_sidx_entry (GstSidxBoxEntry * entry, GstByteReader * reader)
+{
+ guint32 aux;
+
+ aux = gst_byte_reader_get_uint32_be_unchecked (reader);
+ entry->ref_type = aux >> 31;
+ entry->size = aux & 0x7FFFFFFF;
+ entry->duration = gst_byte_reader_get_uint32_be_unchecked (reader);
+ aux = gst_byte_reader_get_uint32_be_unchecked (reader);
+ entry->starts_with_sap = aux >> 31;
+ entry->sap_type = ((aux >> 28) & 0x7);
+ entry->sap_delta_time = aux & 0xFFFFFFF;
+}
+
+GstIsoffParserResult
+gst_isoff_sidx_parser_parse (GstSidxParser * parser,
+ GstByteReader * reader, guint * consumed)
+{
+ GstIsoffParserResult res = GST_ISOFF_PARSER_OK;
+ gsize remaining;
+
+ INITIALIZE_DEBUG_CATEGORY;
+ switch (parser->status) {
+ case GST_ISOFF_SIDX_PARSER_INIT:
+ /* Try again once we have enough data for the FullBox header */
+ if (gst_byte_reader_get_remaining (reader) < 4) {
+ gst_byte_reader_set_pos (reader, 0);
+ break;
+ }
+ parser->sidx.version = gst_byte_reader_get_uint8_unchecked (reader);
+ parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (reader);
+
+ parser->status = GST_ISOFF_SIDX_PARSER_HEADER;
+
+ case GST_ISOFF_SIDX_PARSER_HEADER:
+ remaining = gst_byte_reader_get_remaining (reader);
+ if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) {
+ break;
+ }
+
+ parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (reader);
+ parser->sidx.timescale = gst_byte_reader_get_uint32_be_unchecked (reader);
+ if (parser->sidx.version == 0) {
+ parser->sidx.earliest_pts =
+ gst_byte_reader_get_uint32_be_unchecked (reader);
+ parser->sidx.first_offset =
+ gst_byte_reader_get_uint32_be_unchecked (reader);
+ } else {
+ parser->sidx.earliest_pts =
+ gst_byte_reader_get_uint64_be_unchecked (reader);
+ parser->sidx.first_offset =
+ gst_byte_reader_get_uint64_be_unchecked (reader);
+ }
+ /* skip 2 reserved bytes */
+ gst_byte_reader_skip_unchecked (reader, 2);
+ parser->sidx.entries_count =
+ gst_byte_reader_get_uint16_be_unchecked (reader);
+
+ GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale);
+ GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts);
+ GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset);
+
+ parser->cumulative_pts =
+ gst_util_uint64_scale_int_round (parser->sidx.earliest_pts,
+ GST_SECOND, parser->sidx.timescale);
+
+ if (parser->sidx.entries_count) {
+ parser->sidx.entries =
+ g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count);
+ }
+ parser->sidx.entry_index = 0;
+
+ parser->status = GST_ISOFF_SIDX_PARSER_DATA;
+
+ case GST_ISOFF_SIDX_PARSER_DATA:
+ while (parser->sidx.entry_index < parser->sidx.entries_count) {
+ GstSidxBoxEntry *entry =
+ &parser->sidx.entries[parser->sidx.entry_index];
+
+ remaining = gst_byte_reader_get_remaining (reader);
+ if (remaining < 12)
+ break;
+
+ entry->offset = parser->cumulative_entry_size;
+ entry->pts = parser->cumulative_pts;
+ gst_isoff_parse_sidx_entry (entry, reader);
+ entry->duration = gst_util_uint64_scale_int_round (entry->duration,
+ GST_SECOND, parser->sidx.timescale);
+ parser->cumulative_entry_size += entry->size;
+ parser->cumulative_pts += entry->duration;
+
+ GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %"
+ GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %"
+ G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset,
+ GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration),
+ entry->size);
+
+ parser->sidx.entry_index++;
+ }
+
+ if (parser->sidx.entry_index == parser->sidx.entries_count)
+ parser->status = GST_ISOFF_SIDX_PARSER_FINISHED;
+ else
+ break;
+ case GST_ISOFF_SIDX_PARSER_FINISHED:
+ parser->sidx.entry_index = 0;
+ res = GST_ISOFF_PARSER_DONE;
+ break;
+ }
+
+ *consumed = gst_byte_reader_get_pos (reader);
+
+ return res;
+}
+
+GstIsoffParserResult
+gst_isoff_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer,
+ guint * consumed)
+{
+ GstIsoffParserResult res = GST_ISOFF_PARSER_OK;
+ GstByteReader reader;
+ GstMapInfo info;
+ guint32 fourcc;
+
+ INITIALIZE_DEBUG_CATEGORY;
+ if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
+ *consumed = 0;
+ return GST_ISOFF_PARSER_ERROR;
+ }
+
+ gst_byte_reader_init (&reader, info.data, info.size);
+
+ if (parser->status == GST_ISOFF_SIDX_PARSER_INIT) {
+ if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, NULL,
+ &parser->size))
+ goto done;
+
+ if (fourcc != GST_ISOFF_FOURCC_SIDX) {
+ res = GST_ISOFF_PARSER_UNEXPECTED;
+ gst_byte_reader_set_pos (&reader, 0);
+ goto done;
+ }
+
+ if (parser->size == 0) {
+ res = GST_ISOFF_PARSER_ERROR;
+ gst_byte_reader_set_pos (&reader, 0);
+ goto done;
+ }
+
+ /* Try again once we have enough data for the FullBox header */
+ if (gst_byte_reader_get_remaining (&reader) < 4) {
+ gst_byte_reader_set_pos (&reader, 0);
+ goto done;
+ }
+ }
+
+ res = gst_isoff_sidx_parser_parse (parser, &reader, consumed);
+
+done:
+ gst_buffer_unmap (buffer, &info);
+ return res;
+}
diff --git a/gst-libs/gst/isoff/gstisoff.h b/gst-libs/gst/isoff/gstisoff.h
new file mode 100644
index 000000000..ee160aa10
--- /dev/null
+++ b/gst-libs/gst/isoff/gstisoff.h
@@ -0,0 +1,195 @@
+/*
+ * ISO File Format parsing library
+ *
+ * gstisoff.h
+ *
+ * Copyright (C) 2015 Samsung Electronics. All rights reserved.
+ * Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library (COPYING); if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_ISOFF_H__
+#define __GST_ISOFF_H__
+
+#include <gst/gst.h>
+#include <gst/base/base.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GST_ISOFF_PARSER_OK,
+ GST_ISOFF_PARSER_DONE,
+ GST_ISOFF_PARSER_UNEXPECTED,
+ GST_ISOFF_PARSER_ERROR
+} GstIsoffParserResult;
+
+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;
+ guint32 size;
+ GstClockTime duration;
+ gboolean starts_with_sap;
+ guint8 sap_type;
+ guint32 sap_delta_time;
+
+ guint64 offset;
+ GstClockTime pts;
+} GstSidxBoxEntry;
+
+typedef struct _GstSidxBox
+{
+ guint8 version;
+ guint32 flags;
+
+ guint32 ref_id;
+ guint32 timescale;
+ guint64 earliest_pts;
+ guint64 first_offset;
+
+ gint entry_index;
+ gint entries_count;
+
+ GstSidxBoxEntry *entries;
+} GstSidxBox;
+
+typedef enum _GstSidxParserStatus
+{
+ GST_ISOFF_SIDX_PARSER_INIT,
+ GST_ISOFF_SIDX_PARSER_HEADER,
+ GST_ISOFF_SIDX_PARSER_DATA,
+ GST_ISOFF_SIDX_PARSER_FINISHED
+} GstSidxParserStatus;
+
+typedef struct _GstSidxParser
+{
+ GstSidxParserStatus status;
+
+ guint64 size;
+ guint64 cumulative_entry_size;
+ guint64 cumulative_pts;
+
+ GstSidxBox sidx;
+} GstSidxParser;
+
+void gst_isoff_sidx_parser_init (GstSidxParser * parser);
+void gst_isoff_sidx_parser_clear (GstSidxParser * parser);
+GstIsoffParserResult gst_isoff_sidx_parser_parse (GstSidxParser * parser, GstByteReader * reader, guint * consumed);
+GstIsoffParserResult gst_isoff_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buf, guint * consumed);
+
+G_END_DECLS
+
+#endif /* __GST_ISOFF_H__ */
diff --git a/gst-libs/gst/isoff/meson.build b/gst-libs/gst/isoff/meson.build
new file mode 100644
index 000000000..97acd0ea1
--- /dev/null
+++ b/gst-libs/gst/isoff/meson.build
@@ -0,0 +1,22 @@
+isoff_sources = [
+ 'gstisoff.c',
+]
+isoff_headers = [
+ 'gstisoff.h',
+]
+install_headers(isoff_headers, subdir : 'gstreamer-1.0/gst/isoff')
+
+gstisoff = library('gstisoff-' + api_version,
+ isoff_sources,
+ c_args : gst_plugins_bad_args + [ '-DGST_USE_UNSTABLE_API' ],
+ include_directories : [configinc, libsinc],
+ version : libversion,
+ soversion : soversion,
+ install : true,
+ dependencies : [gstbase_dep],
+ vs_module_defs: vs_module_defs_dir + 'libgstisoff.def',
+)
+
+gstisoff_dep = declare_dependency(link_with : gstisoff,
+ include_directories : [libsinc],
+ dependencies : [gstbase_dep])