qtmux: add mvex/trex in header if fragmented
authorMarc-André Lureau <mlureau@flumotion.com>
Mon, 28 Sep 2009 14:11:35 +0000 (16:11 +0200)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Fri, 19 Nov 2010 18:21:36 +0000 (19:21 +0100)
One "trex" is added per "trak". We don't support default values,
but the "trex" box is mandatory.

gst/qtmux/atoms.c
gst/qtmux/atoms.h
gst/qtmux/gstqtmux.c

index 29d1017..50020b3 100644 (file)
@@ -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;
index 387904b..54e57bc 100644 (file)
@@ -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);
index e128e16..5c79a3c 100644 (file)
@@ -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 */