[vlc-commits] mux: mp4: rework mux helper for better abstraction

Francois Cartegnie git at videolan.org
Fri Oct 26 17:53:14 CEST 2018


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Oct 25 22:34:58 2018 +0200| [be35a870d7ae4592e1f47484b03f82da529f2213] | committer: Francois Cartegnie

mux: mp4: rework mux helper for better abstraction

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=be35a870d7ae4592e1f47484b03f82da529f2213
---

 .../demux/smooth/playlist/ForgedInitSegment.cpp    |  92 ++---
 modules/mux/mp4/libmp4mux.c                        | 269 ++++++++++-----
 modules/mux/mp4/libmp4mux.h                        |  42 ++-
 modules/mux/mp4/mp4.c                              | 382 ++++++++++-----------
 4 files changed, 446 insertions(+), 339 deletions(-)

diff --git a/modules/demux/smooth/playlist/ForgedInitSegment.cpp b/modules/demux/smooth/playlist/ForgedInitSegment.cpp
index 631e580ac9..8375e0a243 100644
--- a/modules/demux/smooth/playlist/ForgedInitSegment.cpp
+++ b/modules/demux/smooth/playlist/ForgedInitSegment.cpp
@@ -210,16 +210,10 @@ void ForgedInitSegment::setLanguage(const std::string &lang)
 block_t * ForgedInitSegment::buildMoovBox()
 {
     const Timescale &trackTimescale = inheritTimescale();
-    mp4mux_trackinfo_t trackinfo;
-    mp4mux_trackinfo_Init(&trackinfo,
-                          0x01, /* Will always be 1st and unique track; tfhd patched on block read */
-                          (uint32_t) trackTimescale);
-    trackinfo.i_read_duration = duration.Get();
-    trackinfo.i_trex_default_length = 1;
-    trackinfo.i_trex_default_size = 1;
-
-    es_format_Init(&trackinfo.fmt, es_type, vlc_fourcc_GetCodec(es_type, fourcc));
-    trackinfo.fmt.i_original_fourcc = fourcc;
+
+    es_format_t fmt;
+    es_format_Init(&fmt, es_type, vlc_fourcc_GetCodec(es_type, fourcc));
+    fmt.i_original_fourcc = fourcc;
     switch(es_type)
     {
         case VIDEO_ES:
@@ -227,44 +221,44 @@ block_t * ForgedInitSegment::buildMoovBox()
                 fourcc == VLC_FOURCC( 'A', 'V', 'C', 'B' ) ||
                 fourcc == VLC_FOURCC( 'H', '2', '6', '4' ) )
             {
-                trackinfo.fmt.i_codec = VLC_CODEC_H264;
+                fmt.i_codec = VLC_CODEC_H264;
             }
             else if( fourcc == VLC_FOURCC( 'W', 'V', 'C', '1' ) )
             {
-                trackinfo.fmt.i_codec = VLC_CODEC_VC1;
-//                trackinfo.fmt.video.i_bits_per_pixel = 0x18; // No clue why this was set in smooth streamfilter
+                fmt.i_codec = VLC_CODEC_VC1;
+//                fmt.video.i_bits_per_pixel = 0x18; // No clue why this was set in smooth streamfilter
             }
 
-            trackinfo.fmt.video.i_width = width;
-            trackinfo.fmt.video.i_height = height;
-            trackinfo.fmt.video.i_visible_width = width;
-            trackinfo.fmt.video.i_visible_height = height;
+            fmt.video.i_width = width;
+            fmt.video.i_height = height;
+            fmt.video.i_visible_width = width;
+            fmt.video.i_visible_height = height;
 
             if(i_extradata && extradata)
             {
-                trackinfo.fmt.p_extra = malloc(i_extradata);
-                if(trackinfo.fmt.p_extra)
+                fmt.p_extra = malloc(i_extradata);
+                if(fmt.p_extra)
                 {
-                    memcpy(trackinfo.fmt.p_extra, extradata, i_extradata);
-                    trackinfo.fmt.i_extra = i_extradata;
+                    memcpy(fmt.p_extra, extradata, i_extradata);
+                    fmt.i_extra = i_extradata;
                 }
             }
             break;
 
         case AUDIO_ES:
-            trackinfo.fmt.audio.i_channels = formatex.nChannels;
-            trackinfo.fmt.audio.i_rate = formatex.nSamplesPerSec;
-            trackinfo.fmt.audio.i_bitspersample = formatex.wBitsPerSample;
-            trackinfo.fmt.audio.i_blockalign = formatex.nBlockAlign;
-            trackinfo.fmt.i_bitrate = formatex.nAvgBytesPerSec * 8; // FIXME (use bitrate) ?
+            fmt.audio.i_channels = formatex.nChannels;
+            fmt.audio.i_rate = formatex.nSamplesPerSec;
+            fmt.audio.i_bitspersample = formatex.wBitsPerSample;
+            fmt.audio.i_blockalign = formatex.nBlockAlign;
+            fmt.i_bitrate = formatex.nAvgBytesPerSec * 8; // FIXME (use bitrate) ?
 
             if(i_extradata && extradata)
             {
-                trackinfo.fmt.p_extra = malloc(i_extradata);
-                if(trackinfo.fmt.p_extra)
+                fmt.p_extra = malloc(i_extradata);
+                if(fmt.p_extra)
                 {
-                    memcpy(trackinfo.fmt.p_extra, extradata, i_extradata);
-                    trackinfo.fmt.i_extra = i_extradata;
+                    memcpy(fmt.p_extra, extradata, i_extradata);
+                    fmt.i_extra = i_extradata;
                 }
             }
             break;
@@ -277,28 +271,36 @@ block_t * ForgedInitSegment::buildMoovBox()
     }
 
     if(!language.empty())
-        trackinfo.fmt.psz_language = strdup(language.c_str());
+        fmt.psz_language = strdup(language.c_str());
 
-    mp4mux_trackinfo_t *p_tracks = &trackinfo;
     bo_t *box = NULL;
-
-    if(mp4mux_CanMux( NULL, &trackinfo.fmt, VLC_FOURCC('s', 'm', 'o', 'o'), true ))
-       box = mp4mux_GetMoovBox(NULL, &p_tracks, 1,
-                               trackTimescale.ToTime(duration.Get()),
-                               true, false, false, false);
-
-    mp4mux_trackinfo_Clear(&trackinfo);
-
-    block_t *moov = NULL;
-    if(box)
+    mp4mux_handle_t *muxh = mp4mux_New(FRAGMENTED);
+    if(muxh)
     {
-        moov = box->b;
-        free(box);
+        if(mp4mux_CanMux(NULL, &fmt, VLC_FOURCC('s', 'm', 'o', 'o'), true ))
+        {
+            mp4mux_trackinfo_t *p_track = mp4mux_track_Add(muxh,
+                                     0x01, /* Will always be 1st and unique track; tfhd patched on block read */
+                                     &fmt, (uint32_t) trackTimescale);
+            if(p_track)
+            {
+                p_track->i_read_duration = duration.Get();
+                p_track->i_trex_default_length = 1;
+                p_track->i_trex_default_size = 1;
+            }
+        }
+
+        box = mp4mux_GetMoov(muxh, NULL, trackTimescale.ToTime(duration.Get()));
+        mp4mux_Delete(muxh);
     }
+    es_format_Clean(&fmt);
 
-    if(!moov)
+    if(!box)
         return NULL;
 
+    block_t *moov = box->b;
+    free(box);
+
     vlc_fourcc_t extra[] = {MAJOR_isom, VLC_FOURCC('p','i','f','f'), VLC_FOURCC('i','s','o','2'), VLC_FOURCC('s','m','o','o')};
     box = mp4mux_GetFtyp(VLC_FOURCC('i','s','m','l'), 1, extra, ARRAY_SIZE(extra));
 
diff --git a/modules/mux/mp4/libmp4mux.c b/modules/mux/mp4/libmp4mux.c
index a78f8d8794..7cfea5dde3 100644
--- a/modules/mux/mp4/libmp4mux.c
+++ b/modules/mux/mp4/libmp4mux.c
@@ -34,36 +34,145 @@
 #include <vlc_es.h>
 #include <vlc_iso_lang.h>
 #include <vlc_bits.h>
+#include <vlc_arrays.h>
 #include <vlc_text_style.h>
 #include <assert.h>
 #include <time.h>
 
-bool mp4mux_trackinfo_Init(mp4mux_trackinfo_t *p_stream, unsigned i_id,
-                           uint32_t i_timescale)
+struct mp4mux_handle_t
+{
+    unsigned options;
+    vlc_array_t tracks;
+};
+
+static bool mp4mux_trackinfo_Init(mp4mux_trackinfo_t *p_stream, unsigned i_id,
+                                  uint32_t i_timescale)
 {
     memset(p_stream, 0, sizeof(*p_stream));
     p_stream->i_track_id = i_id;
 
     p_stream->i_timescale   = i_timescale;
-    p_stream->i_entry_count = 0;
-    p_stream->i_entry_max   = 1000;
-
-    p_stream->entry         = calloc(p_stream->i_entry_max, sizeof(mp4mux_entry_t));
-    if(!p_stream->entry)
-        return false;
+    es_format_Init(&p_stream->fmt, 0, 0);
 
     return true;
 }
 
-void mp4mux_trackinfo_Clear(mp4mux_trackinfo_t *p_stream)
+static void mp4mux_trackinfo_Clear(mp4mux_trackinfo_t *p_stream)
 {
     es_format_Clean(&p_stream->fmt);
     if (p_stream->a52_frame)
         block_Release(p_stream->a52_frame);
-    free(p_stream->entry);
+    free(p_stream->samples);
     free(p_stream->p_edits);
 }
 
