From 78d2d8598d12ab0487547b13909040472cec0ad7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 28 Sep 2009 16:11:35 +0200 Subject: [PATCH] qtmux: add mvex/trex in header if fragmented One "trex" is added per "trak". We don't support default values, but the "trex" box is mandatory. --- gst/qtmux/atoms.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++ gst/qtmux/atoms.h | 38 ++++++++++++++ gst/qtmux/gstqtmux.c | 26 +++++++-- 3 files changed, 205 insertions(+), 4 deletions(-) diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c index 29d1017..50020b3 100644 --- a/gst/qtmux/atoms.c +++ b/gst/qtmux/atoms.c @@ -1184,10 +1184,28 @@ atom_mvhd_clear (AtomMVHD * mvhd) } static void +atom_mehd_init (AtomMEHD * mehd) +{ + guint8 flags[3] = { 0, 0, 0 }; + + atom_full_init (&mehd->header, FOURCC_mehd, 0, 0, 1, flags); + mehd->fragment_duration = 0; +} + +static void +atom_mvex_init (AtomMVEX * mvex) +{ + atom_header_set (&mvex->header, FOURCC_mvex, 0, 0); + atom_mehd_init (&mvex->mehd); + mvex->trexs = NULL; +} + +static void atom_moov_init (AtomMOOV * moov, AtomsContext * context) { atom_header_set (&(moov->header), FOURCC_moov, 0, 0); atom_mvhd_init (&(moov->mvhd)); + atom_mvex_init (&(moov->mvex)); moov->udta = NULL; moov->traks = NULL; moov->context = *context; @@ -1202,6 +1220,28 @@ atom_moov_new (AtomsContext * context) return moov; } +static void +atom_trex_free (AtomTREX * trex) +{ + atom_full_clear (&trex->header); + g_free (trex); +} + +static void +atom_mvex_clear (AtomMVEX * mvex) +{ + GList *walker; + + atom_clear (&mvex->header); + walker = mvex->trexs; + while (walker) { + atom_trex_free ((AtomTREX *) walker->data); + walker = g_list_next (walker); + } + g_list_free (mvex->trexs); + mvex->trexs = NULL; +} + void atom_moov_free (AtomMOOV * moov) { @@ -1223,6 +1263,8 @@ atom_moov_free (AtomMOOV * moov) moov->udta = NULL; } + atom_mvex_clear (&moov->mvex); + g_free (moov); } @@ -2279,6 +2321,70 @@ atom_udta_copy_data (AtomUDTA * udta, guint8 ** buffer, guint64 * size, return *offset - original_offset; } +static guint64 +atom_mehd_copy_data (AtomMEHD * mehd, guint8 ** buffer, guint64 * size, + guint64 * offset) +{ + guint64 original_offset = *offset; + + if (!atom_full_copy_data (&mehd->header, buffer, size, offset)) { + return 0; + } + + prop_copy_uint64 (mehd->fragment_duration, buffer, size, offset); + + atom_write_size (buffer, size, offset, original_offset); + return *offset - original_offset; +} + +static guint64 +atom_trex_copy_data (AtomTREX * trex, guint8 ** buffer, guint64 * size, + guint64 * offset) +{ + guint64 original_offset = *offset; + + if (!atom_full_copy_data (&trex->header, buffer, size, offset)) { + return 0; + } + + prop_copy_uint32 (trex->track_ID, buffer, size, offset); + prop_copy_uint32 (trex->default_sample_description_index, buffer, size, + offset); + prop_copy_uint32 (trex->default_sample_duration, buffer, size, offset); + prop_copy_uint32 (trex->default_sample_size, buffer, size, offset); + prop_copy_uint32 (trex->default_sample_flags, buffer, size, offset); + + atom_write_size (buffer, size, offset, original_offset); + return *offset - original_offset; +} + +static guint64 +atom_mvex_copy_data (AtomMVEX * mvex, guint8 ** buffer, guint64 * size, + guint64 * offset) +{ + guint64 original_offset = *offset; + GList *walker; + + if (!atom_copy_data (&mvex->header, buffer, size, offset)) { + return 0; + } + + if (!atom_mehd_copy_data (&mvex->mehd, buffer, size, offset)) { + return 0; + } + + walker = g_list_first (mvex->trexs); + while (walker != NULL) { + if (!atom_trex_copy_data ((AtomTREX *) walker->data, buffer, size, offset)) { + return 0; + } + walker = g_list_next (walker); + } + + atom_write_size (buffer, size, offset, original_offset); + return *offset - original_offset; +} + guint64 atom_moov_copy_data (AtomMOOV * atom, guint8 ** buffer, guint64 * size, guint64 * offset) @@ -2306,6 +2412,12 @@ atom_moov_copy_data (AtomMOOV * atom, guint8 ** buffer, guint64 * size, } } + if (atom->fragmented) { + if (!atom_mvex_copy_data (&atom->mvex, buffer, size, offset)) { + return 0; + } + } + atom_write_size (buffer, size, offset, original_offset); return *offset - original_offset; } @@ -2488,6 +2600,32 @@ atom_moov_add_trak (AtomMOOV * moov, AtomTRAK * trak) moov->traks = g_list_append (moov->traks, trak); } +void +atom_moov_add_trex (AtomMOOV * moov, AtomTREX * trex) +{ + moov->mvex.trexs = g_list_append (moov->mvex.trexs, trex); +} + +AtomTREX * +atom_trex_new (AtomsContext * context, AtomTRAK * trak, + guint32 default_sample_description_index, + guint32 default_sample_duration, guint32 default_sample_size, + guint32 default_sample_flags) +{ + guint8 flags[3] = { 0, 0, 0 }; + AtomTREX *trex = g_new0 (AtomTREX, 1); + + atom_full_init (&trex->header, FOURCC_trex, 0, 0, 0, flags); + + trex->track_ID = trak->tkhd.track_ID; + trex->default_sample_description_index = default_sample_description_index; + trex->default_sample_duration = default_sample_duration; + trex->default_sample_size = default_sample_size; + trex->default_sample_flags = default_sample_flags; + + return trex; +} + static guint64 atom_trak_get_duration (AtomTRAK * trak) { @@ -2550,6 +2688,7 @@ atom_moov_update_duration (AtomMOOV * moov) traks = g_list_next (traks); } moov->mvhd.time_info.duration = duration; + moov->mvex.mehd.fragment_duration = duration; } static void @@ -2588,6 +2727,12 @@ atom_moov_set_64bits (AtomMOOV * moov, gboolean large_file) } void +atom_moov_set_fragmented (AtomMOOV * moov, gboolean fragmented) +{ + moov->fragmented = fragmented; +} + +void atom_stco64_chunks_add_offset (AtomSTCO64 * stco64, guint32 offset) { guint i; diff --git a/gst/qtmux/atoms.h b/gst/qtmux/atoms.h index 387904b..54e57bc 100644 --- a/gst/qtmux/atoms.h +++ b/gst/qtmux/atoms.h @@ -595,6 +595,35 @@ typedef struct _AtomTRAK gboolean is_h264; } AtomTRAK; +typedef struct _AtomTREX +{ + AtomFull header; + + guint32 track_ID; + guint32 default_sample_description_index; + guint32 default_sample_duration; + guint32 default_sample_size; + guint32 default_sample_flags; +} AtomTREX; + +typedef struct _AtomMEHD +{ + AtomFull header; + + guint64 fragment_duration; +} AtomMEHD; + + +typedef struct _AtomMVEX +{ + Atom header; + + AtomMEHD mehd; + + /* list of AtomTREX */ + GList *trexs; +} AtomMVEX; + typedef struct _AtomMOOV { /* style */ @@ -603,10 +632,13 @@ typedef struct _AtomMOOV Atom header; AtomMVHD mvhd; + AtomMVEX mvex; /* list of AtomTRAK */ GList *traks; AtomUDTA *udta; + + gboolean fragmented; } AtomMOOV; typedef struct _AtomWAVE @@ -662,14 +694,20 @@ void atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint64 chunk_offset, gboolean sync, gboolean do_pts, gint64 pts_offset); +AtomTREX* atom_trex_new (AtomsContext *context, AtomTRAK *trak, + guint32 default_sample_description_index, + guint32 default_sample_duration, guint32 default_sample_size, + guint32 default_sample_flags); AtomMOOV* atom_moov_new (AtomsContext *context); void atom_moov_free (AtomMOOV *moov); guint64 atom_moov_copy_data (AtomMOOV *atom, guint8 **buffer, guint64 *size, guint64* offset); void atom_moov_update_timescale (AtomMOOV *moov, guint32 timescale); void atom_moov_update_duration (AtomMOOV *moov); void atom_moov_set_64bits (AtomMOOV *moov, gboolean large_file); +void atom_moov_set_fragmented (AtomMOOV *moov, gboolean fragmented); void atom_moov_chunks_add_offset (AtomMOOV *moov, guint32 offset); void atom_moov_add_trak (AtomMOOV *moov, AtomTRAK *trak); +void atom_moov_add_trex (AtomMOOV *moov, AtomTREX *trex); guint64 atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer, guint64 * size, guint64 * offset); diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c index e128e16..5c79a3c 100644 --- a/gst/qtmux/gstqtmux.c +++ b/gst/qtmux/gstqtmux.c @@ -271,6 +271,23 @@ gst_qt_mux_pad_reset (GstQTPad * qtpad) qtpad->trak = NULL; } +static AtomTRAK * +gst_qt_mux_add_trak (GstQTMux * qtmux) +{ + AtomTRAK *trak; + + trak = atom_trak_new (qtmux->context); + atom_moov_add_trak (qtmux->moov, trak); + if (qtmux->fragmented) { + AtomTREX *trex; + + trex = atom_trex_new (qtmux->context, trak, 1, 0, 0, 0); + atom_moov_add_trex (qtmux->moov, trex); + } + + return trak; +} + /* * Takes GstQTMux back to its initial state */ @@ -331,8 +348,7 @@ gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc) for (walk = qtmux->sinkpads; walk; walk = g_slist_next (walk)) { GstQTPad *qtpad = (GstQTPad *) walk->data; - qtpad->trak = atom_trak_new (qtmux->context); - atom_moov_add_trak (qtmux->moov, qtpad->trak); + qtpad->trak = gst_qt_mux_add_trak (qtmux); } } } @@ -1460,6 +1476,8 @@ gst_qt_mux_stop_file (GstQTMux * qtmux) timescale); atom_moov_update_timescale (qtmux->moov, timescale); atom_moov_set_64bits (qtmux->moov, large_file); + atom_moov_set_fragmented (qtmux->moov, qtmux->fragmented); + atom_moov_update_duration (qtmux->moov); /* check for late streams */ @@ -2696,8 +2714,8 @@ gst_qt_mux_request_new_pad (GstElement * element, (GstCollectDataDestroyNotify) (gst_qt_mux_pad_reset)); /* set up pad */ gst_qt_mux_pad_reset (collect_pad); - collect_pad->trak = atom_trak_new (qtmux->context); - atom_moov_add_trak (qtmux->moov, collect_pad->trak); + + collect_pad->trak = gst_qt_mux_add_trak (qtmux); qtmux->sinkpads = g_slist_append (qtmux->sinkpads, collect_pad); /* set up pad functions */ -- 2.7.4