Commit 3db9152e authored by Seungha Yang's avatar Seungha Yang Committed by Reynaldo H. Verdejo Pinochet

isoff: Add parsing moov and tfdt

To extract isobmff level timestamp, moov and tfdt parsing is required.

https://bugzilla.gnome.org/show_bug.cgi?id=777825
parent 7d06ecb3
......@@ -231,6 +231,34 @@ error:
return FALSE;
}
static gboolean
gst_isoff_tfdt_box_parse (GstTfdtBox * tfdt, GstByteReader * reader)
{
gint8 version;
memset (tfdt, 0, sizeof (*tfdt));
if (gst_byte_reader_get_remaining (reader) < 4)
return FALSE;
version = gst_byte_reader_get_uint8_unchecked (reader);
if (!gst_byte_reader_skip (reader, 3))
return FALSE;
if (version == 1) {
if (!gst_byte_reader_get_uint64_be (reader, &tfdt->decode_time))
return FALSE;
} else {
guint32 dec_time = 0;
if (!gst_byte_reader_get_uint32_be (reader, &dec_time))
return FALSE;
tfdt->decode_time = dec_time;
}
return TRUE;
}
static gboolean
gst_isoff_traf_box_parse (GstTrafBox * traf, GstByteReader * reader)
{
......@@ -241,10 +269,13 @@ gst_isoff_traf_box_parse (GstTrafBox * traf, GstByteReader * reader)
g_array_set_clear_func (traf->trun,
(GDestroyNotify) gst_isoff_trun_box_clear);
traf->tfdt.decode_time = GST_CLOCK_TIME_NONE;
while (gst_byte_reader_get_remaining (reader) > 0) {
guint32 fourcc;
guint header_size;
guint64 size;
GstByteReader sub_reader;
if (!gst_isoff_parse_box_header (reader, &fourcc, NULL, &header_size,
&size))
......@@ -254,8 +285,6 @@ gst_isoff_traf_box_parse (GstTrafBox * traf, GstByteReader * reader)
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))
......@@ -263,8 +292,14 @@ gst_isoff_traf_box_parse (GstTrafBox * traf, GstByteReader * reader)
had_tfhd = TRUE;
break;
}
case GST_ISOFF_FOURCC_TFDT:{
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_tfdt_box_parse (&traf->tfdt, &sub_reader))
goto error;
break;
}
case GST_ISOFF_FOURCC_TRUN:{
GstByteReader sub_reader;
GstTrunBox trun;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
......@@ -297,6 +332,7 @@ gst_isoff_moof_box_parse (GstByteReader * reader)
{
GstMoofBox *moof;
gboolean had_mfhd = FALSE;
GstByteReader sub_reader;
INITIALIZE_DEBUG_CATEGORY;
......@@ -318,8 +354,6 @@ gst_isoff_moof_box_parse (GstByteReader * reader)
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))
......@@ -328,7 +362,6 @@ gst_isoff_moof_box_parse (GstByteReader * reader)
break;
}
case GST_ISOFF_FOURCC_TRAF:{
GstByteReader sub_reader;
GstTrafBox traf;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
......@@ -362,6 +395,239 @@ gst_isoff_moof_box_free (GstMoofBox * moof)
g_free (moof);
}
static gboolean
gst_isoff_mdhd_box_parse (GstMdhdBox * mdhd, GstByteReader * reader)
{
guint8 version;
memset (mdhd, 0, sizeof (*mdhd));
if (gst_byte_reader_get_remaining (reader) < 4)
return FALSE;
version = gst_byte_reader_get_uint8_unchecked (reader);
if (!gst_byte_reader_skip (reader, 3))
return FALSE;
/* skip {creation, modification}_time, we don't have interest */
if (version == 1) {
if (!gst_byte_reader_skip (reader, 16))
return FALSE;
} else {
if (!gst_byte_reader_skip (reader, 8))
return FALSE;
}
if (!gst_byte_reader_get_uint32_be (reader, &mdhd->timescale))
return FALSE;
return TRUE;
}
static gboolean
gst_isoff_hdlr_box_parse (GstHdlrBox * hdlr, GstByteReader * reader)
{
memset (hdlr, 0, sizeof (*hdlr));
if (gst_byte_reader_get_remaining (reader) < 4)
return FALSE;
/* version & flag */
if (!gst_byte_reader_skip (reader, 4))
return FALSE;
/* pre_defined = 0 */
if (!gst_byte_reader_skip (reader, 4))
return FALSE;
if (!gst_byte_reader_get_uint32_le (reader, &hdlr->handler_type))
return FALSE;
return TRUE;
}
static gboolean
gst_isoff_mdia_box_parse (GstMdiaBox * mdia, GstByteReader * reader)
{
gboolean had_mdhd = FALSE, had_hdlr = FALSE;
while (gst_byte_reader_get_remaining (reader) > 0) {
guint32 fourcc;
guint header_size;
guint64 size;
GstByteReader sub_reader;
if (!gst_isoff_parse_box_header (reader, &fourcc, NULL, &header_size,
&size))
return FALSE;
if (gst_byte_reader_get_remaining (reader) < size - header_size)
return FALSE;
switch (fourcc) {
case GST_ISOFF_FOURCC_MDHD:{
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_mdhd_box_parse (&mdia->mdhd, &sub_reader))
return FALSE;
had_mdhd = TRUE;
break;
}
case GST_ISOFF_FOURCC_HDLR:{
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_hdlr_box_parse (&mdia->hdlr, &sub_reader))
return FALSE;
had_hdlr = TRUE;
break;
}
default:
gst_byte_reader_skip (reader, size - header_size);
break;
}
}
if (!had_mdhd || !had_hdlr)
return FALSE;
return TRUE;
}
static gboolean
gst_isoff_tkhd_box_parse (GstTkhdBox * tkhd, GstByteReader * reader)
{
guint8 version;
memset (tkhd, 0, sizeof (*tkhd));
if (gst_byte_reader_get_remaining (reader) < 4)
return FALSE;
if (!gst_byte_reader_get_uint8 (reader, &version))
return FALSE;
if (!gst_byte_reader_skip (reader, 3))
return FALSE;
/* skip {creation, modification}_time, we don't have interest */
if (version == 1) {
if (!gst_byte_reader_skip (reader, 16))
return FALSE;
} else {
if (!gst_byte_reader_skip (reader, 8))
return FALSE;
}
if (!gst_byte_reader_get_uint32_be (reader, &tkhd->track_id))
return FALSE;
return TRUE;
}
static gboolean
gst_isoff_trak_box_parse (GstTrakBox * trak, GstByteReader * reader)
{
gboolean had_mdia = FALSE, had_tkhd = FALSE;
while (gst_byte_reader_get_remaining (reader) > 0) {
guint32 fourcc;
guint header_size;
guint64 size;
GstByteReader sub_reader;
if (!gst_isoff_parse_box_header (reader, &fourcc, NULL, &header_size,
&size))
return FALSE;
if (gst_byte_reader_get_remaining (reader) < size - header_size)
return FALSE;
switch (fourcc) {
case GST_ISOFF_FOURCC_MDIA:{
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_mdia_box_parse (&trak->mdia, &sub_reader))
return FALSE;
had_mdia = TRUE;
break;
}
case GST_ISOFF_FOURCC_TKHD:{
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_tkhd_box_parse (&trak->tkhd, &sub_reader))
return FALSE;
had_tkhd = TRUE;
break;
}
default:
gst_byte_reader_skip (reader, size - header_size);
break;
}
}
if (!had_tkhd || !had_mdia)
return FALSE;
return TRUE;
}
GstMoovBox *
gst_isoff_moov_box_parse (GstByteReader * reader)
{
GstMoovBox *moov;
gboolean had_trak = FALSE;
moov = g_new0 (GstMoovBox, 1);
moov->trak = g_array_new (FALSE, FALSE, sizeof (GstTrakBox));
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_TRAK:{
GstByteReader sub_reader;
GstTrakBox trak;
gst_byte_reader_get_sub_reader (reader, &sub_reader,
size - header_size);
if (!gst_isoff_trak_box_parse (&trak, &sub_reader))
goto error;
had_trak = TRUE;
g_array_append_val (moov->trak, trak);
break;
}
default:
gst_byte_reader_skip (reader, size - header_size);
break;
}
}
if (!had_trak)
goto error;
return moov;
error:
gst_isoff_moov_box_free (moov);
return NULL;
}
void
gst_isoff_moov_box_free (GstMoovBox * moov)
{
g_array_free (moov->trak, TRUE);
g_free (moov);
}
void
gst_isoff_sidx_parser_init (GstSidxParser * parser)
{
......
......@@ -45,9 +45,20 @@ gboolean gst_isoff_parse_box_header (GstByteReader * reader, guint32 * type, gui
#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_TFDT GST_MAKE_FOURCC('t','f','d','t')
#define GST_ISOFF_FOURCC_MDAT GST_MAKE_FOURCC('m','d','a','t')
#define GST_ISOFF_FOURCC_MOOV GST_MAKE_FOURCC('m','o','o','v')
#define GST_ISOFF_FOURCC_TRAK GST_MAKE_FOURCC('t','r','a','k')
#define GST_ISOFF_FOURCC_TKHD GST_MAKE_FOURCC('t','k','h','d')
#define GST_ISOFF_FOURCC_MDIA GST_MAKE_FOURCC('m','d','i','a')
#define GST_ISOFF_FOURCC_MDHD GST_MAKE_FOURCC('m','d','h','d')
#define GST_ISOFF_FOURCC_HDLR GST_MAKE_FOURCC('h','d','l','r')
#define GST_ISOFF_FOURCC_SIDX GST_MAKE_FOURCC('s','i','d','x')
/* handler type */
#define GST_ISOFF_FOURCC_SOUN GST_MAKE_FOURCC('s','o','u','n')
#define GST_ISOFF_FOURCC_VIDE GST_MAKE_FOURCC('v','i','d','e')
#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)
......@@ -122,9 +133,15 @@ typedef struct _GstTrunSample
} sample_composition_time_offset;
} GstTrunSample;
typedef struct _GstTdftBox
{
guint64 decode_time;
} GstTfdtBox;
typedef struct _GstTrafBox
{
GstTfhdBox tfhd;
GstTfdtBox tfdt;
GArray *trun;
} GstTrafBox;
......@@ -137,6 +154,41 @@ typedef struct _GstMoofBox
GstMoofBox * gst_isoff_moof_box_parse (GstByteReader *reader);
void gst_isoff_moof_box_free (GstMoofBox *moof);
typedef struct _GstTkhdBox
{
guint32 track_id;
} GstTkhdBox;
typedef struct _GstMdhdBox
{
guint32 timescale;
} GstMdhdBox;
typedef struct _GstHdlrBox
{
guint32 handler_type;
} GstHdlrBox;
typedef struct _GstMdiaBox
{
GstMdhdBox mdhd;
GstHdlrBox hdlr;
} GstMdiaBox;
typedef struct _GstTrakBox
{
GstTkhdBox tkhd;
GstMdiaBox mdia;
} GstTrakBox;
typedef struct _GstMoovBox
{
GArray *trak;
} GstMoovBox;
GstMoovBox * gst_isoff_moov_box_parse (GstByteReader *reader);
void gst_isoff_moov_box_free (GstMoovBox *moov);
typedef struct _GstSidxBoxEntry
{
gboolean ref_type;
......
......@@ -180,12 +180,110 @@ GST_START_TEST (isoff_moof_parse)
GST_END_TEST;
GST_START_TEST (isoff_moof_parse_with_tfdt)
{
/* INDENT-ON */
GstByteReader reader = GST_BYTE_READER_INIT (seg_2_m4f, sizeof (seg_2_m4f));
guint32 type;
guint8 extended_type[16];
guint header_size;
guint64 size;
GstMoofBox *moof;
GstTrafBox *traf;
GstTrunBox *trun;
guint i;
fail_unless (gst_isoff_parse_box_header (&reader, &type, extended_type,
&header_size, &size));
fail_unless (type == GST_ISOFF_FOURCC_MOOF);
fail_unless_equals_int (header_size, 8);
fail_unless_equals_uint64 (size, seg_2_m4f_len);
moof = gst_isoff_moof_box_parse (&reader);
fail_unless (moof != NULL);
fail_unless_equals_int (moof->mfhd.sequence_number, 4);
fail_unless_equals_int (moof->traf->len, 1);
traf = &g_array_index (moof->traf, GstTrafBox, 0);
fail_unless_equals_int (traf->tfhd.version, 0);
fail_unless_equals_int (traf->tfhd.flags,
GST_TFHD_FLAGS_DEFAULT_BASE_IS_MOOF);
fail_unless_equals_int (traf->tfhd.track_id, 2);
fail_unless_equals_uint64 (traf->tfhd.base_data_offset, 0);
fail_unless_equals_int (traf->tfhd.sample_description_index, 0);
fail_unless_equals_int (traf->tfhd.default_sample_duration, 0);
fail_unless_equals_int (traf->tfhd.default_sample_size, 0);
fail_unless_equals_int (traf->tfhd.default_sample_flags, 0);
fail_unless_equals_uint64 (traf->tfdt.decode_time, 132096);
fail_unless_equals_int (traf->trun->len, 1);
trun = &g_array_index (traf->trun, GstTrunBox, 0);
fail_unless_equals_int (trun->version, 0);
fail_unless_equals_int (trun->flags,
GST_TRUN_FLAGS_SAMPLE_SIZE_PRESENT |
GST_TRUN_FLAGS_SAMPLE_DURATION_PRESENT |
GST_TRUN_FLAGS_DATA_OFFSET_PRESENT);
fail_unless_equals_int (trun->sample_count, 129);
fail_unless_equals_int (trun->data_offset, size + header_size);
fail_unless_equals_int (trun->first_sample_flags, 0);
fail_unless_equals_int (trun->samples->len, 129);
for (i = 0; i < 129; i++) {
GstTrunSample *sample = &g_array_index (trun->samples, GstTrunSample, i);
fail_unless_equals_int (sample->sample_duration, seg_sample_duration);
fail_unless_equals_int (sample->sample_flags, 0x00000000);
fail_unless_equals_int (sample->sample_size, seg_2_sample_sizes[i]);
}
gst_isoff_moof_box_free (moof);
}
GST_END_TEST;
GST_START_TEST (isoff_moov_parse)
{
/* INDENT-ON */
GstByteReader reader = GST_BYTE_READER_INIT (init_mp4, sizeof (init_mp4));
guint32 type;
guint8 extended_type[16];
guint header_size;
guint64 size;
GstMoovBox *moov;
GstTrakBox *trak;
fail_unless (gst_isoff_parse_box_header (&reader, &type, extended_type,
&header_size, &size));
fail_unless (type == GST_ISOFF_FOURCC_MOOV);
fail_unless_equals_int (header_size, 8);
fail_unless_equals_uint64 (size, sizeof (init_mp4));
moov = gst_isoff_moov_box_parse (&reader);
fail_unless (moov != NULL);
fail_unless_equals_int (moov->trak->len, 1);
trak = &g_array_index (moov->trak, GstTrakBox, 0);
fail_unless_equals_int (trak->tkhd.track_id, 2);
fail_unless (trak->mdia.hdlr.handler_type, GST_ISOFF_FOURCC_SOUN);
fail_unless_equals_int (trak->mdia.mdhd.timescale, seg_timescale);
gst_isoff_moov_box_free (moov);
}
GST_END_TEST;
static Suite *
dash_isoff_suite (void)
{
Suite *s = suite_create ("isoff");
TCase *tc_isoff_box = tcase_create ("isoff-box-parsing");
TCase *tc_moof = tcase_create ("moof");
TCase *tc_moov = tcase_create ("moov");
tcase_add_test (tc_isoff_box, isoff_box_header_minimal);
tcase_add_test (tc_isoff_box, isoff_box_header_long_size);
......@@ -194,10 +292,13 @@ dash_isoff_suite (void)
suite_add_tcase (s, tc_isoff_box);
tcase_add_test (tc_moof, isoff_moof_parse);
tcase_add_test (tc_moof, isoff_moof_parse_with_tfdt);
suite_add_tcase (s, tc_moof);
tcase_add_test (tc_moov, isoff_moov_parse);
suite_add_tcase (s, tc_moov);
return s;
}
......
......@@ -110,4 +110,290 @@ static const guint8 moof1[] = {
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* Fragments taken from http://www.bok.net/dash/tears_of_steel/cleartext/stream.mpd
*
* Audio stream (aac)
* Header (moov only) + first fragment (moof only) + second fragment (moof only)
*/
/* http://www.bok.net/dash/tears_of_steel/cleartext/audio/en/init.mp4 (except for ftyp box) */
static const guint8 init_mp4[] = {
0x00, 0x00, 0x02, 0x50, 0x6d, 0x6f, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x6c,
0x6d, 0x76, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x0b, 0x33, 0xd7,
0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xa4,
0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c, 0x74, 0x6b, 0x68, 0x64,
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x33, 0xbc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x40, 0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20,
0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x44, 0x00, 0x00, 0x00, 0x00,
0x15, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x68, 0x64, 0x6c, 0x72,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x65, 0x6e, 0x74, 0x6f, 0x34, 0x20, 0x53, 0x6f, 0x75, 0x6e, 0x64,
0x20, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00,
0xe3, 0x6d, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x10, 0x73, 0x6d, 0x68,
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x64, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65,
0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0c, 0x75, 0x72, 0x6c, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xa7, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x00, 0x00, 0x5b, 0x73, 0x74, 0x73,
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x4b, 0x6d, 0x70, 0x34, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0xac, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
0x27, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00, 0x03, 0x19, 0x00,
0x00, 0x00, 0x04, 0x11, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf4,
0x01, 0x00, 0x01, 0xf4, 0x01, 0x05, 0x02, 0x12, 0x10, 0x06, 0x01, 0x02,
0x00, 0x00, 0x00, 0x14, 0x73, 0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x73, 0x74, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x63, 0x6f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
0x6d, 0x76, 0x65, 0x78, 0x00, 0x00, 0x00, 0x10, 0x6d, 0x65, 0x68, 0x64,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x33, 0xd7, 0x00, 0x00, 0x00, 0x20,
0x74, 0x72, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
/* http://www.bok.net/dash/tears_of_steel/cleartext/audio/en/seg-1.m4f (except for mdat box) */
static const guint8 seg_1_m4f[] = {
0x00, 0x00, 0x04, 0x60, 0x6d, 0x6f, 0x6f, 0x66, 0x00, 0x00, 0x00, 0x10,
0x6d, 0x66, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x04, 0x48, 0x74, 0x72, 0x61, 0x66, 0x00