+mp4mux_trackinfo_t * mp4mux_track_Add(mp4mux_handle_t *h, unsigned id,
+                                      const es_format_t *fmt, uint32_t timescale)
+{
+    mp4mux_trackinfo_t *t = malloc(sizeof(*t));
+    if(!mp4mux_trackinfo_Init(t, 0, 0))
+    {
+        free(t);
+        return NULL;
+    }
+    t->i_track_id = id;
+    t->i_timescale = timescale;
+    t->i_firstdts = VLC_TICK_INVALID;
+    es_format_Init(&t->fmt, fmt->i_cat, fmt->i_codec);
+    es_format_Copy(&t->fmt, fmt);
+    vlc_array_append(&h->tracks, t);
+    return t;
+}
+
+bool mp4mux_track_AddEdit(mp4mux_trackinfo_t *t, const mp4mux_edit_t *p_newedit)
+{
+    mp4mux_edit_t *p_realloc = realloc( t->p_edits, sizeof(mp4mux_edit_t) *
+                                       (t->i_edits_count + 1) );
+    if(unlikely(!p_realloc))
+        return false;
+
+    t->p_edits = p_realloc;
+    t->p_edits[t->i_edits_count++] = *p_newedit;
+
+    return true;
+}
+
+const mp4mux_edit_t *mp4mux_track_GetLastEdit(const mp4mux_trackinfo_t *t)
+{
+    if(t->i_edits_count)
+        return &t->p_edits[t->i_edits_count - 1];
+    else return NULL;
+}
+
+void mp4mux_track_DebugEdits(vlc_object_t *obj, const mp4mux_trackinfo_t *t)
+{
+    for( unsigned i=0; i<t->i_edits_count; i++ )
+    {
+        msg_Dbg(obj, "tk %d elst media time %" PRId64 " duration %" PRIu64 " offset %" PRId64 ,
+                t->i_track_id,
+                t->p_edits[i].i_start_time,
+                t->p_edits[i].i_duration,
+                t->p_edits[i].i_start_offset);
+    }
+}
+
+bool mp4mux_track_AddSample(mp4mux_trackinfo_t *t, const mp4mux_sample_t *entry)
+{
+    /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
+    if (t->i_samples_count + 2 >= t->i_samples_max)
+    {
+        mp4mux_sample_t *p_realloc =
+                realloc(t->samples, sizeof(*p_realloc) * (t->i_samples_max + 1000));
+        if(!p_realloc)
+            return false;
+        t->samples = p_realloc;
+        t->i_samples_max += 1000;
+    }
+    t->samples[t->i_samples_count++] = *entry;
+    return true;
+}
+
+mp4mux_sample_t *mp4mux_track_GetLastSample(mp4mux_trackinfo_t *t)
+{
+    if(t->i_samples_count)
+        return &t->samples[t->i_samples_count - 1];
+    else return NULL;
+}
+
+mp4mux_handle_t * mp4mux_New(enum mp4mux_options options)
+{
+    mp4mux_handle_t *h = malloc(sizeof(*h));
+    vlc_array_init(&h->tracks);
+    h->options = options;
+    return h;
+}
+
+void mp4mux_Delete(mp4mux_handle_t *h)
+{
+    for(size_t i=0; i<vlc_array_count(&h->tracks); i++)
+    {
+        mp4mux_trackinfo_t *t = vlc_array_item_at_index(&h->tracks, i);
+        mp4mux_trackinfo_Clear(t);
+        free(t);
+    }
+    vlc_array_clear(&h->tracks);
+    free(h);
+}
+
+void mp4mux_Set64BitExt(mp4mux_handle_t *h)
+{
+    /* FIXME FIXME
+     * Quicktime actually doesn't like the 64 bits extensions !!! */
+    if(h->options & QUICKTIME)
+        return;
+
+    h->options |= USE64BITEXT;
+}
+
+bool mp4mux_Is(mp4mux_handle_t *h, enum mp4mux_options o)
+{
+    return h->options & o;
+}
 
 bo_t *box_new(const char *fcc)
 {
@@ -235,10 +344,10 @@ static bo_t *GetESDS(mp4mux_trackinfo_t *p_track)
     int64_t i_bitrate_avg = 0;
     int64_t i_bitrate_max = 0;
     /* Compute avg/max bitrate */
-    for (unsigned i = 0; i < p_track->i_entry_count; i++) {
-        i_bitrate_avg += p_track->entry[i].i_size;
-        if (p_track->entry[i].i_length > 0) {
-            int64_t i_bitrate = CLOCK_FREQ * 8 * p_track->entry[i].i_size / p_track->entry[i].i_length;
+    for (unsigned i = 0; i < p_track->i_samples_count; i++) {
+        i_bitrate_avg += p_track->samples[i].i_size;
+        if (p_track->samples[i].i_length > 0) {
+            int64_t i_bitrate = CLOCK_FREQ * 8 * p_track->samples[i].i_size / p_track->samples[i].i_length;
             if (i_bitrate > i_bitrate_max)
                 i_bitrate_max = i_bitrate;
         }
@@ -828,15 +937,15 @@ static bo_t *GetSVQ3Tag(es_format_t *p_fmt)
     return smi;
 }
 
-static bo_t *GetUdtaTag(mp4mux_trackinfo_t **pp_tracks, unsigned int i_tracks)
+static bo_t *GetUdtaTag(mp4mux_handle_t *muxh)
 {
     bo_t *udta = box_new("udta");
     if (!udta)
         return NULL;
 
     /* Requirements */
-    for (unsigned int i = 0; i < i_tracks; i++) {
-        mp4mux_trackinfo_t *p_stream = pp_tracks[i];
+    for (unsigned int i = 0; i < vlc_array_count(&muxh->tracks); i++) {
+        mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&muxh->tracks, i);
         vlc_fourcc_t codec = p_stream->fmt.i_codec;
 
         if (codec == VLC_CODEC_MP4V || codec == VLC_CODEC_MP4A) {
@@ -1219,7 +1328,7 @@ static bo_t *GetTextBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
     return NULL;
 }
 
-static int64_t GetScaledEntryDuration( const mp4mux_entry_t *p_entry, uint32_t i_timescale,
+static int64_t GetScaledEntryDuration( const mp4mux_sample_t *p_entry, uint32_t i_timescale,
                                        vlc_tick_t *pi_total_mtime, int64_t *pi_total_scaled )
 {
     const vlc_tick_t i_totalscaledtototalmtime = vlc_tick_from_samples(*pi_total_scaled, i_timescale);
@@ -1276,8 +1385,8 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
 
     unsigned i_chunk = 0;
     unsigned i_stsc_last_val = 0, i_stsc_entries = 0;
-    for (unsigned i = 0; i < p_track->i_entry_count; i_chunk++) {
-        mp4mux_entry_t *entry = p_track->entry;
+    for (unsigned i = 0; i < p_track->i_samples_count; i_chunk++) {
+        mp4mux_sample_t *entry = p_track->samples;
         int i_first = i;
 
         if (b_stco64)
@@ -1285,8 +1394,8 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
         else
             bo_add_32be(stco, entry[i].i_pos);
 
-        for (; i < p_track->i_entry_count; i++)
-            if (i >= p_track->i_entry_count - 1 ||
+        for (; i < p_track->i_samples_count; i++)
+            if (i >= p_track->i_samples_count - 1 ||
                     entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
                 i++;
                 break;
@@ -1324,16 +1433,16 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
     vlc_tick_t i_total_mtime = 0;
     int64_t i_total_scaled = 0;
     unsigned i_index = 0;
-    for (unsigned i = 0; i < p_track->i_entry_count; i_index++) {
+    for (unsigned i = 0; i < p_track->i_samples_count; i_index++) {
         int     i_first = i;
 
-        int64_t i_scaled = GetScaledEntryDuration(&p_track->entry[i], p_track->i_timescale,
+        int64_t i_scaled = GetScaledEntryDuration(&p_track->samples[i], p_track->i_timescale,
                                                   &i_total_mtime, &i_total_scaled);
-        for (unsigned j=i+1; j < p_track->i_entry_count; j++)
+        for (unsigned j=i+1; j < p_track->i_samples_count; j++)
         {
             vlc_tick_t i_total_mtime_next = i_total_mtime;
             int64_t i_total_scaled_next = i_total_scaled;
-            int64_t i_scalednext = GetScaledEntryDuration(&p_track->entry[j], p_track->i_timescale,
+            int64_t i_scalednext = GetScaledEntryDuration(&p_track->samples[j], p_track->i_timescale,
                                                           &i_total_mtime_next, &i_total_scaled_next);
             if( i_scalednext != i_scaled )
                 break;
@@ -1357,13 +1466,13 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
     {
         bo_add_32be(ctts, 0);
         i_index = 0;
-        for (unsigned i = 0; i < p_track->i_entry_count; i_index++)
+        for (unsigned i = 0; i < p_track->i_samples_count; i_index++)
         {
             int     i_first = i;
-            vlc_tick_t i_offset = p_track->entry[i].i_pts_dts;
+            vlc_tick_t i_offset = p_track->samples[i].i_pts_dts;
 
-            for (; i < p_track->i_entry_count; ++i)
-                if (i == p_track->i_entry_count || p_track->entry[i].i_pts_dts != i_offset)
+            for (; i < p_track->i_samples_count; ++i)
+                if (i == p_track->i_samples_count || p_track->samples[i].i_pts_dts != i_offset)
                     break;
 
             bo_add_32be(ctts, i - i_first); // sample-count
@@ -1381,22 +1490,22 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
         return NULL;
     }
     int i_size = 0;
-    for (unsigned i = 0; i < p_track->i_entry_count; i++)
+    for (unsigned i = 0; i < p_track->i_samples_count; i++)
     {
         if ( i == 0 )
-            i_size = p_track->entry[i].i_size;
-        else if ( p_track->entry[i].i_size != i_size )
+            i_size = p_track->samples[i].i_size;
+        else if ( p_track->samples[i].i_size != i_size )
         {
             i_size = 0;
             break;
         }
     }
     bo_add_32be(stsz, i_size);                         // sample-size
-    bo_add_32be(stsz, p_track->i_entry_count);       // sample-count
+    bo_add_32be(stsz, p_track->i_samples_count);       // sample-count
     if ( i_size == 0 ) // all samples have different size
     {
-        for (unsigned i = 0; i < p_track->i_entry_count; i++)
-            bo_add_32be(stsz, p_track->entry[i].i_size); // sample-size
+        for (unsigned i = 0; i < p_track->i_samples_count; i++)
+            bo_add_32be(stsz, p_track->samples[i].i_size); // sample-size
     }
 
     /* create stss table */
@@ -1405,16 +1514,16 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
     if ( p_track->fmt.i_cat == VIDEO_ES || p_track->fmt.i_cat == AUDIO_ES )
     {
         vlc_tick_t i_interval = -1;
-        for (unsigned i = 0; i < p_track->i_entry_count; i++)
+        for (unsigned i = 0; i < p_track->i_samples_count; i++)
         {
             if ( i_interval != -1 )
             {
-                i_interval += p_track->entry[i].i_length + p_track->entry[i].i_pts_dts;
+                i_interval += p_track->samples[i].i_length + p_track->samples[i].i_pts_dts;
                 if ( i_interval < VLC_TICK_FROM_SEC(2) )
                     continue;
             }
 
-            if (p_track->entry[i].i_flags & BLOCK_FLAG_TYPE_I) {
+            if (p_track->samples[i].i_flags & BLOCK_FLAG_TYPE_I) {
                 if (stss == NULL) {
                     stss = box_full_new("stss", 0, 0);
                     if(!stss)
@@ -1457,9 +1566,7 @@ static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b
     return stbl;
 }
 
-bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, unsigned int i_tracks,
-                         vlc_tick_t i_duration,
-                         bool b_fragmented, bool b_mov, bool b_64_ext, bool b_stco64 )
+bo_t * mp4mux_GetMoov(mp4mux_handle_t *h, vlc_object_t *p_obj, vlc_tick_t i_duration)
 {
     bo_t            *moov, *mvhd;
 
@@ -1468,17 +1575,17 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
 
     /* Important for smooth streaming where its (not muxed here) media time offsets
      * are in timescale == track timescale */
-    if( i_tracks == 1 )
-        i_movie_timescale = pp_tracks[0]->i_timescale;
+    if( vlc_array_count(&h->tracks) == 1 )
+        i_movie_timescale = ((mp4mux_trackinfo_t *)vlc_array_item_at_index(&h->tracks, 0))->i_timescale;
 
     moov = box_new("moov");
     if(!moov)
         return NULL;
     /* Create general info */
-    if( i_duration == 0 && !b_fragmented )
+    if( i_duration == 0 && (h->options & FRAGMENTED) == 0 )
     {
-        for (unsigned int i = 0; i < i_tracks; i++) {
-            mp4mux_trackinfo_t *p_stream = pp_tracks[i];
+        for (unsigned int i = 0; i < vlc_array_count(&h->tracks); i++) {
+            mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&h->tracks, 0);
             i_duration = __MAX(i_duration, p_stream->i_read_duration);
         }
         if(p_obj)
@@ -1487,7 +1594,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
     int64_t i_movie_duration = samples_from_vlc_tick(i_duration, i_movie_timescale);
 
     /* *** add /moov/mvhd *** */
-    if (!b_64_ext) {
+    if ((h->options & USE64BITEXT) == 0) {
         mvhd = box_full_new("mvhd", 0, 0);
         if(!mvhd)
         {
@@ -1524,15 +1631,18 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
         bo_add_32be(mvhd, 0);             // pre-defined
 
     /* Next available track id */
-    bo_add_32be(mvhd, (i_tracks) ? pp_tracks[i_tracks -1]->i_track_id + 1: 1); // next-track-id
+    const mp4mux_trackinfo_t *lasttrack = vlc_array_count(&h->tracks)
+                                        ? vlc_array_item_at_index(&h->tracks, vlc_array_count(&h->tracks) - 1)
+                                        : NULL;
+    bo_add_32be(mvhd, lasttrack ? lasttrack->i_track_id + 1: 1); // next-track-id
 
     box_gather(moov, mvhd);
 
-    for (unsigned int i_trak = 0; i_trak < i_tracks; i_trak++) {
-        mp4mux_trackinfo_t *p_stream = pp_tracks[i_trak];
+    for (unsigned int i_trak = 0; i_trak < vlc_array_count(&h->tracks); i_trak++) {
+        mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&h->tracks, i_trak);
 
         int64_t i_stream_duration;
-        if ( !b_fragmented )
+        if ( (h->options & FRAGMENTED) == 0 )
             i_stream_duration = samples_from_vlc_tick(p_stream->i_read_duration, i_movie_timescale);
         else
             i_stream_duration = 0;
@@ -1544,8 +1654,8 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
 
         /* *** add /moov/trak/tkhd *** */
         bo_t *tkhd;
-        if (!b_64_ext) {
-            if (b_mov)
+        if ((h->options & USE64BITEXT) == 0) {
+            if (h->options & QUICKTIME)
                 tkhd = box_full_new("tkhd", 0, 0x0f);
             else
                 tkhd = box_full_new("tkhd", 0, 1);
@@ -1560,7 +1670,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
             bo_add_32be(tkhd, 0);                     // reserved 0
             bo_add_32be(tkhd, i_stream_duration); // duration
         } else {
-            if (b_mov)
+            if (h->options & QUICKTIME)
                 tkhd = box_full_new("tkhd", 1, 0x0f);
             else
                 tkhd = box_full_new("tkhd", 1, 1);
@@ -1603,8 +1713,8 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
         } else {
             int i_width = 320 << 16;
             int i_height = 200;
-            for (unsigned int i = 0; i < i_tracks; i++) {
-                mp4mux_trackinfo_t *tk = pp_tracks[i];
+            for (unsigned int i = 0; i < vlc_array_count(&h->tracks); i++) {
+                const mp4mux_trackinfo_t *tk = vlc_array_item_at_index(&h->tracks, i);
                 if (tk->fmt.i_cat == VIDEO_ES) {
                     if (tk->fmt.video.i_sar_num > 0 &&
                         tk->fmt.video.i_sar_den > 0)
@@ -1624,7 +1734,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
         box_gather(trak, tkhd);
 
         /* *** add /moov/trak/edts and elst */
-        bo_t *edts = GetEDTS(p_stream, i_movie_timescale, b_64_ext);
+        bo_t *edts = GetEDTS(p_stream, i_movie_timescale, h->options & USE64BITEXT);
         if(edts)
             box_gather(trak, edts);
 
@@ -1638,7 +1748,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
 
         /* media header */
         bo_t *mdhd;
-        if (!b_64_ext) {
+        if ((h->options & USE64BITEXT) == 0) {
             mdhd = box_full_new("mdhd", 0, 0);
             if(!mdhd)
             {
@@ -1696,7 +1806,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
             continue;
         }
 
-        if (b_mov)
+        if (h->options & QUICKTIME)
             bo_add_fourcc(hdlr, "mhlr");         // media handler
         else
             bo_add_32be(hdlr, 0);
@@ -1711,7 +1821,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
             /* sbtl/tx3g Apple subs */
             /* text/text Apple textmedia */
             if(p_stream->fmt.i_codec == VLC_CODEC_TX3G)
-                bo_add_fourcc(hdlr, (b_mov) ? "sbtl" : "text");
+                bo_add_fourcc(hdlr, (h->options & QUICKTIME) ? "sbtl" : "text");
             else if(p_stream->fmt.i_codec == VLC_CODEC_TTML)
                 bo_add_fourcc(hdlr, "sbtl");
             else
@@ -1722,7 +1832,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
         bo_add_32be(hdlr, 0);         // reserved
         bo_add_32be(hdlr, 0);         // reserved
 
-        if (b_mov)
+        if (h->options & QUICKTIME)
             bo_add_8(hdlr, 12);   /* Pascal string for .mov */
 
         if (p_stream->fmt.i_cat == AUDIO_ES)
@@ -1732,7 +1842,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
         else
             bo_add_mem(hdlr, 12, (uint8_t*)"Text Handler");
 
-        if (!b_mov)
+        if ((h->options & QUICKTIME) == 0)
             bo_add_8(hdlr, 0);   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
 
         box_gather(mdia, hdlr);
@@ -1766,7 +1876,7 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
                 box_gather(minf, vmhd);
             }
         } else if (p_stream->fmt.i_cat == SPU_ES) {
-            if(b_mov &&
+            if((h->options & QUICKTIME) &&
                (p_stream->fmt.i_codec == VLC_CODEC_SUBT||
                 p_stream->fmt.i_codec == VLC_CODEC_TX3G||
                 p_stream->fmt.i_codec == VLC_CODEC_QTXT))
@@ -1814,15 +1924,15 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
 
         /* add stbl */
         bo_t *stbl;
-        if ( b_fragmented )
+        if (h->options & FRAGMENTED)
         {
-            uint32_t i_backup = p_stream->i_entry_count;
-            p_stream->i_entry_count = 0;
-            stbl = GetStblBox(p_obj, p_stream, b_mov, b_stco64);
-            p_stream->i_entry_count = i_backup;
+            uint32_t i_backup = p_stream->i_samples_count;
+            p_stream->i_samples_count = 0;
+            stbl = GetStblBox(p_obj, p_stream, h->options & QUICKTIME, h->options & USE64BITEXT);
+            p_stream->i_samples_count = i_backup;
         }
         else
-            stbl = GetStblBox(p_obj, p_stream, b_mov, b_stco64);
+            stbl = GetStblBox(p_obj, p_stream, h->options & QUICKTIME, h->options & USE64BITEXT);
 
         /* append stbl to minf */
         p_stream->i_stco_pos += bo_size(minf);
@@ -1842,35 +1952,36 @@ bo_t * mp4mux_GetMoovBox(vlc_object_t *p_obj, mp4mux_trackinfo_t **pp_tracks, un
     }
 
     /* Add user data tags */
-    box_gather(moov, GetUdtaTag(pp_tracks, i_tracks));
+    box_gather(moov, GetUdtaTag(h));
 
-    if ( b_fragmented )
+    if ( h->options & FRAGMENTED )
     {
         bo_t *mvex = box_new("mvex");
         if( mvex )
         {
             if( i_movie_duration )
             {
-                bo_t *mehd = box_full_new("mehd", b_64_ext ? 1 : 0, 0);
+                bo_t *mehd = box_full_new("mehd", (h->options & USE64BITEXT) ? 1 : 0, 0);
                 if(mehd)
                 {
-                    if(b_64_ext)
+                    if((h->options & USE64BITEXT))
                         bo_add_64be(mehd, i_movie_duration);
                     else
                         bo_add_32be(mehd, i_movie_duration);
                     box_gather(mvex, mehd);
                 }
             }
-            for (unsigned int i_trak = 0; mvex && i_trak < i_tracks; i_trak++)
+
+            for (unsigned int i = 0; mvex && i < vlc_array_count(&h->tracks); i++)
             {
-                mp4mux_trackinfo_t *p_stream = pp_tracks[i_trak];
+                mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&h->tracks, i);
 
                 /* Try to find some defaults */
-                if ( p_stream->i_entry_count )
+                if ( p_stream->i_samples_count )
                 {
                     // FIXME: find highest occurence
-                    p_stream->i_trex_default_length = p_stream->entry[0].i_length;
-                    p_stream->i_trex_default_size = p_stream->entry[0].i_size;
+                    p_stream->i_trex_default_length = p_stream->samples[0].i_length;
+                    p_stream->i_trex_default_size = p_stream->samples[0].i_size;
                 }
 
                 /* *** add /mvex/trex *** */
diff --git a/modules/mux/mp4/libmp4mux.h b/modules/mux/mp4/libmp4mux.h
index 0a5d0ab452..6a45bc3fa2 100644
--- a/modules/mux/mp4/libmp4mux.h
+++ b/modules/mux/mp4/libmp4mux.h
@@ -24,6 +24,8 @@
 #include <vlc_es.h>
 #include <vlc_boxes.h>
 
+typedef struct mp4mux_handle_t mp4mux_handle_t;
+
 typedef struct
 {
     uint64_t i_pos;
@@ -32,7 +34,7 @@ typedef struct
     vlc_tick_t  i_pts_dts;
     vlc_tick_t  i_length;
     unsigned int i_flags;
-} mp4mux_entry_t;
+} mp4mux_sample_t;
 
 typedef struct
 {
@@ -47,9 +49,9 @@ typedef struct
     es_format_t   fmt;
 
     /* index */
-    unsigned int i_entry_count;
-    unsigned int i_entry_max;
-    mp4mux_entry_t *entry;
+    unsigned int i_samples_count;
+    unsigned int i_samples_max;
+    mp4mux_sample_t *samples;
 
     /* XXX: needed for other codecs too, see lavf */
     block_t      *a52_frame;
@@ -74,8 +76,32 @@ typedef struct
 
 } mp4mux_trackinfo_t;
 
-bool mp4mux_trackinfo_Init( mp4mux_trackinfo_t *, unsigned, uint32_t );
-void mp4mux_trackinfo_Clear( mp4mux_trackinfo_t * );
+enum mp4mux_options
+{
+    FRAGMENTED          = 1 << 0,
+    QUICKTIME           = 1 << 1,
+    USE64BITEXT         = 1 << 2,
+};
+
+mp4mux_handle_t * mp4mux_New(enum mp4mux_options);
+void mp4mux_Delete(mp4mux_handle_t *);
+void mp4mux_Set64BitExt(mp4mux_handle_t *);
+bool mp4mux_Is(mp4mux_handle_t *, enum mp4mux_options);
+
+mp4mux_trackinfo_t * mp4mux_track_Add(mp4mux_handle_t *, unsigned id,
+                                      const es_format_t *fmt, uint32_t timescale);
+/* ELST */
+bool mp4mux_track_AddEdit(mp4mux_trackinfo_t *, const mp4mux_edit_t *);
+const mp4mux_edit_t *mp4mux_track_GetLastEdit(const mp4mux_trackinfo_t *);
+void mp4mux_track_DebugEdits(vlc_object_t *, const mp4mux_trackinfo_t *);
+/* Samples */
+bool mp4mux_track_AddSample(mp4mux_trackinfo_t *, const mp4mux_sample_t *);
+mp4mux_sample_t *mp4mux_track_GetLastSample(mp4mux_trackinfo_t *);
+
+
+bo_t *mp4mux_GetMoov(mp4mux_handle_t *, vlc_object_t *, vlc_tick_t i_movie_duration);
+
+/* old */
 
 bo_t *box_new     (const char *fcc);
 bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f);
@@ -84,6 +110,4 @@ void  box_gather  (bo_t *box, bo_t *box2);
 
 bool mp4mux_CanMux(vlc_object_t *, const es_format_t *, vlc_fourcc_t, bool);
 bo_t *mp4mux_GetFtyp(vlc_fourcc_t, uint32_t, vlc_fourcc_t[], size_t i_fourcc);
-bo_t *mp4mux_GetMoovBox(vlc_object_t *, mp4mux_trackinfo_t **pp_tracks, unsigned int i_tracks,
-                        vlc_tick_t i_movie_duration,
-                        bool b_fragmented, bool b_mov, bool b_64ext, bool b_stco64);
+
diff --git a/modules/mux/mp4/mp4.c b/modules/mux/mp4/mp4.c
index 7e31a6fb1e..5799245486 100644
--- a/modules/mux/mp4/mp4.c
+++ b/modules/mux/mp4/mp4.c
@@ -127,7 +127,7 @@ typedef struct mp4_fragqueue_t
 
 typedef struct
 {
-    mp4mux_trackinfo_t mux;
+    mp4mux_trackinfo_t *tinfo;
 
     /* index */
     vlc_tick_t   i_length_neg;
@@ -153,9 +153,8 @@ typedef struct
 
 typedef struct
 {
-    bool b_mov;
+    mp4mux_handle_t *muxh;
     bool b_3gp;
-    bool b_64_ext;
     bool b_fast_start;
 
     /* global */
@@ -171,17 +170,14 @@ typedef struct
 
 
     /* mp4frag */
-    bool           b_fragmented;
     vlc_tick_t     i_written_duration;
     uint32_t       i_mfhd_sequence;
 } sout_mux_sys_t;
 
 static void box_send(sout_mux_t *p_mux,  bo_t *box);
-static bo_t *BuildMoov(sout_mux_t *p_mux);
 
 static block_t *ConvertSUBT(block_t *);
 static bool CreateCurrentEdit(mp4_stream_t *, vlc_tick_t, bool);
-static void DebugEdits(sout_mux_t *, const mp4_stream_t *);
 static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_stream);
 
 static int WriteSlowStartHeader(sout_mux_t *p_mux)
@@ -189,7 +185,7 @@ static int WriteSlowStartHeader(sout_mux_t *p_mux)
     sout_mux_sys_t *p_sys = p_mux->p_sys;
     bo_t *box;
 
-    if (!p_sys->b_mov) {
+    if (!mp4mux_Is(p_sys->muxh, QUICKTIME)) {
         /* Now add ftyp header */
         if(p_sys->b_3gp)
         {
@@ -238,13 +234,18 @@ static int Open(vlc_object_t *p_this)
     msg_Dbg(p_mux, "Mp4 muxer opened");
     config_ChainParse(p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg);
 
-    p_sys->b_mov        = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "mov");
-    p_sys->b_3gp        = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "3gp");
-    p_sys->b_fragmented = p_mux->psz_mux && (!strcmp(p_mux->psz_mux, "mp4frag") ||
-                                             !strcmp(p_mux->psz_mux, "mp4stream"));
-    /* FIXME FIXME
-     * Quicktime actually doesn't like the 64 bits extensions !!! */
-    p_sys->b_64_ext = false;
+    enum mp4mux_options options = 0;
+    if(p_mux->psz_mux)
+    {
+        if(!strcmp(p_mux->psz_mux, "mov"))
+            options |= QUICKTIME;
+        if(!strcmp(p_mux->psz_mux, "mp4frag") || !strcmp(p_mux->psz_mux, "mp4stream"))
+            options |= FRAGMENTED;
+    }
+
+    p_sys->b_3gp = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "3gp");
+
+    p_sys->muxh = mp4mux_New(options);
 
     p_sys->i_pos        = 0;
     p_sys->i_nb_streams = 0;
@@ -261,7 +262,7 @@ static int Open(vlc_object_t *p_this)
     p_mux->pf_control   = Control;
     p_mux->pf_addstream = AddStream;
     p_mux->pf_delstream = DelStream;
-    p_mux->pf_mux       = p_sys->b_fragmented ? MuxFrag : Mux;
+    p_mux->pf_mux       = (options & FRAGMENTED) ? MuxFrag : Mux;
 
     return VLC_SUCCESS;
 }
@@ -296,9 +297,11 @@ static void Close(vlc_object_t *p_this)
     sout_AccessOutWrite(p_mux->p_access, bo.b);
 
     /* Create MOOV header */
-    const bool b_stco64 = (p_sys->i_pos >= (((uint64_t)0x1) << 32));
+    const bool b_64bitext = (p_sys->i_pos >= (((uint64_t)0x1) << 32));
+    if(b_64bitext)
+        mp4mux_Set64BitExt(p_sys->muxh);
     uint64_t i_moov_pos = p_sys->i_pos;
-    bo_t *moov = BuildMoov(p_mux);
+    bo_t *moov = mp4mux_GetMoov(p_sys->muxh, VLC_OBJECT(p_mux), 0);
 
     /* Check we need to create "fast start" files */
     p_sys->b_fast_start = var_GetBool(p_this, SOUT_CFG_PREFIX "faststart");
@@ -337,15 +340,15 @@ static void Close(vlc_object_t *p_this)
         for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
             unsigned i_written = 0;
-            for (unsigned i = 0; i < p_stream->mux.i_entry_count; ) {
-                mp4mux_entry_t *entry = p_stream->mux.entry;
-                if (b_stco64)
-                    bo_set_64be(moov, p_stream->mux.i_stco_pos + i_written++ * 8, entry[i].i_pos + p_sys->i_mdat_pos - i_moov_pos);
+            for (unsigned i = 0; i < p_stream->tinfo->i_samples_count; ) {
+                mp4mux_sample_t *entry = p_stream->tinfo->samples;
+                if (b_64bitext)
+                    bo_set_64be(moov, p_stream->tinfo->i_stco_pos + i_written++ * 8, entry[i].i_pos + p_sys->i_mdat_pos - i_moov_pos);
                 else
-                    bo_set_32be(moov, p_stream->mux.i_stco_pos + i_written++ * 4, entry[i].i_pos + p_sys->i_mdat_pos - i_moov_pos);
+                    bo_set_32be(moov, p_stream->tinfo->i_stco_pos + i_written++ * 4, entry[i].i_pos + p_sys->i_mdat_pos - i_moov_pos);
 
-                for (; i < p_stream->mux.i_entry_count; i++)
-                    if (i >= p_stream->mux.i_entry_count - 1 ||
+                for (; i < p_stream->tinfo->i_samples_count; i++)
+                    if (i >= p_stream->tinfo->i_samples_count - 1 ||
                         entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
                         i++;
                         break;
@@ -363,12 +366,10 @@ static void Close(vlc_object_t *p_this)
 
 cleanup:
     /* Clean-up */
-    for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
-        mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
-        mp4mux_trackinfo_Clear(&p_stream->mux);
-        free(p_stream);
-    }
+    for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++)
+        free(p_sys->pp_streams[i_trak]);
     TAB_CLEAN(p_sys->i_nb_streams, p_sys->pp_streams);
+    mp4mux_Delete(p_sys->muxh);
     free(p_sys);
 }
 
@@ -407,8 +408,8 @@ static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input)
     mp4_stream_t    *p_stream;
 
     if(!mp4mux_CanMux(VLC_OBJECT(p_mux), p_input->p_fmt,
-                      p_sys->b_mov ? MAJOR_qt__ : MAJOR_isom,
-                      p_sys->b_fragmented))
+                      mp4mux_Is(p_sys->muxh, QUICKTIME) ? MAJOR_qt__ : MAJOR_isom,
+                      mp4mux_Is(p_sys->muxh, FRAGMENTED)))
     {
         msg_Err(p_mux, "unsupported codec %4.4s in mp4",
                  (char*)&p_input->p_fmt->i_codec);
@@ -416,52 +417,57 @@ static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input)
     }
 
     p_stream = malloc(sizeof(mp4_stream_t));
-    if (!p_stream ||
-        !mp4mux_trackinfo_Init(&p_stream->mux, p_sys->i_nb_streams + 1, CLOCK_FREQ))
-    {
-        free(p_stream);
+    if(!p_stream)
         return VLC_ENOMEM;
-    }
 
-    es_format_Copy(&p_stream->mux.fmt, p_input->p_fmt);
-    p_stream->i_length_neg  = 0;
-    p_stream->i_first_dts   = VLC_TICK_INVALID;
-    switch( p_stream->mux.fmt.i_cat )
+    uint32_t i_track_timescale = CLOCK_FREQ;
+    es_format_t trackfmt;
+    es_format_Init(&trackfmt, p_input->p_fmt->i_cat, p_input->p_fmt->i_codec);
+    es_format_Copy(&trackfmt, p_input->p_fmt);
+
+    switch( p_input->p_fmt->i_cat )
     {
     case AUDIO_ES:
-        if(!p_stream->mux.fmt.audio.i_rate)
+        if(!trackfmt.audio.i_rate)
         {
             msg_Warn( p_mux, "no audio rate given for stream %d, assuming 48KHz",
                       p_sys->i_nb_streams );
-            p_stream->mux.fmt.audio.i_rate = 48000;
+            trackfmt.audio.i_rate = 48000;
         }
-        p_stream->mux.i_timescale = p_stream->mux.fmt.audio.i_rate;
+        i_track_timescale = trackfmt.audio.i_rate;
         break;
     case VIDEO_ES:
-        if( !p_stream->mux.fmt.video.i_frame_rate ||
-            !p_stream->mux.fmt.video.i_frame_rate_base )
+        if( !trackfmt.video.i_frame_rate ||
+            !trackfmt.video.i_frame_rate_base )
         {
             msg_Warn( p_mux, "Missing frame rate for stream %d, assuming 25fps",
                       p_sys->i_nb_streams );
-            p_stream->mux.fmt.video.i_frame_rate = 25;
-            p_stream->mux.fmt.video.i_frame_rate_base = 1;
+            trackfmt.video.i_frame_rate = 25;
+            trackfmt.video.i_frame_rate_base = 1;
         }
 
-        p_stream->mux.i_timescale = p_stream->mux.fmt.video.i_frame_rate *
-                                    p_stream->mux.fmt.video.i_frame_rate_base;
+        i_track_timescale = trackfmt.video.i_frame_rate *
+                            trackfmt.video.i_frame_rate_base;
 
-        if( p_stream->mux.i_timescale > CLOCK_FREQ )
-            p_stream->mux.i_timescale = CLOCK_FREQ;
-        else if( p_stream->mux.i_timescale < 90000 )
-            p_stream->mux.i_timescale = 90000;
+        if( i_track_timescale > CLOCK_FREQ )
+            i_track_timescale = CLOCK_FREQ;
+        else if( i_track_timescale < 90000 )
+            i_track_timescale = 90000;
         break;
     default:
         break;
     }
 
-    p_stream->mux.p_edits = NULL;
-    p_stream->mux.i_edits_count = 0;
-    p_stream->mux.i_firstdts = VLC_TICK_INVALID;
+    p_stream->tinfo = mp4mux_track_Add(p_sys->muxh, p_sys->i_nb_streams + 1,
+                                       &trackfmt, i_track_timescale);
+    es_format_Clean(&trackfmt);
+    if(!p_stream->tinfo)
+    {
+        free(p_stream);
+        return VLC_ENOMEM;
+    }
+
+    p_stream->i_length_neg  = 0;
     p_stream->i_last_dts    = VLC_TICK_INVALID;
     p_stream->i_last_pts    = VLC_TICK_INVALID;
 
@@ -495,13 +501,13 @@ static void DelStream(sout_mux_t *p_mux, sout_input_t *p_input)
     sout_mux_sys_t *p_sys = p_mux->p_sys;
     mp4_stream_t *p_stream = (mp4_stream_t*)p_input->p_sys;
 
-    if(!p_sys->b_fragmented)
+    if(!mp4mux_Is(p_sys->muxh, FRAGMENTED))
     {
         while(block_FifoCount(p_input->p_fifo) > 0 &&
               MuxStream(p_mux, p_input, p_stream) == VLC_SUCCESS) {};
 
         if(CreateCurrentEdit(p_stream, p_sys->i_start_dts, false))
-            DebugEdits(p_mux, p_stream);
+            mp4mux_track_DebugEdits(VLC_OBJECT(p_mux), p_stream->tinfo);
     }
 
     msg_Dbg(p_mux, "removing input");
@@ -510,64 +516,46 @@ static void DelStream(sout_mux_t *p_mux, sout_input_t *p_input)
 /*****************************************************************************
  * Mux:
  *****************************************************************************/
-static void DebugEdits(sout_mux_t *p_mux, const mp4_stream_t *p_stream)
-{
-    for( unsigned i=0; i<p_stream->mux.i_edits_count; i++ )
-    {
-        msg_Dbg(p_mux, "tk %d elst media time %" PRId64 " duration %" PRIu64 " offset %" PRId64 ,
-                p_stream->mux.i_track_id,
-                p_stream->mux.p_edits[i].i_start_time,
-                p_stream->mux.p_edits[i].i_duration,
-                p_stream->mux.p_edits[i].i_start_offset);
-    }
-}
-
 static bool CreateCurrentEdit(mp4_stream_t *p_stream, vlc_tick_t i_mux_start_dts,
                               bool b_fragmented)
 {
+    const mp4mux_edit_t *p_lastedit = mp4mux_track_GetLastEdit(p_stream->tinfo);
+
     /* Never more than first empty edit for fragmented */
-    if(p_stream->mux.i_edits_count && b_fragmented)
+    if(p_lastedit != NULL && b_fragmented)
         return true;
 
-    if(p_stream->mux.i_entry_count == 0)
+    if(p_stream->tinfo->i_samples_count == 0)
         return true;
 
-    mp4mux_edit_t *p_realloc = realloc( p_stream->mux.p_edits, sizeof(mp4mux_edit_t) *
-                                       (p_stream->mux.i_edits_count + 1) );
-    if(unlikely(!p_realloc))
-        return false;
+    mp4mux_edit_t newedit;
 
-    mp4mux_edit_t *p_newedit = &p_realloc[p_stream->mux.i_edits_count];
-    if(p_stream->mux.i_edits_count == 0)
+    if(p_lastedit == NULL)
     {
-        p_newedit->i_start_time = 0;
-        p_newedit->i_start_offset = __MAX(0, p_stream->i_first_dts - i_mux_start_dts);
+        newedit.i_start_time = 0;
+        newedit.i_start_offset = __MAX(0, p_stream->i_first_dts - i_mux_start_dts);
     }
     else
     {
-        const mp4mux_edit_t *p_lastedit = &p_realloc[p_stream->mux.i_edits_count - 1];
-        p_newedit->i_start_time = __MAX(0, p_lastedit->i_start_time + p_lastedit->i_duration);
-        p_newedit->i_start_offset = 0;
+        newedit.i_start_time = __MAX(0, p_lastedit->i_start_time + p_lastedit->i_duration);
+        newedit.i_start_offset = 0;
     }
 
     if(b_fragmented)
     {
-        p_newedit->i_duration = 0;
+        newedit.i_duration = 0;
     }
     else
     {
         if(p_stream->i_last_pts != VLC_TICK_INVALID)
-            p_newedit->i_duration = p_stream->i_last_pts - p_stream->i_first_dts;
+            newedit.i_duration = p_stream->i_last_pts - p_stream->i_first_dts;
         else
-            p_newedit->i_duration = p_stream->i_last_dts - p_stream->i_first_dts;
-        if(p_stream->mux.i_entry_count)
-            p_newedit->i_duration += p_stream->mux.entry[p_stream->mux.i_entry_count - 1].i_length;
+            newedit.i_duration = p_stream->i_last_dts - p_stream->i_first_dts;
+        if(p_stream->tinfo->i_samples_count)
+            newedit.i_duration += p_stream->tinfo->samples[p_stream->tinfo->i_samples_count - 1].i_length;
     }
 
-    p_stream->mux.p_edits = p_realloc;
-    p_stream->mux.i_edits_count++;
-
-    return true;
+    return mp4mux_track_AddEdit(p_stream->tinfo, &newedit);
 }
 
 static block_t * BlockDequeue(sout_input_t *p_input, mp4_stream_t *p_stream)
@@ -576,7 +564,7 @@ static block_t * BlockDequeue(sout_input_t *p_input, mp4_stream_t *p_stream)
     if(unlikely(!p_block))
         return NULL;
 
-    switch(p_stream->mux.fmt.i_codec)
+    switch(p_stream->tinfo->fmt.i_codec)
     {
         case VLC_CODEC_AV1:
             p_block = AV1_Pack_Sample(p_block);
@@ -590,8 +578,8 @@ static block_t * BlockDequeue(sout_input_t *p_input, mp4_stream_t *p_stream)
             break;
         case VLC_CODEC_A52:
         case VLC_CODEC_EAC3:
-            if (p_stream->mux.a52_frame == NULL && p_block->i_buffer >= 8)
-                p_stream->mux.a52_frame = block_Duplicate(p_block);
+            if (p_stream->tinfo->a52_frame == NULL && p_block->i_buffer >= 8)
+                p_stream->tinfo->a52_frame = block_Duplicate(p_block);
             break;
         default:
             break;
@@ -614,11 +602,12 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
         return VLC_SUCCESS;
 
     /* Reset reference dts in case of discontinuity (ex: gather sout) */
-    if (p_data->i_flags & BLOCK_FLAG_DISCONTINUITY && p_stream->mux.i_entry_count)
+    if (p_data->i_flags & BLOCK_FLAG_DISCONTINUITY && p_stream->tinfo->i_samples_count)
     {
         if(p_stream->i_first_dts != VLC_TICK_INVALID)
         {
-            if(!CreateCurrentEdit(p_stream, p_sys->i_start_dts, p_sys->b_fragmented))
+            if(!CreateCurrentEdit(p_stream, p_sys->i_start_dts,
+                                  mp4mux_Is(p_sys->muxh, FRAGMENTED)))
             {
                 block_Release( p_data );
                 return VLC_ENOMEM;
@@ -631,13 +620,6 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
         p_stream->i_last_pts = VLC_TICK_INVALID;
     }
 
-    /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
-    if (p_stream->mux.i_entry_count >= p_stream->mux.i_entry_max - 2) {
-        p_stream->mux.i_entry_max += 1000;
-        p_stream->mux.entry = xrealloc(p_stream->mux.entry,
-                                       p_stream->mux.i_entry_max * sizeof(mp4mux_entry_t));
-    }
-
     /* Set current segment ranges */
     if( p_stream->i_first_dts == VLC_TICK_INVALID )
     {
@@ -646,7 +628,7 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
             p_sys->i_start_dts = p_stream->i_first_dts;
     }
 
-    if (p_stream->mux.fmt.i_cat != SPU_ES)
+    if (p_stream->tinfo->fmt.i_cat != SPU_ES)
     {
         /* Fix length of the sample */
         if (block_FifoCount(p_input->p_fifo) > 0)
@@ -654,29 +636,29 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
             block_t *p_next = block_FifoShow(p_input->p_fifo);
             if ( p_next->i_flags & BLOCK_FLAG_DISCONTINUITY )
             { /* we have no way to know real length except by decoding */
-                if ( p_stream->mux.fmt.i_cat == VIDEO_ES )
+                if ( p_stream->tinfo->fmt.i_cat == VIDEO_ES )
                 {
                     p_data->i_length = vlc_tick_from_samples(
-                            p_stream->mux.fmt.video.i_frame_rate_base,
-                            p_stream->mux.fmt.video.i_frame_rate );
+                            p_stream->tinfo->fmt.video.i_frame_rate_base,
+                            p_stream->tinfo->fmt.video.i_frame_rate );
                     if( p_data->i_flags & BLOCK_FLAG_SINGLE_FIELD )
                         p_data->i_length >>= 1;
                     msg_Dbg( p_mux, "video track %u fixup to %"PRId64" for sample %u",
-                             p_stream->mux.i_track_id, p_data->i_length, p_stream->mux.i_entry_count );
+                             p_stream->tinfo->i_track_id, p_data->i_length, p_stream->tinfo->i_samples_count );
                 }
-                else if ( p_stream->mux.fmt.i_cat == AUDIO_ES &&
-                          p_stream->mux.fmt.audio.i_rate &&
+                else if ( p_stream->tinfo->fmt.i_cat == AUDIO_ES &&
+                          p_stream->tinfo->fmt.audio.i_rate &&
                           p_data->i_nb_samples )
                 {
                     p_data->i_length = vlc_tick_from_samples(p_data->i_nb_samples,
-                            p_stream->mux.fmt.audio.i_rate);
+                            p_stream->tinfo->fmt.audio.i_rate);
                     msg_Dbg( p_mux, "audio track %u fixup to %"PRId64" for sample %u",
-                             p_stream->mux.i_track_id, p_data->i_length, p_stream->mux.i_entry_count );
+                             p_stream->tinfo->i_track_id, p_data->i_length, p_stream->tinfo->i_samples_count );
                 }
                 else if ( p_data->i_length <= 0 )
                 {
                     msg_Warn( p_mux, "unknown length for track %u sample %u",
-                              p_stream->mux.i_track_id, p_stream->mux.i_entry_count );
+                              p_stream->tinfo->i_track_id, p_stream->tinfo->i_samples_count );
                     p_data->i_length = 1;
                 }
             }
@@ -700,16 +682,16 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
     }
     else /* SPU_ES */
     {
-        if (p_stream->mux.i_entry_count > 0 &&
-            p_stream->mux.entry[p_stream->mux.i_entry_count-1].i_length == 0)
+        mp4mux_sample_t *p_lastsample = mp4mux_track_GetLastSample(p_stream->tinfo);
+        if (p_lastsample != NULL && p_lastsample->i_length == 0)
         {
             /* length of previous spu, stored in spu clearer */
             int64_t i_length = dts_fb_pts( p_data ) - p_stream->i_last_dts;
             if(i_length < 0)
                 i_length = 0;
             /* Fix entry */
-            p_stream->mux.entry[p_stream->mux.i_entry_count-1].i_length = i_length;
-            p_stream->mux.i_read_duration += i_length;
+            p_lastsample->i_length = i_length;
+            p_stream->tinfo->i_read_duration += i_length;
         }
     }
 
@@ -719,36 +701,39 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
         p_stream->i_last_pts = p_data->i_pts;
 
     /* add index entry */
-    mp4mux_entry_t *e = &p_stream->mux.entry[p_stream->mux.i_entry_count++];
-    e->i_pos    = p_sys->i_pos;
-    e->i_size   = p_data->i_buffer;
+    mp4mux_sample_t sample;
+    sample.i_pos    = p_sys->i_pos;
+    sample.i_size   = p_data->i_buffer;
 
     if ( p_data->i_dts != VLC_TICK_INVALID && p_data->i_pts > p_data->i_dts )
     {
-        e->i_pts_dts = p_data->i_pts - p_data->i_dts;
-        if ( !p_stream->mux.b_hasbframes )
-            p_stream->mux.b_hasbframes = true;
+        sample.i_pts_dts = p_data->i_pts - p_data->i_dts;
+        if ( !p_stream->tinfo->b_hasbframes )
+            p_stream->tinfo->b_hasbframes = true;
     }
-    else e->i_pts_dts = 0;
+    else sample.i_pts_dts = 0;
 
-    e->i_length = p_data->i_length;
-    e->i_flags  = p_data->i_flags;
+    sample.i_length = p_data->i_length;
+    sample.i_flags  = p_data->i_flags;
 
     /* update */
-    p_stream->mux.i_read_duration += __MAX( 0, p_data->i_length );
+    p_stream->tinfo->i_read_duration += __MAX( 0, p_data->i_length );
     p_stream->i_last_dts = dts_fb_pts( p_data );
 
     /* write data */
-    p_sys->i_pos += p_data->i_buffer;
-    sout_AccessOutWrite(p_mux->p_access, p_data);
+    if(mp4mux_track_AddSample(p_stream->tinfo, &sample))
+    {
+        p_sys->i_pos += p_data->i_buffer;
+        sout_AccessOutWrite(p_mux->p_access, p_data);
+    }
 
     /* Add SPU clearing tag (duration tb fixed on next SPU or stream end )*/
-    if ( p_stream->mux.fmt.i_cat == SPU_ES && e->i_length > 0 )
+    if ( p_stream->tinfo->fmt.i_cat == SPU_ES && sample.i_length > 0 )
     {
         block_t *p_empty = NULL;
-        if(p_stream->mux.fmt.i_codec == VLC_CODEC_SUBT||
-           p_stream->mux.fmt.i_codec == VLC_CODEC_QTXT||
-           p_stream->mux.fmt.i_codec == VLC_CODEC_TX3G)
+        if(p_stream->tinfo->fmt.i_codec == VLC_CODEC_SUBT||
+           p_stream->tinfo->fmt.i_codec == VLC_CODEC_QTXT||
+           p_stream->tinfo->fmt.i_codec == VLC_CODEC_TX3G)
         {
             p_empty = block_Alloc(3);
             if(p_empty)
@@ -759,13 +744,13 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
                 p_empty->p_buffer[2] = ' ';
             }
         }
-        else if(p_stream->mux.fmt.i_codec == VLC_CODEC_TTML)
+        else if(p_stream->tinfo->fmt.i_codec == VLC_CODEC_TTML)
         {
             p_empty = block_Alloc(40);
             if(p_empty)
                 memcpy(p_empty->p_buffer, "<tt><body><div><p></p></div></body></tt>", 40);
         }
-        else if(p_stream->mux.fmt.i_codec == VLC_CODEC_WEBVTT)
+        else if(p_stream->tinfo->fmt.i_codec == VLC_CODEC_WEBVTT)
         {
             p_empty = block_Alloc(8);
             if(p_empty)
@@ -773,27 +758,30 @@ static int MuxStream(sout_mux_t *p_mux, sout_input_t *p_input, mp4_stream_t *p_s
         }
 
         /* point to start of our empty */
-        p_stream->i_last_dts += e->i_length;
+        p_stream->i_last_dts += sample.i_length;
 
         if(p_empty)
         {
             /* Append a idx entry */
             /* XXX: No need to grow the entry here */
-            mp4mux_entry_t *e_empty = &p_stream->mux.entry[p_stream->mux.i_entry_count++];
-            e_empty->i_pos    = p_sys->i_pos;
-            e_empty->i_size   = p_empty->i_buffer;
-            e_empty->i_pts_dts= 0;
-            e_empty->i_length = 0; /* will add dts diff later*/
-            e_empty->i_flags  = 0;
-
-            p_sys->i_pos += p_empty->i_buffer;
-            sout_AccessOutWrite(p_mux->p_access, p_empty);
+            mp4mux_sample_t closersample;
+            closersample.i_pos    = p_sys->i_pos;
+            closersample.i_size   = p_empty->i_buffer;
+            closersample.i_pts_dts= 0;
+            closersample.i_length = 0; /* will add dts diff later*/
+            closersample.i_flags  = 0;
+
+            if(mp4mux_track_AddSample(p_stream->tinfo, &closersample))
+            {
+                p_sys->i_pos += p_empty->i_buffer;
+                sout_AccessOutWrite(p_mux->p_access, p_empty);
+            }
         }
     }
 
     /* Update the global segment/media duration */
-    if( p_stream->mux.i_read_duration > p_sys->i_read_duration )
-        p_sys->i_read_duration = p_stream->mux.i_read_duration;
+    if( p_stream->tinfo->i_read_duration > p_sys->i_read_duration )
+        p_sys->i_read_duration = p_stream->tinfo->i_read_duration;
 
     return VLC_SUCCESS;
 }
@@ -969,13 +957,13 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
         {
             /* Current segment have all same duration value, different than trex's default */
             if (b_allsamelength &&
-                p_stream->read.p_first->p_block->i_length != p_stream->mux.i_trex_default_length &&
+                p_stream->read.p_first->p_block->i_length != p_stream->tinfo->i_trex_default_length &&
                 p_stream->read.p_first->p_block->i_length)
                     i_tfhd_flags |= MP4_TFHD_DFLT_SAMPLE_DURATION;
 
             /* Current segment have all same size value, different than trex's default */
             if (b_allsamesize &&
-                p_stream->read.p_first->p_block->i_buffer != p_stream->mux.i_trex_default_size &&
+                p_stream->read.p_first->p_block->i_buffer != p_stream->tinfo->i_trex_default_size &&
                 p_stream->read.p_first->p_block->i_buffer)
                     i_tfhd_flags |= MP4_TFHD_DFLT_SAMPLE_SIZE;
         }
@@ -992,11 +980,11 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
             bo_free(traf);
             continue;
         }
-        bo_add_32be(tfhd, p_stream->mux.i_track_id);
+        bo_add_32be(tfhd, p_stream->tinfo->i_track_id);
 
         /* set the local sample duration default */
         if (i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION)
-            bo_add_32be(tfhd, samples_from_vlc_tick(p_stream->read.p_first->p_block->i_length, p_stream->mux.i_timescale));
+            bo_add_32be(tfhd, samples_from_vlc_tick(p_stream->read.p_first->p_block->i_length, p_stream->tinfo->i_timescale));
 
         /* set the local sample size default */
         if (i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE)
@@ -1011,7 +999,7 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
             bo_free(traf);
             continue;
         }
-        bo_add_64be(tfdt, samples_from_vlc_tick(p_stream->i_written_duration, p_stream->mux.i_timescale) );
+        bo_add_64be(tfdt, samples_from_vlc_tick(p_stream->i_written_duration, p_stream->tinfo->i_timescale) );
         box_gather(traf, tfdt);
 
         /* *** add /moof/traf/trun *** */
@@ -1023,14 +1011,14 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
                 i_trun_flags |= MP4_TRUN_FIRST_FLAGS;
 
             if (!b_allsamelength ||
-                ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION) && p_stream->mux.i_trex_default_length == 0 ))
+                ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION) && p_stream->tinfo->i_trex_default_length == 0 ))
                 i_trun_flags |= MP4_TRUN_SAMPLE_DURATION;
 
             if (!b_allsamesize ||
-                ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE) && p_stream->mux.i_trex_default_size == 0 ))
+                ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE) && p_stream->tinfo->i_trex_default_size == 0 ))
                 i_trun_flags |= MP4_TRUN_SAMPLE_SIZE;
 
-            if (p_stream->mux.b_hasbframes)
+            if (p_stream->tinfo->b_hasbframes)
                 i_trun_flags |= MP4_TRUN_SAMPLE_TIME_OFFSET;
 
             if (i_fixupoffset == 0)
@@ -1071,7 +1059,7 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
                 DEQUEUE_ENTRY(p_stream->read, p_entry);
 
                 if (i_trun_flags & MP4_TRUN_SAMPLE_DURATION)
-                    bo_add_32be(trun, samples_from_vlc_tick(p_entry->p_block->i_length, p_stream->mux.i_timescale)); // sample duration
+                    bo_add_32be(trun, samples_from_vlc_tick(p_entry->p_block->i_length, p_stream->tinfo->i_timescale)); // sample duration
 
                 if (i_trun_flags & MP4_TRUN_SAMPLE_SIZE)
                     bo_add_32be(trun, p_entry->p_block->i_buffer); // sample size
@@ -1084,7 +1072,7 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
                     {
                         i_diff = p_entry->p_block->i_pts - p_entry->p_block->i_dts;
                     }
-                    bo_add_32be(trun, samples_from_vlc_tick(i_diff, p_stream->mux.i_timescale)); // ctts
+                    bo_add_32be(trun, samples_from_vlc_tick(i_diff, p_stream->tinfo->i_timescale)); // ctts
                 }
 
                 *pi_mdat_total_size += p_entry->p_block->i_buffer;
@@ -1095,7 +1083,7 @@ static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
 
                 /* Add keyframe entry if needed */
                 if (p_stream->b_hasiframes && (p_entry->p_block->i_flags & BLOCK_FLAG_TYPE_I) &&
-                    (p_stream->mux.fmt.i_cat == VIDEO_ES || p_stream->mux.fmt.i_cat == AUDIO_ES))
+                    (p_stream->tinfo->fmt.i_cat == VIDEO_ES || p_stream->tinfo->fmt.i_cat == AUDIO_ES))
                 {
                     AddKeyframeEntry(p_stream, i_write_pos, i_trak, i_sample, i_time);
                 }
@@ -1178,7 +1166,7 @@ static bo_t *GetMfraBox(sout_mux_t *p_mux)
         {
             bo_t *tfra = box_full_new("tfra", 0, 0x0);
             if (!tfra) continue;
-            bo_add_32be(tfra, p_stream->mux.i_track_id);
+            bo_add_32be(tfra, p_stream->tinfo->i_track_id);
             bo_add_32be(tfra, 0x3); // reserved + lengths (1,1,4)=>(0,0,3)
             bo_add_32be(tfra, p_stream->i_indexentries);
             for(uint32_t i_index=0; i_index<p_stream->i_indexentries; i_index++)
@@ -1206,36 +1194,19 @@ static bo_t *GetMfraBox(sout_mux_t *p_mux)
     return mfra;
 }
 
-static bo_t *BuildMoov(sout_mux_t *p_mux)
-{
-    sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
-    const bool b_stco64 = (p_sys->i_pos >= (((uint64_t)0x1) << 32));
-    /* map our structs */
-    mp4mux_trackinfo_t **pp_infos = NULL;
-    if(p_sys->i_nb_streams) /* Trackless moov ? */
-    {
-        pp_infos = vlc_alloc(p_sys->i_nb_streams, sizeof(mp4mux_trackinfo_t *));
-        if(!pp_infos)
-            return NULL;
-        for(unsigned int i=0; i<p_sys->i_nb_streams; i++)
-            pp_infos[i] = &p_sys->pp_streams[i]->mux;
-    }
-    bo_t *p_moov = mp4mux_GetMoovBox(VLC_OBJECT(p_mux), pp_infos, p_sys->i_nb_streams, 0,
-                              p_sys->b_fragmented, p_sys->b_mov, p_sys->b_64_ext, b_stco64);
-    free(pp_infos);
-    return p_moov;
-}
-
 static void FlushHeader(sout_mux_t *p_mux)
 {
     sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
 
+    if(p_sys->i_pos >= (((uint64_t)0x1) << 32))
+        mp4mux_Set64BitExt(p_sys->muxh);
+
     /* Now add ftyp header */
     bo_t *ftyp = mp4mux_GetFtyp(MAJOR_isom, 0, NULL, 0);
     if(!ftyp)
         return;
 
-    bo_t *moov = BuildMoov(p_mux);
+    bo_t *moov = mp4mux_GetMoov(p_sys->muxh, VLC_OBJECT(p_mux), 0);
 
     /* merge into a single block */
     box_gather(ftyp, moov);
@@ -1261,7 +1232,7 @@ static void WriteFragments(sout_mux_t *p_mux, bool b_flush)
         {
             mp4_stream_t *p_stream = p_sys->pp_streams[j];
             if(CreateCurrentEdit(p_stream, p_sys->i_start_dts, true))
-                DebugEdits(p_mux, p_stream);
+                mp4mux_track_DebugEdits(VLC_OBJECT(p_mux), p_stream->tinfo);
         }
     }
 
@@ -1275,8 +1246,8 @@ static void WriteFragments(sout_mux_t *p_mux, bool b_flush)
             /* set a barrier so we try to align to keyframe */
             if (p_stream->b_hasiframes &&
                     p_stream->i_last_iframe_time > p_stream->i_written_duration &&
-                    (p_stream->mux.fmt.i_cat == VIDEO_ES ||
-                     p_stream->mux.fmt.i_cat == AUDIO_ES) )
+                    (p_stream->tinfo->fmt.i_cat == VIDEO_ES ||
+                     p_stream->tinfo->fmt.i_cat == AUDIO_ES) )
             {
                 i_barrier_time = __MIN(i_barrier_time, p_stream->i_last_iframe_time);
             }
@@ -1317,27 +1288,27 @@ static void WriteFragments(sout_mux_t *p_mux, bool b_flush)
  * This is the end boundary case. */
 static void LengthLocalFixup(sout_mux_t *p_mux, const mp4_stream_t *p_stream, block_t *p_entrydata)
 {
-    if ( p_stream->mux.fmt.i_cat == VIDEO_ES && p_stream->mux.fmt.video.i_frame_rate )
+    if ( p_stream->tinfo->fmt.i_cat == VIDEO_ES && p_stream->tinfo->fmt.video.i_frame_rate )
     {
         p_entrydata->i_length = vlc_tick_from_samples(
-                p_stream->mux.fmt.video.i_frame_rate_base,
-                p_stream->mux.fmt.video.i_frame_rate);
+                p_stream->tinfo->fmt.video.i_frame_rate_base,
+                p_stream->tinfo->fmt.video.i_frame_rate);
         msg_Dbg(p_mux, "video track %d fixup to %"PRId64" for sample %u",
-                p_stream->mux.i_track_id, p_entrydata->i_length, p_stream->mux.i_entry_count - 1);
+                p_stream->tinfo->i_track_id, p_entrydata->i_length, p_stream->tinfo->i_samples_count - 1);
     }
-    else if (p_stream->mux.fmt.i_cat == AUDIO_ES &&
-             p_stream->mux.fmt.audio.i_rate &&
-             p_entrydata->i_nb_samples && p_stream->mux.fmt.audio.i_rate)
+    else if (p_stream->tinfo->fmt.i_cat == AUDIO_ES &&
+             p_stream->tinfo->fmt.audio.i_rate &&
+             p_entrydata->i_nb_samples && p_stream->tinfo->fmt.audio.i_rate)
     {
         p_entrydata->i_length = vlc_tick_from_samples(p_entrydata->i_nb_samples,
-                p_stream->mux.fmt.audio.i_rate);
+                p_stream->tinfo->fmt.audio.i_rate);
         msg_Dbg(p_mux, "audio track %d fixup to %"PRId64" for sample %u",
-                p_stream->mux.i_track_id, p_entrydata->i_length, p_stream->mux.i_entry_count - 1);
+                p_stream->tinfo->i_track_id, p_entrydata->i_length, p_stream->tinfo->i_samples_count - 1);
     }
     else
     {
         msg_Warn(p_mux, "unknown length for track %d sample %u",
-                 p_stream->mux.i_track_id, p_stream->mux.i_entry_count - 1);
+                 p_stream->tinfo->i_track_id, p_stream->tinfo->i_samples_count - 1);
         p_entrydata->i_length = 1;
     }
 }
@@ -1367,11 +1338,10 @@ static void CleanupFrag(sout_mux_sys_t *p_sys)
             p_stream->towrite.p_first = p_next;
         }
         free(p_stream->p_indexentries);
-
-        mp4mux_trackinfo_Clear(&p_stream->mux);
         free(p_stream);
     }
     TAB_CLEAN(p_sys->i_nb_streams, p_sys->pp_streams);
+    mp4mux_Delete(p_sys->muxh);
     free(p_sys);
 }
 
@@ -1464,15 +1434,15 @@ static int MuxFrag(sout_mux_t *p_mux)
         p_stream->p_held_entry = NULL;
 
         if (p_stream->b_hasiframes && (p_heldblock->i_flags & BLOCK_FLAG_TYPE_I) &&
-            p_stream->mux.i_read_duration - p_sys->i_written_duration < FRAGMENT_LENGTH)
+            p_stream->tinfo->i_read_duration - p_sys->i_written_duration < FRAGMENT_LENGTH)
         {
             /* Flag the last iframe time, we'll use it as boundary so it will start
                next fragment */
-            p_stream->i_last_iframe_time = p_stream->mux.i_read_duration;
+            p_stream->i_last_iframe_time = p_stream->tinfo->i_read_duration;
         }
 
         /* update buffered time */
-        p_stream->mux.i_read_duration += __MAX(0, p_heldblock->i_length);
+        p_stream->tinfo->i_read_duration += __MAX(0, p_heldblock->i_length);
     }
 
 
@@ -1485,26 +1455,26 @@ static int MuxFrag(sout_mux_t *p_mux)
     p_stream->p_held_entry->i_run    = p_stream->i_current_run;
     p_stream->p_held_entry->p_next   = NULL;
 
-    if (p_stream->mux.fmt.i_cat == VIDEO_ES )
+    if (p_stream->tinfo->fmt.i_cat == VIDEO_ES )
     {
         if (!p_stream->b_hasiframes && (p_currentblock->i_flags & BLOCK_FLAG_TYPE_I))
             p_stream->b_hasiframes = true;
 
-        if (!p_stream->mux.b_hasbframes && p_currentblock->i_dts != VLC_TICK_INVALID &&
+        if (!p_stream->tinfo->b_hasbframes && p_currentblock->i_dts != VLC_TICK_INVALID &&
             p_currentblock->i_pts > p_currentblock->i_dts)
-            p_stream->mux.b_hasbframes = true;
+            p_stream->tinfo->b_hasbframes = true;
     }
 
     /* Update the global fragment/media duration */
-    vlc_tick_t i_min_read_duration = p_stream->mux.i_read_duration;
+    vlc_tick_t i_min_read_duration = p_stream->tinfo->i_read_duration;
     vlc_tick_t i_min_written_duration = p_stream->i_written_duration;
     for (unsigned int i=0; i<p_sys->i_nb_streams; i++)
     {
         const mp4_stream_t *p_s = p_sys->pp_streams[i];
-        if (p_s->mux.fmt.i_cat != VIDEO_ES && p_s->mux.fmt.i_cat != AUDIO_ES)
+        if (p_s->tinfo->fmt.i_cat != VIDEO_ES && p_s->tinfo->fmt.i_cat != AUDIO_ES)
             continue;
-        if (p_s->mux.i_read_duration < i_min_read_duration)
-            i_min_read_duration = p_s->mux.i_read_duration;
+        if (p_s->tinfo->i_read_duration < i_min_read_duration)
+            i_min_read_duration = p_s->tinfo->i_read_duration;
 
         if (p_s->i_written_duration < i_min_written_duration)
             i_min_written_duration = p_s->i_written_duration;



More information about the vlc-commits mailing list