]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
mux: mp4: add fragmented mp4 muxer
[vlc] / modules / mux / mp4.c
1 /*****************************************************************************
2  * mp4.c: mp4/mov muxer
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2003, 2006 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_sout.h>
36 #include <vlc_block.h>
37
38 #include <time.h>
39
40 #include <vlc_iso_lang.h>
41 #include <vlc_meta.h>
42
43 #include "../demux/mpeg/mpeg_parser_helpers.h"
44 #include "../demux/mp4/libmp4.h"
45
46 #include "assert.h"
47 /*****************************************************************************
48  * Module descriptor
49  *****************************************************************************/
50 #define FASTSTART_TEXT N_("Create \"Fast Start\" files")
51 #define FASTSTART_LONGTEXT N_(\
52     "Create \"Fast Start\" files. " \
53     "\"Fast Start\" files are optimized for downloads and allow the user " \
54     "to start previewing the file while it is downloading.")
55
56 static int  Open   (vlc_object_t *);
57 static void Close  (vlc_object_t *);
58 static int  OpenFrag   (vlc_object_t *);
59 static void CloseFrag  (vlc_object_t *);
60
61 #define SOUT_CFG_PREFIX "sout-mp4-"
62
63 vlc_module_begin ()
64     set_description(N_("MP4/MOV muxer"))
65     set_category(CAT_SOUT)
66     set_subcategory(SUBCAT_SOUT_MUX)
67     set_shortname("MP4")
68
69     add_bool(SOUT_CFG_PREFIX "faststart", true,
70               FASTSTART_TEXT, FASTSTART_LONGTEXT,
71               true)
72     set_capability("sout mux", 5)
73     add_shortcut("mp4", "mov", "3gp")
74     set_callbacks(Open, Close)
75
76 add_submodule ()
77     set_description(N_("Fragmented and streamable MP4 muxer"))
78     set_category(CAT_SOUT)
79     set_subcategory(SUBCAT_SOUT_MUX)
80     set_shortname("MP4 Frag")
81     add_shortcut("mp4frag", "mp4stream")
82     set_capability("sout mux", 0)
83     set_callbacks(OpenFrag, CloseFrag)
84
85 vlc_module_end ()
86
87 /*****************************************************************************
88  * Exported prototypes
89  *****************************************************************************/
90 static const char *const ppsz_sout_options[] = {
91     "faststart", NULL
92 };
93
94 static int Control(sout_mux_t *, int, va_list);
95 static int AddStream(sout_mux_t *, sout_input_t *);
96 static int DelStream(sout_mux_t *, sout_input_t *);
97 static int Mux      (sout_mux_t *);
98 static int MuxFrag  (sout_mux_t *);
99
100 /*****************************************************************************
101  * Local prototypes
102  *****************************************************************************/
103 typedef struct
104 {
105     uint64_t i_pos;
106     int      i_size;
107
108     mtime_t  i_pts_dts;
109     mtime_t  i_length;
110     unsigned int i_flags;
111 } mp4_entry_t;
112
113 typedef struct mp4_fragentry_t mp4_fragentry_t;
114
115 struct mp4_fragentry_t
116 {
117     block_t  *p_block;
118     uint32_t  i_run;
119     mp4_fragentry_t *p_next;
120 };
121
122 typedef struct mp4_fragindex_t
123 {
124     uint64_t i_moofoffset;
125     mtime_t  i_time;
126     uint8_t  i_traf;
127     uint8_t  i_trun;
128     uint32_t i_sample;
129 } mp4_fragindex_t;
130
131 typedef struct mp4_fragqueue_t
132 {
133     mp4_fragentry_t *p_first;
134     mp4_fragentry_t *p_last;
135 } mp4_fragqueue_t;
136
137 typedef struct
138 {
139     es_format_t   fmt;
140     unsigned int  i_track_id;
141
142     /* index */
143     unsigned int i_entry_count;
144     unsigned int i_entry_max;
145     mp4_entry_t  *entry;
146     int64_t      i_length_neg;
147
148     /* stats */
149     int64_t      i_dts_start; /* applies to current segment only */
150     int64_t      i_read_duration;
151     uint32_t     i_timescale;
152     mtime_t      i_starttime; /* the really first packet */
153     bool         b_hasbframes;
154
155     /* for later stco fix-up (fast start files) */
156     uint64_t i_stco_pos;
157     bool b_stco64;
158
159     /* for spu */
160     int64_t i_last_dts; /* applies to current segment only */
161     int64_t i_last_length;
162
163     /*** mp4frag ***/
164     bool         b_hasiframes;
165     uint32_t     i_trex_length;
166     uint32_t     i_trex_size;
167     uint32_t     i_tfhd_flags;
168
169     uint32_t         i_current_run;
170     mp4_fragentry_t *p_held_entry;
171     mp4_fragqueue_t  read;
172     mp4_fragqueue_t  towrite;
173     mtime_t          i_last_iframe_time;
174     mtime_t          i_written_duration;
175     mp4_fragindex_t *p_indexentries;
176     uint32_t         i_indexentriesmax;
177     uint32_t         i_indexentries;
178 } mp4_stream_t;
179
180 struct sout_mux_sys_t
181 {
182     bool b_mov;
183     bool b_3gp;
184     bool b_64_ext;
185     bool b_fast_start;
186
187     uint64_t i_mdat_pos;
188     uint64_t i_pos;
189     mtime_t  i_read_duration;
190
191     unsigned int   i_nb_streams;
192     mp4_stream_t **pp_streams;
193
194     /* mp4frag */
195     bool           b_fragmented;
196     bool           b_header_sent;
197     mtime_t        i_written_duration;
198     uint32_t       i_mfhd_sequence;
199 };
200
201 typedef struct bo_t
202 {
203     block_t    *b;
204     size_t     len;
205 } bo_t;
206
207 static void bo_init     (bo_t *);
208 static void bo_add_8    (bo_t *, uint8_t);
209 static void bo_add_16be (bo_t *, uint16_t);
210 static void bo_add_24be (bo_t *, uint32_t);
211 static void bo_add_32be (bo_t *, uint32_t);
212 static void bo_add_64be (bo_t *, uint64_t);
213 static void bo_add_fourcc(bo_t *, const char *);
214 static void bo_add_mem  (bo_t *, int , uint8_t *);
215 static void bo_add_descr(bo_t *, uint8_t , uint32_t);
216
217 static void bo_fix_32be (bo_t *, int , uint32_t);
218
219 static bo_t *box_new     (const char *fcc);
220 static bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f);
221 static void  box_fix     (bo_t *box);
222 static void  box_gather  (bo_t *box, bo_t *box2);
223
224 static void box_send(sout_mux_t *p_mux,  bo_t *box);
225
226 static bo_t *GetMoovBox(sout_mux_t *p_mux);
227
228 static block_t *ConvertSUBT(block_t *);
229 static block_t *ConvertFromAnnexB(block_t *);
230
231 static const char avc1_start_code[4] = { 0, 0, 0, 1 };
232
233 /*****************************************************************************
234  * Open:
235  *****************************************************************************/
236 static int Open(vlc_object_t *p_this)
237 {
238     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
239     sout_mux_sys_t  *p_sys;
240     bo_t            *box;
241
242     msg_Dbg(p_mux, "Mp4 muxer opened");
243     config_ChainParse(p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg);
244
245     p_mux->pf_control   = Control;
246     p_mux->pf_addstream = AddStream;
247     p_mux->pf_delstream = DelStream;
248     p_mux->pf_mux       = Mux;
249     p_mux->p_sys        = p_sys = malloc(sizeof(sout_mux_sys_t));
250     if (!p_sys)
251         return VLC_ENOMEM;
252     p_sys->i_pos        = 0;
253     p_sys->i_nb_streams = 0;
254     p_sys->pp_streams   = NULL;
255     p_sys->i_mdat_pos   = 0;
256     p_sys->b_mov        = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "mov");
257     p_sys->b_3gp        = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "3gp");
258     p_sys->i_read_duration   = 0;
259     p_sys->b_fragmented = false;
260
261     if (!p_sys->b_mov) {
262         /* Now add ftyp header */
263         box = box_new("ftyp");
264         if (p_sys->b_3gp)
265             bo_add_fourcc(box, "3gp6");
266         else
267             bo_add_fourcc(box, "isom");
268         bo_add_32be  (box, 0);
269         if (p_sys->b_3gp)
270             bo_add_fourcc(box, "3gp4");
271         else
272             bo_add_fourcc(box, "mp41");
273         bo_add_fourcc(box, "avc1");
274         bo_add_fourcc(box, "qt  ");
275         box_fix(box);
276
277         p_sys->i_pos += box->len;
278         p_sys->i_mdat_pos = p_sys->i_pos;
279
280         box_send(p_mux, box);
281     }
282
283     /* FIXME FIXME
284      * Quicktime actually doesn't like the 64 bits extensions !!! */
285     p_sys->b_64_ext = false;
286
287     /* Now add mdat header */
288     box = box_new("mdat");
289     bo_add_64be  (box, 0); // enough to store an extended size
290
291     p_sys->i_pos += box->len;
292
293     box_send(p_mux, box);
294
295     return VLC_SUCCESS;
296 }
297
298 /*****************************************************************************
299  * Close:
300  *****************************************************************************/
301 static void Close(vlc_object_t *p_this)
302 {
303     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
304     sout_mux_sys_t  *p_sys = p_mux->p_sys;
305
306     msg_Dbg(p_mux, "Close");
307
308     /* Update mdat size */
309     bo_t bo;
310     bo_init(&bo);
311     if (p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32)) {
312         /* Extended size */
313         bo_add_32be  (&bo, 1);
314         bo_add_fourcc(&bo, "mdat");
315         bo_add_64be  (&bo, p_sys->i_pos - p_sys->i_mdat_pos);
316     } else {
317         bo_add_32be  (&bo, 8);
318         bo_add_fourcc(&bo, "wide");
319         bo_add_32be  (&bo, p_sys->i_pos - p_sys->i_mdat_pos - 8);
320         bo_add_fourcc(&bo, "mdat");
321     }
322
323     bo.b->i_buffer = bo.len;
324     sout_AccessOutSeek(p_mux->p_access, p_sys->i_mdat_pos);
325     sout_AccessOutWrite(p_mux->p_access, bo.b);
326
327     /* Create MOOV header */
328     uint64_t i_moov_pos = p_sys->i_pos;
329     bo_t *moov = GetMoovBox(p_mux);
330
331     /* Check we need to create "fast start" files */
332     p_sys->b_fast_start = var_GetBool(p_this, SOUT_CFG_PREFIX "faststart");
333     while (p_sys->b_fast_start) {
334         /* Move data to the end of the file so we can fit the moov header
335          * at the start */
336         int64_t i_size = p_sys->i_pos - p_sys->i_mdat_pos;
337         int i_moov_size = moov->len;
338
339         while (i_size > 0) {
340             int64_t i_chunk = __MIN(32768, i_size);
341             block_t *p_buf = block_Alloc(i_chunk);
342             sout_AccessOutSeek(p_mux->p_access,
343                                 p_sys->i_mdat_pos + i_size - i_chunk);
344             if (sout_AccessOutRead(p_mux->p_access, p_buf) < i_chunk) {
345                 msg_Warn(p_this, "read() not supported by access output, "
346                           "won't create a fast start file");
347                 p_sys->b_fast_start = false;
348                 block_Release(p_buf);
349                 break;
350             }
351             sout_AccessOutSeek(p_mux->p_access, p_sys->i_mdat_pos + i_size +
352                                 i_moov_size - i_chunk);
353             sout_AccessOutWrite(p_mux->p_access, p_buf);
354             i_size -= i_chunk;
355         }
356
357         if (!p_sys->b_fast_start)
358             break;
359
360         /* Fix-up samples to chunks table in MOOV header */
361         for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
362             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
363
364             moov->len = p_stream->i_stco_pos;
365             for (unsigned i = 0; i < p_stream->i_entry_count; ) {
366                 mp4_entry_t *entry = p_stream->entry;
367                 if (p_stream->b_stco64)
368                     bo_add_64be(moov, entry[i].i_pos + i_moov_size);
369                 else
370                     bo_add_32be(moov, entry[i].i_pos + i_moov_size);
371
372                 for (; i < p_stream->i_entry_count; i++)
373                     if (i >= p_stream->i_entry_count - 1 ||
374                         entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
375                         i++;
376                         break;
377                     }
378             }
379         }
380
381         moov->len = i_moov_size;
382         i_moov_pos = p_sys->i_mdat_pos;
383         p_sys->b_fast_start = false;
384     }
385
386     /* Write MOOV header */
387     sout_AccessOutSeek(p_mux->p_access, i_moov_pos);
388     box_send(p_mux, moov);
389
390     /* Clean-up */
391     for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
392         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
393
394         es_format_Clean(&p_stream->fmt);
395         free(p_stream->entry);
396         free(p_stream);
397     }
398     if (p_sys->i_nb_streams)
399         free(p_sys->pp_streams);
400     free(p_sys);
401 }
402
403 /*****************************************************************************
404  * Control:
405  *****************************************************************************/
406 static int Control(sout_mux_t *p_mux, int i_query, va_list args)
407 {
408     VLC_UNUSED(p_mux);
409     bool *pb_bool;
410
411     switch(i_query)
412     {
413     case MUX_CAN_ADD_STREAM_WHILE_MUXING:
414         pb_bool = (bool*)va_arg(args, bool *);
415         *pb_bool = false;
416         return VLC_SUCCESS;
417
418     case MUX_GET_ADD_STREAM_WAIT:
419         pb_bool = (bool*)va_arg(args, bool *);
420         *pb_bool = true;
421         return VLC_SUCCESS;
422
423     case MUX_GET_MIME:   /* Not needed, as not streamable */
424     default:
425         return VLC_EGENERIC;
426     }
427 }
428
429 /*****************************************************************************
430  * AddStream:
431  *****************************************************************************/
432 static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input)
433 {
434     sout_mux_sys_t  *p_sys = p_mux->p_sys;
435     mp4_stream_t    *p_stream;
436
437     switch(p_input->p_fmt->i_codec)
438     {
439     case VLC_CODEC_MP4A:
440     case VLC_CODEC_MP4V:
441     case VLC_CODEC_MPGA:
442     case VLC_CODEC_MPGV:
443     case VLC_CODEC_MP2V:
444     case VLC_CODEC_MP1V:
445     case VLC_CODEC_MJPG:
446     case VLC_CODEC_MJPGB:
447     case VLC_CODEC_SVQ1:
448     case VLC_CODEC_SVQ3:
449     case VLC_CODEC_H263:
450     case VLC_CODEC_H264:
451     case VLC_CODEC_HEVC:
452     case VLC_CODEC_AMR_NB:
453     case VLC_CODEC_AMR_WB:
454     case VLC_CODEC_YV12:
455     case VLC_CODEC_YUYV:
456         break;
457     case VLC_CODEC_SUBT:
458         msg_Warn(p_mux, "subtitle track added like in .mov (even when creating .mp4)");
459         break;
460     default:
461         msg_Err(p_mux, "unsupported codec %4.4s in mp4",
462                  (char*)&p_input->p_fmt->i_codec);
463         return VLC_EGENERIC;
464     }
465
466     p_stream = malloc(sizeof(mp4_stream_t));
467     if (!p_stream)
468         return VLC_ENOMEM;
469     es_format_Copy(&p_stream->fmt, p_input->p_fmt);
470     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
471     p_stream->i_length_neg  = 0;
472     p_stream->i_entry_count = 0;
473     p_stream->i_entry_max   = 1000;
474     p_stream->entry         =
475         calloc(p_stream->i_entry_max, sizeof(mp4_entry_t));
476     p_stream->i_dts_start   = 0;
477     p_stream->i_read_duration    = 0;
478     switch( p_stream->fmt.i_cat )
479     {
480     case AUDIO_ES:
481         p_stream->i_timescale = p_stream->fmt.audio.i_rate;
482         break;
483     case VIDEO_ES:
484         p_stream->i_timescale = p_stream->fmt.video.i_frame_rate * 1000 /
485                                 p_stream->fmt.video.i_frame_rate_base;
486         break;
487     default:
488         p_stream->i_timescale = CLOCK_FREQ;
489         break;
490     }
491
492     p_stream->i_starttime   = p_sys->i_read_duration;
493     p_stream->b_hasbframes  = false;
494
495     p_stream->i_last_dts    = 0;
496     p_stream->i_last_length = 0;
497
498     p_stream->b_hasiframes  = false;
499     p_stream->i_trex_length = 0;
500     p_stream->i_trex_size   = 0;
501
502     p_stream->i_current_run = 0;
503     p_stream->read.p_first  = NULL;
504     p_stream->read.p_last   = NULL;
505     p_stream->towrite.p_first = NULL;
506     p_stream->towrite.p_last  = NULL;
507     p_stream->p_held_entry    = NULL;
508     p_stream->i_last_iframe_time = 0;
509     p_stream->i_written_duration = 0;
510     p_stream->p_indexentries     = NULL;
511     p_stream->i_indexentriesmax  = 0;
512     p_stream->i_indexentries     = 0;
513
514     p_input->p_sys          = p_stream;
515
516     msg_Dbg(p_mux, "adding input");
517
518     TAB_APPEND(p_sys->i_nb_streams, p_sys->pp_streams, p_stream);
519     return VLC_SUCCESS;
520 }
521
522 /*****************************************************************************
523  * DelStream:
524  *****************************************************************************/
525 static int DelStream(sout_mux_t *p_mux, sout_input_t *p_input)
526 {
527     VLC_UNUSED(p_input);
528     msg_Dbg(p_mux, "removing input");
529     return VLC_SUCCESS;
530 }
531
532 /*****************************************************************************
533  * Mux:
534  *****************************************************************************/
535 static int Mux(sout_mux_t *p_mux)
536 {
537     sout_mux_sys_t *p_sys = p_mux->p_sys;
538
539     for (;;) {
540         int i_stream = sout_MuxGetStream(p_mux, 2, NULL);
541         if (i_stream < 0)
542             return(VLC_SUCCESS);
543
544         sout_input_t *p_input  = p_mux->pp_inputs[i_stream];
545         mp4_stream_t *p_stream = (mp4_stream_t*)p_input->p_sys;
546
547         block_t *p_data;
548         do {
549             p_data = block_FifoGet(p_input->p_fifo);
550             if (p_stream->fmt.i_codec == VLC_CODEC_H264 ||
551                 p_stream->fmt.i_codec == VLC_CODEC_HEVC)
552                 p_data = ConvertFromAnnexB(p_data);
553             else if (p_stream->fmt.i_codec == VLC_CODEC_SUBT)
554                 p_data = ConvertSUBT(p_data);
555         } while (!p_data);
556
557         /* Reset reference dts in case of discontinuity (ex: gather sout) */
558         if ( p_stream->i_entry_count == 0 || p_data->i_flags & BLOCK_FLAG_DISCONTINUITY )
559         {
560             p_stream->i_dts_start = p_data->i_dts;
561             p_stream->i_last_dts = p_data->i_dts;
562             p_stream->i_length_neg = 0;
563         }
564
565         if (p_stream->fmt.i_cat != SPU_ES) {
566             /* Fix length of the sample */
567             if (block_FifoCount(p_input->p_fifo) > 0) {
568                 block_t *p_next = block_FifoShow(p_input->p_fifo);
569                 if ( p_next->i_flags & BLOCK_FLAG_DISCONTINUITY )
570                 { /* we have no way to know real length except by decoding */
571                     if ( p_stream->fmt.i_cat == VIDEO_ES )
572                     {
573                         p_data->i_length = CLOCK_FREQ *
574                                            p_stream->fmt.video.i_frame_rate_base /
575                                            p_stream->fmt.video.i_frame_rate;
576                         msg_Dbg( p_mux, "video track %u fixup to %"PRId64" for sample %u",
577                                  p_stream->i_track_id, p_data->i_length, p_stream->i_entry_count );
578                     }
579                     else if ( p_stream->fmt.i_cat == AUDIO_ES &&
580                               p_stream->fmt.audio.i_rate &&
581                               p_data->i_nb_samples )
582                     {
583                         p_data->i_length = CLOCK_FREQ * p_data->i_nb_samples /
584                                            p_stream->fmt.audio.i_rate;
585                         msg_Dbg( p_mux, "audio track %u fixup to %"PRId64" for sample %u",
586                                  p_stream->i_track_id, p_data->i_length, p_stream->i_entry_count );
587                     }
588                     else if ( p_data->i_length <= 0 )
589                     {
590                         msg_Warn( p_mux, "unknown length for track %u sample %u",
591                                   p_stream->i_track_id, p_stream->i_entry_count );
592                         p_data->i_length = 1;
593                     }
594                 }
595                 else
596                 {
597                     int64_t i_diff  = p_next->i_dts - p_data->i_dts;
598                     if (i_diff < CLOCK_FREQ) /* protection */
599                         p_data->i_length = i_diff;
600                 }
601             }
602             if (p_data->i_length <= 0) {
603                 msg_Warn(p_mux, "i_length <= 0");
604                 p_stream->i_length_neg += p_data->i_length - 1;
605                 p_data->i_length = 1;
606             } else if (p_stream->i_length_neg < 0) {
607                 int64_t i_recover = __MIN(p_data->i_length / 4, - p_stream->i_length_neg);
608
609                 p_data->i_length -= i_recover;
610                 p_stream->i_length_neg += i_recover;
611             }
612         }
613
614         if (p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0) {
615             int64_t i_length = p_data->i_dts - p_stream->i_last_dts;
616
617             if (i_length <= 0) /* FIXME handle this broken case */
618                 i_length = 1;
619
620             /* Fix last entry */
621             if (p_stream->entry[p_stream->i_entry_count-1].i_length <= 0)
622                 p_stream->entry[p_stream->i_entry_count-1].i_length = i_length;
623         }
624
625         /* add index entry */
626         mp4_entry_t *e = &p_stream->entry[p_stream->i_entry_count];
627         e->i_pos    = p_sys->i_pos;
628         e->i_size   = p_data->i_buffer;
629
630         if ( p_data->i_dts > VLC_TS_INVALID && p_data->i_pts > p_data->i_dts )
631         {
632             e->i_pts_dts = p_data->i_pts - p_data->i_dts;
633             if ( !p_stream->b_hasbframes )
634                 p_stream->b_hasbframes = true;
635         }
636         else e->i_pts_dts = 0;
637
638         e->i_length = p_data->i_length;
639         e->i_flags  = p_data->i_flags;
640
641         p_stream->i_entry_count++;
642         /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
643         if (p_stream->i_entry_count >= p_stream->i_entry_max - 1) {
644             p_stream->i_entry_max += 1000;
645             p_stream->entry = xrealloc(p_stream->entry,
646                          p_stream->i_entry_max * sizeof(mp4_entry_t));
647         }
648
649         /* update */
650         p_stream->i_read_duration += __MAX( 0, p_data->i_length );
651         p_stream->i_last_length = p_data->i_length;
652         p_sys->i_pos += p_data->i_buffer;
653
654         /* Save the DTS for SPU */
655         p_stream->i_last_dts = p_data->i_dts;
656
657         /* write data */
658         sout_AccessOutWrite(p_mux->p_access, p_data);
659
660         /* close subtitle with empty frame */
661         if (p_stream->fmt.i_cat == SPU_ES) {
662             int64_t i_length = p_stream->entry[p_stream->i_entry_count-1].i_length;
663
664             if ( i_length != 0 && (p_data = block_Alloc(3)) ) {
665                 /* TODO */
666                 msg_Dbg(p_mux, "writing an empty sub") ;
667
668                 /* Append a idx entry */
669                 mp4_entry_t *e = &p_stream->entry[p_stream->i_entry_count];
670                 e->i_pos    = p_sys->i_pos;
671                 e->i_size   = 3;
672                 e->i_pts_dts= 0;
673                 e->i_length = 0;
674                 e->i_flags  = 0;
675
676                 /* XXX: No need to grow the entry here */
677                 p_stream->i_entry_count++;
678
679                 /* Fix last dts */
680                 p_stream->i_last_dts += i_length;
681
682                 /* Write a " " */
683                 p_data->i_dts = p_stream->i_last_dts;
684                 p_data->i_dts = p_data->i_pts;
685                 p_data->p_buffer[0] = 0;
686                 p_data->p_buffer[1] = 1;
687                 p_data->p_buffer[2] = ' ';
688
689                 p_sys->i_pos += p_data->i_buffer;
690
691                 sout_AccessOutWrite(p_mux->p_access, p_data);
692             }
693
694             /* Fix duration = current segment starttime + duration within */
695             p_stream->i_read_duration = p_stream->i_starttime + ( p_stream->i_last_dts - p_stream->i_dts_start );
696         }
697     }
698
699     /* Update the global segment/media duration */
700     for ( unsigned int i=0; i<p_sys->i_nb_streams; i++ )
701     {
702         if ( p_sys->pp_streams[i]->i_read_duration > p_sys->i_read_duration )
703             p_sys->i_read_duration = p_sys->pp_streams[i]->i_read_duration;
704     }
705
706     return(VLC_SUCCESS);
707 }
708
709 /*****************************************************************************
710  *
711  *****************************************************************************/
712 static block_t *ConvertSUBT(block_t *p_block)
713 {
714     p_block = block_Realloc(p_block, 2, p_block->i_buffer);
715
716     /* No trailling '\0' */
717     if (p_block->i_buffer > 2 && p_block->p_buffer[p_block->i_buffer-1] == '\0')
718         p_block->i_buffer--;
719
720     p_block->p_buffer[0] = ((p_block->i_buffer - 2) >> 8)&0xff;
721     p_block->p_buffer[1] = ((p_block->i_buffer - 2)     )&0xff;
722
723     return p_block;
724 }
725
726 static block_t *ConvertFromAnnexB(block_t *p_block)
727 {
728     uint8_t *last = p_block->p_buffer;  /* Assume it starts with 0x00000001 */
729     uint8_t *dat  = &p_block->p_buffer[4];
730     uint8_t *end = &p_block->p_buffer[p_block->i_buffer];
731
732
733     /* Replace the 4 bytes start code with 4 bytes size,
734      * FIXME are all startcodes 4 bytes ? (I don't think :(*/
735     while (dat < end) {
736         while (dat < end - 4) {
737             if (!memcmp(dat, avc1_start_code, 4))
738                 break;
739             dat++;
740         }
741         if (dat >= end - 4)
742             dat = end;
743
744         /* Fix size */
745         int i_size = dat - &last[4];
746         last[0] = (i_size >> 24)&0xff;
747         last[1] = (i_size >> 16)&0xff;
748         last[2] = (i_size >>  8)&0xff;
749         last[3] = (i_size      )&0xff;
750
751         /* Skip blocks with SPS/PPS */
752         //if ((last[4]&0x1f) == 7 || (last[4]&0x1f) == 8)
753         //    ; // FIXME Find a way to skip dat without frelling everything
754         last = dat;
755         dat += 4;
756     }
757     return p_block;
758 }
759
760 static bo_t *GetESDS(mp4_stream_t *p_stream)
761 {
762     bo_t *esds;
763     int64_t i_bitrate_avg = 0;
764     int64_t i_bitrate_max = 0;
765
766     /* Compute avg/max bitrate */
767     for (unsigned i = 0; i < p_stream->i_entry_count; i++) {
768         i_bitrate_avg += p_stream->entry[i].i_size;
769         if (p_stream->entry[i].i_length > 0) {
770             int64_t i_bitrate = INT64_C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
771             if (i_bitrate > i_bitrate_max)
772                 i_bitrate_max = i_bitrate;
773         }
774     }
775
776     if (p_stream->i_read_duration > 0)
777         i_bitrate_avg = INT64_C(8000000) * i_bitrate_avg / p_stream->i_read_duration;
778     else
779         i_bitrate_avg = 0;
780     if (i_bitrate_max <= 1)
781         i_bitrate_max = 0x7fffffff;
782
783     /* */
784     int i_decoder_specific_info_size = (p_stream->fmt.i_extra > 0) ? 5 + p_stream->fmt.i_extra : 0;
785
786     esds = box_full_new("esds", 0, 0);
787
788     /* ES_Descr */
789     bo_add_descr(esds, 0x03, 3 + 5 + 13 + i_decoder_specific_info_size + 5 + 1);
790     bo_add_16be(esds, p_stream->i_track_id);
791     bo_add_8   (esds, 0x1f);      // flags=0|streamPriority=0x1f
792
793     /* DecoderConfigDescr */
794     bo_add_descr(esds, 0x04, 13 + i_decoder_specific_info_size);
795
796     int  i_object_type_indication;
797     switch(p_stream->fmt.i_codec)
798     {
799     case VLC_CODEC_MP4V:
800         i_object_type_indication = 0x20;
801         break;
802     case VLC_CODEC_MP2V:
803         /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
804         i_object_type_indication = 0x65;
805         break;
806     case VLC_CODEC_MP1V:
807         /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
808         i_object_type_indication = 0x6b;
809         break;
810     case VLC_CODEC_MP4A:
811         /* FIXME for mpeg2-aac == 0x66->0x68 */
812         i_object_type_indication = 0x40;
813         break;
814     case VLC_CODEC_MPGA:
815         i_object_type_indication =
816             p_stream->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b;
817         break;
818     default:
819         i_object_type_indication = 0x00;
820         break;
821     }
822     int i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05;
823
824     bo_add_8   (esds, i_object_type_indication);
825     bo_add_8   (esds, (i_stream_type << 2) | 1);
826     bo_add_24be(esds, 1024 * 1024);       // bufferSizeDB
827     bo_add_32be(esds, i_bitrate_max);     // maxBitrate
828     bo_add_32be(esds, i_bitrate_avg);     // avgBitrate
829
830     if (p_stream->fmt.i_extra > 0) {
831         /* DecoderSpecificInfo */
832         bo_add_descr(esds, 0x05, p_stream->fmt.i_extra);
833
834         for (int i = 0; i < p_stream->fmt.i_extra; i++)
835             bo_add_8(esds, ((uint8_t*)p_stream->fmt.p_extra)[i]);
836     }
837
838     /* SL_Descr mandatory */
839     bo_add_descr(esds, 0x06, 1);
840     bo_add_8    (esds, 0x02);  // sl_predefined
841
842     return esds;
843 }
844
845 static bo_t *GetWaveTag(mp4_stream_t *p_stream)
846 {
847     bo_t *wave;
848     bo_t *box;
849
850     wave = box_new("wave");
851
852     box = box_new("frma");
853     bo_add_fourcc(box, "mp4a");
854     box_gather(wave, box);
855
856     box = box_new("mp4a");
857     bo_add_32be(box, 0);
858     box_gather(wave, box);
859
860     box = GetESDS(p_stream);
861     box_gather(wave, box);
862
863     box = box_new("srcq");
864     bo_add_32be(box, 0x40);
865     box_gather(wave, box);
866
867     /* wazza ? */
868     bo_add_32be(wave, 8); /* new empty box */
869     bo_add_32be(wave, 0); /* box label */
870
871     return wave;
872 }
873
874 static bo_t *GetDamrTag(mp4_stream_t *p_stream)
875 {
876     bo_t *damr;
877
878     damr = box_new("damr");
879
880     bo_add_fourcc(damr, "REFC");
881     bo_add_8(damr, 0);
882
883     if (p_stream->fmt.i_codec == VLC_CODEC_AMR_NB)
884         bo_add_16be(damr, 0x81ff); /* Mode set (all modes for AMR_NB) */
885     else
886         bo_add_16be(damr, 0x83ff); /* Mode set (all modes for AMR_WB) */
887     bo_add_16be(damr, 0x1); /* Mode change period (no restriction) */
888
889     return damr;
890 }
891
892 static bo_t *GetD263Tag(void)
893 {
894     bo_t *d263;
895
896     d263 = box_new("d263");
897
898     bo_add_fourcc(d263, "VLC ");
899     bo_add_16be(d263, 0xa);
900     bo_add_8(d263, 0);
901
902     return d263;
903 }
904
905 static void hevcParseVPS(uint8_t * p_buffer, size_t i_buffer, uint8_t *general,
906                          uint8_t * numTemporalLayer, bool * temporalIdNested)
907 {
908     const size_t i_decoded_nal_size = 512;
909     uint8_t p_dec_nal[i_decoded_nal_size];
910     size_t i_size = (i_buffer < i_decoded_nal_size)?i_buffer:i_decoded_nal_size;
911     nal_decode(p_buffer, p_dec_nal, i_size);
912
913     /* first two bytes are the NAL header, 3rd and 4th are:
914         vps_video_parameter_set_id(4)
915         vps_reserved_3_2bis(2)
916         vps_max_layers_minus1(6)
917         vps_max_sub_layers_minus1(3)
918         vps_temporal_id_nesting_flags
919     */
920     *numTemporalLayer =  ((p_dec_nal[3] & 0x0E) >> 1) + 1;
921     *temporalIdNested = (bool)(p_dec_nal[3] & 0x01);
922
923     /* 5th & 6th are reserved 0xffff */
924     /* copy the first 12 bytes of profile tier */
925     memcpy(general, &p_dec_nal[6], 12);
926 }
927
928 static void hevcParseSPS(uint8_t * p_buffer, size_t i_buffer, uint8_t * chroma_idc,
929                          uint8_t *bit_depth_luma_minus8, uint8_t *bit_depth_chroma_minus8)
930 {
931     const size_t i_decoded_nal_size = 512;
932     uint8_t p_dec_nal[i_decoded_nal_size];
933     size_t i_size = (i_buffer < i_decoded_nal_size)?i_buffer-2:i_decoded_nal_size;
934     nal_decode(p_buffer+2, p_dec_nal, i_size);
935     bs_t bs;
936     bs_init(&bs, p_dec_nal, i_size);
937
938     /* skip vps id */
939     bs_skip(&bs, 4);
940     uint32_t sps_max_sublayer_minus1 = bs_read(&bs, 3);
941
942     /* skip nesting flag */
943     bs_skip(&bs, 1);
944
945     hevc_skip_profile_tiers_level(&bs, sps_max_sublayer_minus1);
946
947     /* skip sps id */
948     (void) bs_read_ue( &bs );
949
950     *chroma_idc = bs_read_ue(&bs);
951     if (*chroma_idc == 3)
952         bs_skip(&bs, 1);
953
954     /* skip width and heigh */
955     (void) bs_read_ue( &bs );
956     (void) bs_read_ue( &bs );
957
958     uint32_t conformance_window_flag = bs_read1(&bs);
959     if (conformance_window_flag) {
960         /* skip offsets*/
961         (void) bs_read_ue(&bs);
962         (void) bs_read_ue(&bs);
963         (void) bs_read_ue(&bs);
964         (void) bs_read_ue(&bs);
965     }
966     *bit_depth_luma_minus8 = bs_read_ue(&bs);
967     *bit_depth_chroma_minus8 = bs_read_ue(&bs);
968 }
969
970 static bo_t *GetHvcCTag(mp4_stream_t *p_stream)
971 {
972     /* Generate hvcC box matching iso/iec 14496-15 3rd edition */
973     bo_t *hvcC = box_new("hvcC");
974     if(!p_stream->fmt.i_extra)
975         return hvcC;
976
977     struct nal {
978         size_t i_buffer;
979         uint8_t * p_buffer;
980     };
981
982     /* According to the specification HEVC stream can have
983      * 16 vps id and an "unlimited" number of sps and pps id using ue(v) id*/
984     struct nal p_vps[16], *p_sps = NULL, *p_pps = NULL, *p_sei = NULL,
985                *p_nal = NULL;
986     size_t i_vps = 0, i_sps = 0, i_pps = 0, i_sei = 0;
987     uint8_t i_num_arrays = 0;
988
989     uint8_t * p_buffer = p_stream->fmt.p_extra;
990     size_t i_buffer = p_stream->fmt.i_extra;
991
992     uint8_t general_configuration[12] = {0};
993     uint8_t i_numTemporalLayer = 0;
994     uint8_t i_chroma_idc = 1;
995     uint8_t i_bit_depth_luma_minus8 = 0;
996     uint8_t i_bit_depth_chroma_minus8 = 0;
997     bool b_temporalIdNested = false;
998
999     uint32_t cmp = 0xFFFFFFFF;
1000     while (i_buffer) {
1001         /* look for start code 0X0000001 */
1002         while (i_buffer) {
1003             cmp = (cmp << 8) | *p_buffer;
1004             if((cmp ^ UINT32_C(0x100)) <= UINT32_C(0xFF))
1005                 break;
1006             p_buffer++;
1007             i_buffer--;
1008         }
1009         if (p_nal)
1010             p_nal->i_buffer = p_buffer - p_nal->p_buffer - ((i_buffer)?3:0);
1011
1012         switch (*p_buffer & 0x72) {
1013             /* VPS */
1014         case 0x40:
1015             p_nal = &p_vps[i_vps++];
1016             p_nal->p_buffer = p_buffer;
1017             /* Only keep the general profile from the first VPS
1018              * if there are several (this shouldn't happen so soon) */
1019             if (i_vps == 1) {
1020                 hevcParseVPS(p_buffer, i_buffer, general_configuration,
1021                              &i_numTemporalLayer, &b_temporalIdNested);
1022                 i_num_arrays++;
1023             }
1024             break;
1025             /* SPS */
1026         case 0x42: {
1027             struct nal * p_tmp =  realloc(p_sps, sizeof(struct nal) * (i_sps + 1));
1028             if (!p_tmp)
1029                 break;
1030             p_sps = p_tmp;
1031             p_nal = &p_sps[i_sps++];
1032             p_nal->p_buffer = p_buffer;
1033             if (i_sps == 1 && i_buffer > 15) {
1034                 /* Get Chroma_idc and bitdepths */
1035                 hevcParseSPS(p_buffer, i_buffer, &i_chroma_idc,
1036                              &i_bit_depth_luma_minus8, &i_bit_depth_chroma_minus8);
1037                 i_num_arrays++;
1038             }
1039             break;
1040             }
1041         /* PPS */
1042         case 0x44: {
1043             struct nal * p_tmp =  realloc(p_pps, sizeof(struct nal) * (i_pps + 1));
1044             if (!p_tmp)
1045                 break;
1046             p_pps = p_tmp;
1047             p_nal = &p_pps[i_pps++];
1048             p_nal->p_buffer = p_buffer;
1049             if (i_pps == 1)
1050                 i_num_arrays++;
1051             break;
1052             }
1053         /* SEI */
1054         case 0x4E:
1055         case 0x50: {
1056             struct nal * p_tmp =  realloc(p_sei, sizeof(struct nal) * (i_sei + 1));
1057             if (!p_tmp)
1058                 break;
1059             p_sei = p_tmp;
1060             p_nal = &p_sei[i_sei++];
1061             p_nal->p_buffer = p_buffer;
1062             if(i_sei == 1)
1063                 i_num_arrays++;
1064             break;
1065         }
1066         default:
1067             p_nal = NULL;
1068             break;
1069         }
1070     }
1071     bo_add_8(hvcC, 0x01);
1072     bo_add_mem(hvcC, 12, general_configuration);
1073     /* Don't set min spatial segmentation */
1074     bo_add_16be(hvcC, 0xF000);
1075     /* Don't set parallelism type since segmentation isn't set */
1076     bo_add_8(hvcC, 0xFC);
1077     bo_add_8(hvcC, (0xFC | (i_chroma_idc & 0x03)));
1078     bo_add_8(hvcC, (0xF8 | (i_bit_depth_luma_minus8 & 0x07)));
1079     bo_add_8(hvcC, (0xF8 | (i_bit_depth_chroma_minus8 & 0x07)));
1080
1081     /* Don't set framerate */
1082     bo_add_16be(hvcC, 0x0000);
1083     /* Force NAL size of 4 bytes that replace the startcode */
1084     bo_add_8(hvcC, (((i_numTemporalLayer & 0x07) << 3) |
1085                     (b_temporalIdNested << 2) | 0x03));
1086     bo_add_8(hvcC, i_num_arrays);
1087
1088     if (i_vps)
1089     {
1090         /* Write VPS without forcing array_completeness */
1091         bo_add_8(hvcC, 32);
1092         bo_add_16be(hvcC, i_vps);
1093         for (size_t i = 0; i < i_vps; i++) {
1094             p_nal = &p_vps[i];
1095             bo_add_16be(hvcC, p_nal->i_buffer);
1096             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
1097         }
1098     }
1099
1100     if (i_sps) {
1101         /* Write SPS without forcing array_completeness */
1102         bo_add_8(hvcC, 33);
1103         bo_add_16be(hvcC, i_sps);
1104         for (size_t i = 0; i < i_sps; i++) {
1105             p_nal = &p_sps[i];
1106             bo_add_16be(hvcC, p_nal->i_buffer);
1107             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
1108         }
1109     }
1110
1111     if (i_pps) {
1112         /* Write PPS without forcing array_completeness */
1113         bo_add_8(hvcC, 34);
1114         bo_add_16be(hvcC, i_pps);
1115         for (size_t i = 0; i < i_pps; i++) {
1116             p_nal = &p_pps[i];
1117             bo_add_16be(hvcC, p_nal->i_buffer);
1118             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
1119         }
1120     }
1121
1122     if (i_sei) {
1123         /* Write SEI without forcing array_completeness */
1124         bo_add_8(hvcC, 39);
1125         bo_add_16be(hvcC, i_sei);
1126         for (size_t i = 0; i < i_sei; i++) {
1127             p_nal = &p_sei[i];
1128             bo_add_16be(hvcC, p_nal->i_buffer);
1129             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
1130         }
1131     }
1132     return hvcC;
1133 }
1134
1135 static bo_t *GetAvcCTag(mp4_stream_t *p_stream)
1136 {
1137     bo_t    *avcC = NULL;
1138     uint8_t *p_sps = NULL;
1139     uint8_t *p_pps = NULL;
1140     int     i_sps_size = 0;
1141     int     i_pps_size = 0;
1142
1143     if (p_stream->fmt.i_extra > 0) {
1144         /* FIXME: take into account multiple sps/pps */
1145         uint8_t *p_buffer = p_stream->fmt.p_extra;
1146         int     i_buffer = p_stream->fmt.i_extra;
1147
1148         while (i_buffer > 3) {
1149             while (memcmp(p_buffer, &avc1_start_code[1], 3)) {
1150                  i_buffer--;
1151                  p_buffer++;
1152             }
1153             const int i_nal_type = p_buffer[3]&0x1f;
1154             int i_startcode = 0;
1155  
1156             for (int i_offset = 1; i_offset+2 < i_buffer ; i_offset++)
1157                 if (!memcmp(&p_buffer[i_offset], &avc1_start_code[1], 3)) {
1158                     /* we found another startcode */
1159                     i_startcode = i_offset;
1160                     while (p_buffer[i_startcode-1] == 0 && i_startcode > 0)
1161                         i_startcode--;
1162                     break;
1163                 }
1164
1165             int i_size = i_startcode ? i_startcode : i_buffer;
1166
1167             if (i_nal_type == 7) {
1168                 p_sps = &p_buffer[3];
1169                 i_sps_size = i_size - 3;
1170             }
1171             if (i_nal_type == 8) {
1172                 p_pps = &p_buffer[3];
1173                 i_pps_size = i_size - 3;
1174             }
1175             i_buffer -= i_size;
1176             p_buffer += i_size;
1177         }
1178     }
1179  
1180     /* FIXME use better value */
1181     avcC = box_new("avcC");
1182     bo_add_8(avcC, 1);      /* configuration version */
1183     bo_add_8(avcC, i_sps_size ? p_sps[1] : 77);
1184     bo_add_8(avcC, i_sps_size ? p_sps[2] : 64);
1185     bo_add_8(avcC, i_sps_size ? p_sps[3] : 30);       /* level, 5.1 */
1186     bo_add_8(avcC, 0xff);   /* 0b11111100 | lengthsize = 0x11 */
1187
1188     bo_add_8(avcC, 0xe0 | (i_sps_size > 0 ? 1 : 0));   /* 0b11100000 | sps_count */
1189     if (i_sps_size > 0) {
1190         bo_add_16be(avcC, i_sps_size);
1191         bo_add_mem(avcC, i_sps_size, p_sps);
1192     }
1193
1194     bo_add_8(avcC, (i_pps_size > 0 ? 1 : 0));   /* pps_count */
1195     if (i_pps_size > 0) {
1196         bo_add_16be(avcC, i_pps_size);
1197         bo_add_mem(avcC, i_pps_size, p_pps);
1198     }
1199
1200     return avcC;
1201 }
1202
1203 /* TODO: No idea about these values */
1204 static bo_t *GetSVQ3Tag(mp4_stream_t *p_stream)
1205 {
1206     bo_t *smi = box_new("SMI ");
1207
1208     if (p_stream->fmt.i_extra > 0x4e) {
1209         uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra];
1210         uint8_t *p     = &((uint8_t*)p_stream->fmt.p_extra)[0x46];
1211
1212         while (p + 8 < p_end) {
1213             int i_size = GetDWBE(p);
1214             if (i_size <= 1) /* FIXME handle 1 as long size */
1215                 break;
1216             if (!strncmp((const char *)&p[4], "SMI ", 4)) {
1217                 bo_add_mem(smi, p_end - p - 8, &p[8]);
1218                 return smi;
1219             }
1220             p += i_size;
1221         }
1222     }
1223
1224     /* Create a dummy one in fallback */
1225     bo_add_fourcc(smi, "SEQH");
1226     bo_add_32be(smi, 0x5);
1227     bo_add_32be(smi, 0xe2c0211d);
1228     bo_add_8(smi, 0xc0);
1229
1230     return smi;
1231 }
1232
1233 static bo_t *GetUdtaTag(sout_mux_t *p_mux)
1234 {
1235     sout_mux_sys_t *p_sys = p_mux->p_sys;
1236     bo_t *udta = box_new("udta");
1237
1238     /* Requirements */
1239     for (unsigned int i_track = 0; i_track < p_sys->i_nb_streams; i_track++) {
1240         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
1241         vlc_fourcc_t codec = p_stream->fmt.i_codec;
1242
1243         if (codec == VLC_CODEC_MP4V || codec == VLC_CODEC_MP4A) {
1244             bo_t *box = box_new("\251req");
1245             /* String length */
1246             bo_add_16be(box, sizeof("QuickTime 6.0 or greater") - 1);
1247             bo_add_16be(box, 0);
1248             bo_add_mem(box, sizeof("QuickTime 6.0 or greater") - 1,
1249                         (uint8_t *)"QuickTime 6.0 or greater");
1250             box_gather(udta, box);
1251             break;
1252         }
1253     }
1254
1255     /* Encoder */
1256     {
1257         bo_t *box = box_new("\251enc");
1258         /* String length */
1259         bo_add_16be(box, sizeof(PACKAGE_STRING " stream output") - 1);
1260         bo_add_16be(box, 0);
1261         bo_add_mem(box, sizeof(PACKAGE_STRING " stream output") - 1,
1262                     (uint8_t*)PACKAGE_STRING " stream output");
1263         box_gather(udta, box);
1264     }
1265 #if 0
1266     /* Misc atoms */
1267     vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
1268     if (p_meta) {
1269 #define ADD_META_BOX(type, box_string) { \
1270         bo_t *box = NULL;  \
1271         if (vlc_meta_Get(p_meta, vlc_meta_##type)) \
1272             box = box_new("\251" box_string); \
1273         if (box) { \
1274             bo_add_16be(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type))); \
1275             bo_add_16be(box, 0); \
1276             bo_add_mem(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type)), \
1277                         (uint8_t*)(vlc_meta_Get(p_meta, vlc_meta_##type))); \
1278             box_gather(udta, box); \
1279         } }
1280
1281         ADD_META_BOX(Title, "nam");
1282         ADD_META_BOX(Artist, "ART");
1283         ADD_META_BOX(Genre, "gen");
1284         ADD_META_BOX(Copyright, "cpy");
1285         ADD_META_BOX(Description, "des");
1286         ADD_META_BOX(Date, "day");
1287         ADD_META_BOX(URL, "url");
1288 #undef ADD_META_BOX
1289     }
1290 #endif
1291     return udta;
1292 }
1293
1294 static bo_t *GetSounBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
1295 {
1296     sout_mux_sys_t *p_sys = p_mux->p_sys;
1297     bool b_descr = true;
1298     vlc_fourcc_t codec = p_stream->fmt.i_codec;
1299     char fcc[4];
1300     vlc_fourcc_to_char(codec, fcc);
1301
1302     if (codec == VLC_CODEC_MPGA) {
1303         if (p_sys->b_mov) {
1304             b_descr = false;
1305             memcpy(fcc, ".mp3", 4);
1306         } else
1307             memcpy(fcc, "mp4a", 4);
1308     }
1309
1310     bo_t *soun = box_new(fcc);
1311     for (int i = 0; i < 6; i++)
1312         bo_add_8(soun, 0);        // reserved;
1313     bo_add_16be(soun, 1);         // data-reference-index
1314
1315     /* SoundDescription */
1316     if (p_sys->b_mov && codec == VLC_CODEC_MP4A)
1317         bo_add_16be(soun, 1);     // version 1;
1318     else
1319         bo_add_16be(soun, 0);     // version 0;
1320     bo_add_16be(soun, 0);         // revision level (0)
1321     bo_add_32be(soun, 0);         // vendor
1322     // channel-count
1323     bo_add_16be(soun, p_stream->fmt.audio.i_channels);
1324     // sample size
1325     bo_add_16be(soun, p_stream->fmt.audio.i_bitspersample ?
1326                  p_stream->fmt.audio.i_bitspersample : 16);
1327     bo_add_16be(soun, -2);        // compression id
1328     bo_add_16be(soun, 0);         // packet size (0)
1329     bo_add_16be(soun, p_stream->fmt.audio.i_rate); // sampleratehi
1330     bo_add_16be(soun, 0);                             // sampleratelo
1331
1332     /* Extended data for SoundDescription V1 */
1333     if (p_sys->b_mov && p_stream->fmt.i_codec == VLC_CODEC_MP4A) {
1334         /* samples per packet */
1335         bo_add_32be(soun, p_stream->fmt.audio.i_frame_length);
1336         bo_add_32be(soun, 1536); /* bytes per packet */
1337         bo_add_32be(soun, 2);    /* bytes per frame */
1338         /* bytes per sample */
1339         bo_add_32be(soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */);
1340     }
1341
1342     /* Add an ES Descriptor */
1343     if (b_descr) {
1344         bo_t *box;
1345
1346         if (p_sys->b_mov && codec == VLC_CODEC_MP4A)
1347             box = GetWaveTag(p_stream);
1348         else if (codec == VLC_CODEC_AMR_NB)
1349             box = GetDamrTag(p_stream);
1350         else
1351             box = GetESDS(p_stream);
1352         box_gather(soun, box);
1353     }
1354
1355     return soun;
1356 }
1357
1358 static bo_t *GetVideBox(mp4_stream_t *p_stream)
1359 {
1360     char fcc[4];
1361
1362     switch(p_stream->fmt.i_codec)
1363     {
1364     case VLC_CODEC_MP4V:
1365     case VLC_CODEC_MPGV: memcpy(fcc, "mp4v", 4); break;
1366     case VLC_CODEC_MJPG: memcpy(fcc, "mjpa", 4); break;
1367     case VLC_CODEC_SVQ1: memcpy(fcc, "SVQ1", 4); break;
1368     case VLC_CODEC_SVQ3: memcpy(fcc, "SVQ3", 4); break;
1369     case VLC_CODEC_H263: memcpy(fcc, "s263", 4); break;
1370     case VLC_CODEC_H264: memcpy(fcc, "avc1", 4); break;
1371     case VLC_CODEC_HEVC: memcpy(fcc, "hvc1", 4); break;
1372     case VLC_CODEC_YV12: memcpy(fcc, "yv12", 4); break;
1373     case VLC_CODEC_YUYV: memcpy(fcc, "yuy2", 4); break;
1374     default:
1375         vlc_fourcc_to_char(p_stream->fmt.i_codec, fcc);
1376         break;
1377     }
1378
1379     bo_t *vide = box_new(fcc);
1380     for (int i = 0; i < 6; i++)
1381         bo_add_8(vide, 0);        // reserved;
1382     bo_add_16be(vide, 1);         // data-reference-index
1383
1384     bo_add_16be(vide, 0);         // predefined;
1385     bo_add_16be(vide, 0);         // reserved;
1386     for (int i = 0; i < 3; i++)
1387         bo_add_32be(vide, 0);     // predefined;
1388
1389     bo_add_16be(vide, p_stream->fmt.video.i_width);  // i_width
1390     bo_add_16be(vide, p_stream->fmt.video.i_height); // i_height
1391
1392     bo_add_32be(vide, 0x00480000);                // h 72dpi
1393     bo_add_32be(vide, 0x00480000);                // v 72dpi
1394
1395     bo_add_32be(vide, 0);         // data size, always 0
1396     bo_add_16be(vide, 1);         // frames count per sample
1397
1398     // compressor name;
1399     for (int i = 0; i < 32; i++)
1400         bo_add_8(vide, 0);
1401
1402     bo_add_16be(vide, 0x18);      // depth
1403     bo_add_16be(vide, 0xffff);    // predefined
1404
1405     /* add an ES Descriptor */
1406     switch(p_stream->fmt.i_codec)
1407     {
1408     case VLC_CODEC_MP4V:
1409     case VLC_CODEC_MPGV:
1410         box_gather(vide, GetESDS(p_stream));
1411         break;
1412
1413     case VLC_CODEC_H263:
1414         box_gather(vide, GetD263Tag());
1415         break;
1416
1417     case VLC_CODEC_SVQ3:
1418         box_gather(vide, GetSVQ3Tag(p_stream));
1419         break;
1420
1421     case VLC_CODEC_H264:
1422         box_gather(vide, GetAvcCTag(p_stream));
1423         break;
1424
1425     case VLC_CODEC_HEVC:
1426         box_gather(vide, GetHvcCTag(p_stream));
1427         break;
1428     }
1429
1430     return vide;
1431 }
1432
1433 static bo_t *GetTextBox(void)
1434 {
1435     bo_t *text = box_new("text");
1436
1437     for (int i = 0; i < 6; i++)
1438         bo_add_8(text, 0);        // reserved;
1439     bo_add_16be(text, 1);         // data-reference-index
1440
1441     bo_add_32be(text, 0);         // display flags
1442     bo_add_32be(text, 0);         // justification
1443     for (int i = 0; i < 3; i++)
1444         bo_add_16be(text, 0);     // back ground color
1445
1446     bo_add_16be(text, 0);         // box text
1447     bo_add_16be(text, 0);         // box text
1448     bo_add_16be(text, 0);         // box text
1449     bo_add_16be(text, 0);         // box text
1450
1451     bo_add_64be(text, 0);         // reserved
1452     for (int i = 0; i < 3; i++)
1453         bo_add_16be(text, 0xff);  // foreground color
1454
1455     bo_add_8 (text, 9);
1456     bo_add_mem(text, 9, (uint8_t*)"Helvetica");
1457
1458     return text;
1459 }
1460
1461 static bo_t *GetStblBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
1462 {
1463     sout_mux_sys_t *p_sys = p_mux->p_sys;
1464
1465     /* sample description */
1466     bo_t *stsd = box_full_new("stsd", 0, 0);
1467     bo_add_32be(stsd, 1);
1468     if (p_stream->fmt.i_cat == AUDIO_ES)
1469         box_gather(stsd, GetSounBox(p_mux, p_stream));
1470     else if (p_stream->fmt.i_cat == VIDEO_ES)
1471         box_gather(stsd, GetVideBox(p_stream));
1472     else if (p_stream->fmt.i_cat == SPU_ES)
1473         box_gather(stsd, GetTextBox());
1474
1475     /* chunk offset table */
1476     bo_t *stco;
1477     if (p_sys->i_pos >= (((uint64_t)0x1) << 32)) {
1478         /* 64 bits version */
1479         p_stream->b_stco64 = true;
1480         stco = box_full_new("co64", 0, 0);
1481     } else {
1482         /* 32 bits version */
1483         p_stream->b_stco64 = false;
1484         stco = box_full_new("stco", 0, 0);
1485     }
1486     bo_add_32be(stco, 0);     // entry-count (fixed latter)
1487
1488     /* sample to chunk table */
1489     bo_t *stsc = box_full_new("stsc", 0, 0);
1490     bo_add_32be(stsc, 0);     // entry-count (fixed latter)
1491
1492     unsigned i_chunk = 0;
1493     unsigned i_stsc_last_val = 0, i_stsc_entries = 0;
1494     for (unsigned i = 0; i < p_stream->i_entry_count; i_chunk++) {
1495         mp4_entry_t *entry = p_stream->entry;
1496         int i_first = i;
1497
1498         if (p_stream->b_stco64)
1499             bo_add_64be(stco, entry[i].i_pos);
1500         else
1501             bo_add_32be(stco, entry[i].i_pos);
1502
1503         for (; i < p_stream->i_entry_count; i++)
1504             if (i >= p_stream->i_entry_count - 1 ||
1505                     entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
1506                 i++;
1507                 break;
1508             }
1509
1510         /* Add entry to the stsc table */
1511         if (i_stsc_last_val != i - i_first) {
1512             bo_add_32be(stsc, 1 + i_chunk);   // first-chunk
1513             bo_add_32be(stsc, i - i_first) ;  // samples-per-chunk
1514             bo_add_32be(stsc, 1);             // sample-descr-index
1515             i_stsc_last_val = i - i_first;
1516             i_stsc_entries++;
1517         }
1518     }
1519
1520     /* Fix stco entry count */
1521     bo_fix_32be(stco, 12, i_chunk);
1522     msg_Dbg(p_mux, "created %d chunks (stco)", i_chunk);
1523
1524     /* Fix stsc entry count */
1525     bo_fix_32be(stsc, 12, i_stsc_entries );
1526
1527     /* add stts */
1528     bo_t *stts = box_full_new("stts", 0, 0);
1529     bo_add_32be(stts, 0);     // entry-count (fixed latter)
1530
1531     unsigned i_index = 0;
1532     for (unsigned i = 0; i < p_stream->i_entry_count; i_index++) {
1533         int     i_first = i;
1534         mtime_t i_delta = p_stream->entry[i].i_length;
1535
1536         for (; i < p_stream->i_entry_count; ++i)
1537             if (i == p_stream->i_entry_count || p_stream->entry[i].i_length != i_delta)
1538                 break;
1539
1540         bo_add_32be(stts, i - i_first); // sample-count
1541         bo_add_32be(stts, (uint64_t)i_delta  * p_stream->i_timescale / CLOCK_FREQ); // sample-delta
1542     }
1543     bo_fix_32be(stts, 12, i_index);
1544
1545     /* composition time handling */
1546     bo_t *ctts = NULL;
1547     if ( p_stream->b_hasbframes && (ctts = box_full_new("ctts", 0, 0)) )
1548     {
1549         bo_add_32be(ctts, 0);
1550         i_index = 0;
1551         for (unsigned i = 0; i < p_stream->i_entry_count; i_index++)
1552         {
1553             int     i_first = i;
1554             mtime_t i_offset = p_stream->entry[i].i_pts_dts;
1555
1556             for (; i < p_stream->i_entry_count; ++i)
1557                 if (i == p_stream->i_entry_count || p_stream->entry[i].i_pts_dts != i_offset)
1558                     break;
1559
1560             bo_add_32be(ctts, i - i_first); // sample-count
1561             bo_add_32be(ctts, i_offset * p_stream->i_timescale / CLOCK_FREQ ); // sample-offset
1562         }
1563         bo_fix_32be(ctts, 12, i_index);
1564     }
1565
1566     bo_t *stsz = box_full_new("stsz", 0, 0);
1567     int i_size = 0;
1568     for (unsigned i = 0; i < p_stream->i_entry_count; i++)
1569     {
1570         if ( i == 0 )
1571             i_size = p_stream->entry[i].i_size;
1572         else if ( p_stream->entry[i].i_size != i_size )
1573         {
1574             i_size = 0;
1575             break;
1576         }
1577     }
1578     bo_add_32be(stsz, i_size);                         // sample-size
1579     bo_add_32be(stsz, p_stream->i_entry_count);       // sample-count
1580     if ( i_size == 0 ) // all samples have different size
1581     {
1582         for (unsigned i = 0; i < p_stream->i_entry_count; i++)
1583             bo_add_32be(stsz, p_stream->entry[i].i_size); // sample-size
1584     }
1585
1586     /* create stss table */
1587     bo_t *stss = NULL;
1588     i_index = 0;
1589     if ( p_stream->fmt.i_cat == VIDEO_ES || p_stream->fmt.i_cat == AUDIO_ES )
1590     {
1591         mtime_t i_interval = -1;
1592         for (unsigned i = 0; i < p_stream->i_entry_count; i++)
1593         {
1594             if ( i_interval != -1 )
1595             {
1596                 i_interval += p_stream->entry[i].i_length + p_stream->entry[i].i_pts_dts;
1597                 if ( i_interval < CLOCK_FREQ * 2 )
1598                     continue;
1599             }
1600
1601             if (p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I) {
1602                 if (stss == NULL) {
1603                     stss = box_full_new("stss", 0, 0);
1604                     bo_add_32be(stss, 0); /* fixed later */
1605                 }
1606                 bo_add_32be(stss, 1 + i);
1607                 i_index++;
1608                 i_interval = 0;
1609             }
1610         }
1611     }
1612
1613     if (stss)
1614         bo_fix_32be(stss, 12, i_index);
1615
1616     /* Now gather all boxes into stbl */
1617     bo_t *stbl = box_new("stbl");
1618
1619     box_gather(stbl, stsd);
1620     box_gather(stbl, stts);
1621     if (stss)
1622         box_gather(stbl, stss);
1623     if (ctts)
1624         box_gather(stbl, ctts);
1625     box_gather(stbl, stsc);
1626     box_gather(stbl, stsz);
1627     p_stream->i_stco_pos = stbl->len + 16;
1628     box_gather(stbl, stco);
1629
1630     return stbl;
1631 }
1632
1633 static int64_t get_timestamp(void);
1634
1635 static void matrix_apply_rotation(es_format_t *fmt, uint32_t mvhd_matrix[9])
1636 {
1637     enum video_orientation_t orientation = ORIENT_NORMAL;
1638     if (fmt->i_cat == VIDEO_ES)
1639         orientation = fmt->video.orientation;
1640
1641 #define ATAN(a, b) do { mvhd_matrix[1] = (a) << 16; \
1642     mvhd_matrix[0] = (b) << 16; \
1643     } while(0)
1644
1645     switch (orientation) {
1646     case ORIENT_ROTATED_90:  ATAN( 1,  0); break;
1647     case ORIENT_ROTATED_180: ATAN( 0, -1); break;
1648     case ORIENT_ROTATED_270: ATAN( -1, 0); break;
1649     default:                 ATAN( 0,  1); break;
1650     }
1651
1652     mvhd_matrix[3] = mvhd_matrix[0] ? 0 : 0x10000;
1653     mvhd_matrix[4] = mvhd_matrix[1] ? 0 : 0x10000;
1654 }
1655
1656 static bo_t *GetMoovBox(sout_mux_t *p_mux)
1657 {
1658     sout_mux_sys_t *p_sys = p_mux->p_sys;
1659
1660     bo_t            *moov, *mvhd;
1661
1662     uint32_t        i_movie_timescale = 90000;
1663     int64_t         i_movie_duration  = 0;
1664     int64_t         i_timestamp = get_timestamp();
1665
1666     moov = box_new("moov");
1667
1668     /* Create general info */
1669     if ( !p_sys->b_fragmented )
1670     {
1671         for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
1672             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1673             i_movie_duration = __MAX(i_movie_duration, p_stream->i_read_duration);
1674         }
1675         msg_Dbg(p_mux, "movie duration %"PRId64"s", i_movie_duration / CLOCK_FREQ);
1676
1677         i_movie_duration = i_movie_duration * i_movie_timescale / CLOCK_FREQ;
1678     }
1679     else
1680         i_movie_duration = 0;
1681
1682     /* *** add /moov/mvhd *** */
1683     if (!p_sys->b_64_ext) {
1684         mvhd = box_full_new("mvhd", 0, 0);
1685         bo_add_32be(mvhd, i_timestamp);   // creation time
1686         bo_add_32be(mvhd, i_timestamp);   // modification time
1687         bo_add_32be(mvhd, i_movie_timescale);  // timescale
1688         bo_add_32be(mvhd, i_movie_duration);  // duration
1689     } else {
1690         mvhd = box_full_new("mvhd", 1, 0);
1691         bo_add_64be(mvhd, i_timestamp);   // creation time
1692         bo_add_64be(mvhd, i_timestamp);   // modification time
1693         bo_add_32be(mvhd, i_movie_timescale);  // timescale
1694         bo_add_64be(mvhd, i_movie_duration);  // duration
1695     }
1696     bo_add_32be(mvhd, 0x10000);           // rate
1697     bo_add_16be(mvhd, 0x100);             // volume
1698     bo_add_16be(mvhd, 0);                 // reserved
1699     for (int i = 0; i < 2; i++)
1700         bo_add_32be(mvhd, 0);             // reserved
1701
1702     uint32_t mvhd_matrix[9] = { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
1703
1704     for (int i = 0; i < 9; i++)
1705         bo_add_32be(mvhd, mvhd_matrix[i]);// matrix
1706     for (int i = 0; i < 6; i++)
1707         bo_add_32be(mvhd, 0);             // pre-defined
1708
1709     /* Next available track id */
1710     bo_add_32be(mvhd, p_sys->i_nb_streams + 1); // next-track-id
1711
1712     box_gather(moov, mvhd);
1713
1714     for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
1715         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1716
1717         mtime_t i_stream_duration;
1718         if ( !p_sys->b_fragmented )
1719             i_stream_duration = p_stream->i_read_duration * i_movie_timescale / CLOCK_FREQ;
1720         else
1721             i_stream_duration = 0;
1722
1723         /* *** add /moov/trak *** */
1724         bo_t *trak = box_new("trak");
1725
1726         /* *** add /moov/trak/tkhd *** */
1727         bo_t *tkhd;
1728         if (!p_sys->b_64_ext) {
1729             if (p_sys->b_mov)
1730                 tkhd = box_full_new("tkhd", 0, 0x0f);
1731             else
1732                 tkhd = box_full_new("tkhd", 0, 1);
1733
1734             bo_add_32be(tkhd, i_timestamp);       // creation time
1735             bo_add_32be(tkhd, i_timestamp);       // modification time
1736             bo_add_32be(tkhd, p_stream->i_track_id);
1737             bo_add_32be(tkhd, 0);                     // reserved 0
1738             bo_add_32be(tkhd, i_stream_duration); // duration
1739         } else {
1740             if (p_sys->b_mov)
1741                 tkhd = box_full_new("tkhd", 1, 0x0f);
1742             else
1743                 tkhd = box_full_new("tkhd", 1, 1);
1744
1745             bo_add_64be(tkhd, i_timestamp);       // creation time
1746             bo_add_64be(tkhd, i_timestamp);       // modification time
1747             bo_add_32be(tkhd, p_stream->i_track_id);
1748             bo_add_32be(tkhd, 0);                     // reserved 0
1749             bo_add_64be(tkhd, i_stream_duration); // duration
1750         }
1751
1752         for (int i = 0; i < 2; i++)
1753             bo_add_32be(tkhd, 0);                 // reserved
1754         bo_add_16be(tkhd, 0);                     // layer
1755         bo_add_16be(tkhd, 0);                     // pre-defined
1756         // volume
1757         bo_add_16be(tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0);
1758         bo_add_16be(tkhd, 0);                     // reserved
1759         matrix_apply_rotation(&p_stream->fmt, mvhd_matrix);
1760         for (int i = 0; i < 9; i++)
1761             bo_add_32be(tkhd, mvhd_matrix[i]);    // matrix
1762         if (p_stream->fmt.i_cat == AUDIO_ES) {
1763             bo_add_32be(tkhd, 0);                 // width (presentation)
1764             bo_add_32be(tkhd, 0);                 // height(presentation)
1765         } else if (p_stream->fmt.i_cat == VIDEO_ES) {
1766             int i_width = p_stream->fmt.video.i_width << 16;
1767             if (p_stream->fmt.video.i_sar_num > 0 && p_stream->fmt.video.i_sar_den > 0) {
1768                 i_width = (int64_t)p_stream->fmt.video.i_sar_num *
1769                           ((int64_t)p_stream->fmt.video.i_width << 16) /
1770                           p_stream->fmt.video.i_sar_den;
1771             }
1772             // width (presentation)
1773             bo_add_32be(tkhd, i_width);
1774             // height(presentation)
1775             bo_add_32be(tkhd, p_stream->fmt.video.i_height << 16);
1776         } else {
1777             int i_width = 320 << 16;
1778             int i_height = 200;
1779             for (unsigned int i = 0; i < p_sys->i_nb_streams; i++) {
1780                 mp4_stream_t *tk = p_sys->pp_streams[i];
1781                 if (tk->fmt.i_cat == VIDEO_ES) {
1782                     if (tk->fmt.video.i_sar_num > 0 &&
1783                         tk->fmt.video.i_sar_den > 0)
1784                         i_width = (int64_t)tk->fmt.video.i_sar_num *
1785                                   ((int64_t)tk->fmt.video.i_width << 16) /
1786                                   tk->fmt.video.i_sar_den;
1787                     else
1788                         i_width = tk->fmt.video.i_width << 16;
1789                     i_height = tk->fmt.video.i_height;
1790                     break;
1791                 }
1792             }
1793             bo_add_32be(tkhd, i_width);     // width (presentation)
1794             bo_add_32be(tkhd, i_height << 16);    // height(presentation)
1795         }
1796
1797         box_gather(trak, tkhd);
1798
1799         /* *** add /moov/trak/edts and elst */
1800         if ( !p_sys->b_fragmented )
1801         {
1802             bo_t *edts = box_new("edts");
1803             bo_t *elst = box_full_new("elst", p_sys->b_64_ext ? 1 : 0, 0);
1804             if (p_stream->i_starttime > 0) {
1805                 bo_add_32be(elst, 2);
1806
1807                 if (p_sys->b_64_ext) {
1808                     bo_add_64be(elst, p_stream->i_starttime *
1809                                 i_movie_timescale / CLOCK_FREQ);
1810                     bo_add_64be(elst, -1);
1811                 } else {
1812                     bo_add_32be(elst, p_stream->i_starttime *
1813                                 i_movie_timescale / CLOCK_FREQ);
1814                     bo_add_32be(elst, -1);
1815                 }
1816                 bo_add_16be(elst, 1);
1817                 bo_add_16be(elst, 0);
1818             } else {
1819                 bo_add_32be(elst, 1);
1820             }
1821             if (p_sys->b_64_ext) {
1822                 bo_add_64be(elst, p_stream->i_read_duration *
1823                             i_movie_timescale / CLOCK_FREQ);
1824                 bo_add_64be(elst, 0);
1825             } else {
1826                 bo_add_32be(elst, p_stream->i_read_duration *
1827                             i_movie_timescale / CLOCK_FREQ);
1828                 bo_add_32be(elst, 0);
1829             }
1830             bo_add_16be(elst, 1);
1831             bo_add_16be(elst, 0);
1832
1833             box_gather(edts, elst);
1834             box_gather(trak, edts);
1835         }
1836
1837         /* *** add /moov/trak/mdia *** */
1838         bo_t *mdia = box_new("mdia");
1839
1840         /* media header */
1841         bo_t *mdhd;
1842         if (!p_sys->b_64_ext) {
1843             mdhd = box_full_new("mdhd", 0, 0);
1844             bo_add_32be(mdhd, i_timestamp);   // creation time
1845             bo_add_32be(mdhd, i_timestamp);   // modification time
1846             bo_add_32be(mdhd, p_stream->i_timescale); // timescale
1847             bo_add_32be(mdhd, i_stream_duration);  // duration
1848         } else {
1849             mdhd = box_full_new("mdhd", 1, 0);
1850             bo_add_64be(mdhd, i_timestamp);   // creation time
1851             bo_add_64be(mdhd, i_timestamp);   // modification time
1852             bo_add_32be(mdhd, p_stream->i_timescale); // timescale
1853             bo_add_64be(mdhd, i_stream_duration);  // duration
1854         }
1855
1856         if (p_stream->fmt.psz_language) {
1857             char *psz = p_stream->fmt.psz_language;
1858             const iso639_lang_t *pl = NULL;
1859             uint16_t lang = 0x0;
1860
1861             if (strlen(psz) == 2)
1862                 pl = GetLang_1(psz);
1863             else if (strlen(psz) == 3) {
1864                 pl = GetLang_2B(psz);
1865                 if (!strcmp(pl->psz_iso639_1, "??"))
1866                     pl = GetLang_2T(psz);
1867             }
1868
1869             if (pl && strcmp(pl->psz_iso639_1, "??"))
1870                 lang = ((pl->psz_iso639_2T[0] - 0x60) << 10) |
1871                        ((pl->psz_iso639_2T[1] - 0x60) <<  5) |
1872                        ((pl->psz_iso639_2T[2] - 0x60));
1873             bo_add_16be(mdhd, lang);          // language
1874         } else
1875             bo_add_16be(mdhd, 0   );          // language
1876         bo_add_16be(mdhd, 0   );              // predefined
1877         box_gather(mdia, mdhd);
1878
1879         /* handler reference */
1880         bo_t *hdlr = box_full_new("hdlr", 0, 0);
1881
1882         if (p_sys->b_mov)
1883             bo_add_fourcc(hdlr, "mhlr");         // media handler
1884         else
1885             bo_add_32be(hdlr, 0);
1886
1887         if (p_stream->fmt.i_cat == AUDIO_ES)
1888             bo_add_fourcc(hdlr, "soun");
1889         else if (p_stream->fmt.i_cat == VIDEO_ES)
1890             bo_add_fourcc(hdlr, "vide");
1891         else if (p_stream->fmt.i_cat == SPU_ES)
1892             bo_add_fourcc(hdlr, "text");
1893
1894         bo_add_32be(hdlr, 0);         // reserved
1895         bo_add_32be(hdlr, 0);         // reserved
1896         bo_add_32be(hdlr, 0);         // reserved
1897
1898         if (p_sys->b_mov)
1899             bo_add_8(hdlr, 12);   /* Pascal string for .mov */
1900
1901         if (p_stream->fmt.i_cat == AUDIO_ES)
1902             bo_add_mem(hdlr, 12, (uint8_t*)"SoundHandler");
1903         else if (p_stream->fmt.i_cat == VIDEO_ES)
1904             bo_add_mem(hdlr, 12, (uint8_t*)"VideoHandler");
1905         else
1906             bo_add_mem(hdlr, 12, (uint8_t*)"Text Handler");
1907
1908         if (!p_sys->b_mov)
1909             bo_add_8(hdlr, 0);   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
1910
1911         box_gather(mdia, hdlr);
1912
1913         /* minf*/
1914         bo_t *minf = box_new("minf");
1915
1916         /* add smhd|vmhd */
1917         if (p_stream->fmt.i_cat == AUDIO_ES) {
1918             bo_t *smhd;
1919
1920             smhd = box_full_new("smhd", 0, 0);
1921             bo_add_16be(smhd, 0);     // balance
1922             bo_add_16be(smhd, 0);     // reserved
1923
1924             box_gather(minf, smhd);
1925         } else if (p_stream->fmt.i_cat == VIDEO_ES) {
1926             bo_t *vmhd;
1927
1928             vmhd = box_full_new("vmhd", 0, 1);
1929             bo_add_16be(vmhd, 0);     // graphicsmode
1930             for (int i = 0; i < 3; i++)
1931                 bo_add_16be(vmhd, 0); // opcolor
1932
1933             box_gather(minf, vmhd);
1934         } else if (p_stream->fmt.i_cat == SPU_ES) {
1935             bo_t *gmhd = box_new("gmhd");
1936             bo_t *gmin = box_full_new("gmin", 0, 1);
1937
1938             bo_add_16be(gmin, 0);     // graphicsmode
1939             for (int i = 0; i < 3; i++)
1940                 bo_add_16be(gmin, 0); // opcolor
1941             bo_add_16be(gmin, 0);     // balance
1942             bo_add_16be(gmin, 0);     // reserved
1943
1944             box_gather(gmhd, gmin);
1945
1946             box_gather(minf, gmhd);
1947         }
1948
1949         /* dinf */
1950         bo_t *dinf = box_new("dinf");
1951         bo_t *dref = box_full_new("dref", 0, 0);
1952         bo_add_32be(dref, 1);
1953         bo_t *url = box_full_new("url ", 0, 0x01);
1954         box_gather(dref, url);
1955         box_gather(dinf, dref);
1956
1957         /* append dinf to mdia */
1958         box_gather(minf, dinf);
1959
1960         /* add stbl */
1961         bo_t *stbl;
1962         if ( p_sys->b_fragmented )
1963         {
1964             uint32_t i_backup = p_stream->i_entry_count;
1965             p_stream->i_entry_count = 0;
1966             stbl = GetStblBox(p_mux, p_stream);
1967             p_stream->i_entry_count = i_backup;
1968         }
1969         else
1970             stbl = GetStblBox(p_mux, p_stream);
1971
1972         /* append stbl to minf */
1973         p_stream->i_stco_pos += minf->len;
1974         box_gather(minf, stbl);
1975
1976         /* append minf to mdia */
1977         p_stream->i_stco_pos += mdia->len;
1978         box_gather(mdia, minf);
1979
1980         /* append mdia to trak */
1981         p_stream->i_stco_pos += trak->len;
1982         box_gather(trak, mdia);
1983
1984         /* append trak to moov */
1985         p_stream->i_stco_pos += moov->len;
1986         box_gather(moov, trak);
1987     }
1988
1989     /* Add user data tags */
1990     box_gather(moov, GetUdtaTag(p_mux));
1991
1992     if ( p_sys->b_fragmented )
1993     {
1994         bo_t *mvex = box_new("mvex");
1995         for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++)
1996         {
1997             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1998
1999             /* Try to find some defaults */
2000             if ( p_stream->i_entry_count )
2001             {
2002                 // FIXME: find highest occurence
2003                 p_stream->i_trex_length = p_stream->entry[0].i_length;
2004                 p_stream->i_trex_size = p_stream->entry[0].i_size;
2005             }
2006
2007             /* *** add /mvex/trex *** */
2008             bo_t *trex = box_full_new("trex", 0, 0);
2009             bo_add_32be(trex, p_stream->i_track_id);
2010             bo_add_32be(trex, 1); // sample desc index
2011             bo_add_32be(trex, (uint64_t)p_stream->i_trex_length * p_stream->i_timescale / CLOCK_FREQ); // sample duration
2012             bo_add_32be(trex, p_stream->i_trex_size); // sample size
2013             bo_add_32be(trex, 0); // sample flags
2014             box_gather(mvex, trex);
2015         }
2016         box_gather(moov, mvex);
2017     }
2018
2019     box_fix(moov);
2020     return moov;
2021 }
2022
2023 /****************************************************************************/
2024
2025 static void bo_init(bo_t *p_bo)
2026 {
2027     p_bo->len = 0;
2028     p_bo->b = block_Alloc(1024);
2029 }
2030
2031 static void bo_add_8(bo_t *p_bo, uint8_t i)
2032 {
2033     if (p_bo->len >= p_bo->b->i_buffer)
2034         p_bo->b = block_Realloc(p_bo->b, 0, p_bo->b->i_buffer + 1024);
2035
2036     p_bo->b->p_buffer[p_bo->len++] = i;
2037 }
2038
2039 static void bo_add_16be(bo_t *p_bo, uint16_t i)
2040 {
2041     bo_add_8(p_bo, ((i >> 8) &0xff));
2042     bo_add_8(p_bo, i &0xff);
2043 }
2044
2045 static void bo_add_24be(bo_t *p_bo, uint32_t i)
2046 {
2047     bo_add_8(p_bo, ((i >> 16) &0xff));
2048     bo_add_8(p_bo, ((i >> 8) &0xff));
2049     bo_add_8(p_bo, (  i &0xff));
2050 }
2051 static void bo_add_32be(bo_t *p_bo, uint32_t i)
2052 {
2053     bo_add_16be(p_bo, ((i >> 16) &0xffff));
2054     bo_add_16be(p_bo, i &0xffff);
2055 }
2056
2057 static void bo_fix_32be (bo_t *p_bo, int i_pos, uint32_t i)
2058 {
2059     p_bo->b->p_buffer[i_pos    ] = (i >> 24)&0xff;
2060     p_bo->b->p_buffer[i_pos + 1] = (i >> 16)&0xff;
2061     p_bo->b->p_buffer[i_pos + 2] = (i >>  8)&0xff;
2062     p_bo->b->p_buffer[i_pos + 3] = (i      )&0xff;
2063 }
2064
2065 static void bo_add_64be(bo_t *p_bo, uint64_t i)
2066 {
2067     bo_add_32be(p_bo, ((i >> 32) &0xffffffff));
2068     bo_add_32be(p_bo, i &0xffffffff);
2069 }
2070
2071 static void bo_add_fourcc(bo_t *p_bo, const char *fcc)
2072 {
2073     bo_add_8(p_bo, fcc[0]);
2074     bo_add_8(p_bo, fcc[1]);
2075     bo_add_8(p_bo, fcc[2]);
2076     bo_add_8(p_bo, fcc[3]);
2077 }
2078
2079 static void bo_add_mem(bo_t *p_bo, int i_size, uint8_t *p_mem)
2080 {
2081     for (int i = 0; i < i_size; i++)
2082         bo_add_8(p_bo, p_mem[i]);
2083 }
2084
2085 static void bo_add_descr(bo_t *p_bo, uint8_t tag, uint32_t size)
2086 {
2087     bo_add_8(p_bo, tag);
2088     for (int i = 3; i>0; i--)
2089         bo_add_8(p_bo, (size>>(7*i)) | 0x80);
2090     bo_add_8(p_bo, size & 0x7F);
2091 }
2092
2093 static bo_t *box_new(const char *fcc)
2094 {
2095     bo_t *box = malloc(sizeof(*box));
2096     if (!box)
2097         return NULL;
2098
2099     bo_init(box);
2100
2101     bo_add_32be  (box, 0);
2102     bo_add_fourcc(box, fcc);
2103
2104     return box;
2105 }
2106
2107 static bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f)
2108 {
2109     bo_t *box = box_new(fcc);
2110     if (!box)
2111         return NULL;
2112
2113     bo_add_8     (box, v);
2114     bo_add_24be  (box, f);
2115
2116     return box;
2117 }
2118
2119 static void box_free(bo_t *box)
2120 {
2121     block_Release(box->b);
2122     free(box);
2123 }
2124
2125 static void box_fix(bo_t *box)
2126 {
2127     box->b->p_buffer[0] = box->len >> 24;
2128     box->b->p_buffer[1] = box->len >> 16;
2129     box->b->p_buffer[2] = box->len >>  8;
2130     box->b->p_buffer[3] = box->len;
2131 }
2132
2133 static void box_gather (bo_t *box, bo_t *box2)
2134 {
2135     box_fix(box2);
2136     box->b = block_Realloc(box->b, 0, box->len + box2->len);
2137     memcpy(&box->b->p_buffer[box->len], box2->b->p_buffer, box2->len);
2138     box->len += box2->len;
2139     box_free(box2);
2140 }
2141
2142 static void box_send(sout_mux_t *p_mux,  bo_t *box)
2143 {
2144     box->b->i_buffer = box->len;
2145     sout_AccessOutWrite(p_mux->p_access, box->b);
2146     free(box);
2147 }
2148
2149 static int64_t get_timestamp(void)
2150 {
2151     int64_t i_timestamp = time(NULL);
2152
2153     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
2154     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
2155
2156     return i_timestamp;
2157 }
2158
2159 /***************************************************************************
2160     MP4 Live submodule
2161 ****************************************************************************/
2162 #define FRAGMENT_LENGTH  (CLOCK_FREQ * 3/2)
2163
2164 #define ENQUEUE_ENTRY(object, entry) \
2165     do {\
2166         if (object.p_last)\
2167             object.p_last->p_next = entry;\
2168         object.p_last = entry;\
2169         if (!object.p_first)\
2170             object.p_first = entry;\
2171     } while(0)
2172
2173 #define DEQUEUE_ENTRY(object, entry) \
2174     do {\
2175         entry = object.p_first;\
2176         if (object.p_last == entry)\
2177             object.p_last = NULL;\
2178         object.p_first = object.p_first->p_next;\
2179         entry->p_next = NULL;\
2180     } while(0)
2181
2182 /* Creates mfra/traf index entries */
2183 static void AddKeyframeEntry(mp4_stream_t *p_stream, const uint64_t i_moof_pos,
2184                              const uint8_t i_traf, const uint32_t i_sample,
2185                              const mtime_t i_time)
2186 {
2187     /* alloc or realloc */
2188     mp4_fragindex_t *p_entries = p_stream->p_indexentries;
2189     if (p_stream->i_indexentries >= p_stream->i_indexentriesmax)
2190     {
2191         p_stream->i_indexentriesmax += 256;
2192         p_entries = xrealloc(p_stream->p_indexentries,
2193                              p_stream->i_indexentriesmax * sizeof(mp4_fragindex_t));
2194         if (p_entries) /* realloc can fail */
2195             p_stream->p_indexentries = p_entries;
2196     }
2197
2198     mtime_t i_last_entry_time;
2199     if (p_stream->i_indexentries)
2200         i_last_entry_time = p_stream->p_indexentries[p_stream->i_indexentries - 1].i_time;
2201     else
2202         i_last_entry_time = 0;
2203
2204     if (p_entries && i_time - i_last_entry_time >= CLOCK_FREQ * 2)
2205     {
2206         mp4_fragindex_t *p_indexentry = &p_stream->p_indexentries[p_stream->i_indexentries];
2207         p_indexentry->i_time = i_time;
2208         p_indexentry->i_moofoffset = i_moof_pos;
2209         p_indexentry->i_sample = i_sample;
2210         p_indexentry->i_traf = i_traf;
2211         p_indexentry->i_trun = 1;
2212         p_stream->i_indexentries++;
2213     }
2214 }
2215
2216 /* Creates moof box and traf/trun information.
2217  * Single run per traf is absolutely not optimal as interleaving should be done
2218  * using runs and not limiting moof size, but creating an relative offset only
2219  * requires base_offset_is_moof and then comply to late iso brand spec which
2220  * breaks clients. */
2221 static bo_t *GetMoofBox(sout_mux_t *p_mux, size_t *pi_mdat_total_size,
2222                         mtime_t i_barrier_time, const uint64_t i_write_pos)
2223 {
2224     sout_mux_sys_t *p_sys = p_mux->p_sys;
2225
2226     bo_t            *moof, *mfhd;
2227     size_t           i_fixupoffset = 0;
2228
2229     *pi_mdat_total_size = 0;
2230
2231     moof = box_new("moof");
2232
2233     /* *** add /moof/mfhd *** */
2234
2235     mfhd = box_full_new("mfhd", 0, 0);
2236     bo_add_32be(mfhd, p_sys->i_mfhd_sequence++);   // sequence number
2237
2238     box_gather(moof, mfhd);
2239
2240     for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++)
2241     {
2242         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
2243
2244         /* *** add /moof/traf *** */
2245         bo_t *traf = box_new("traf");
2246
2247         uint32_t i_sample = 0;
2248         mtime_t i_time = p_stream->i_written_duration;
2249         bool b_allsamesize = true;
2250         bool b_allsamelength = true;
2251         if ( p_stream->read.p_first )
2252         {
2253             mp4_fragentry_t *p_entry = p_stream->read.p_first->p_next;
2254             while (p_entry && (b_allsamelength || b_allsamesize))
2255             {
2256                 /* compare against queue head */
2257                 b_allsamelength &= ( p_entry->p_block->i_length == p_stream->read.p_first->p_block->i_length );
2258                 b_allsamesize &= ( p_entry->p_block->i_buffer == p_stream->read.p_first->p_block->i_buffer );
2259                 p_entry = p_entry->p_next;
2260             }
2261         }
2262
2263         uint16_t i_tfhd_flags = 0x0;
2264         if (p_stream->read.p_first)
2265         {
2266             /* Current segment have all same duration value, different than trex's default */
2267             if (b_allsamelength &&
2268                 p_stream->read.p_first->p_block->i_length != p_stream->i_trex_length &&
2269                 p_stream->read.p_first->p_block->i_length)
2270                     i_tfhd_flags |= MP4_TFHD_DFLT_SAMPLE_DURATION;
2271
2272             /* Current segment have all same size value, different than trex's default */
2273             if (b_allsamesize &&
2274                 p_stream->read.p_first->p_block->i_buffer != p_stream->i_trex_size &&
2275                 p_stream->read.p_first->p_block->i_buffer)
2276                     i_tfhd_flags |= MP4_TFHD_DFLT_SAMPLE_SIZE;
2277         }
2278         else
2279         {
2280             /* We have no samples */
2281             i_tfhd_flags |= MP4_TFHD_DURATION_IS_EMPTY;
2282         }
2283
2284         /* *** add /moof/traf/tfhd *** */
2285         bo_t *tfhd = box_full_new("tfhd", 0, i_tfhd_flags);
2286         bo_add_32be(tfhd, p_stream->i_track_id);
2287
2288         /* set the local sample duration default */
2289         if (i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION)
2290             bo_add_32be(tfhd, p_stream->read.p_first->p_block->i_length * p_stream->i_timescale / CLOCK_FREQ);
2291
2292         /* set the local sample size default */
2293         if (i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE)
2294             bo_add_32be(tfhd, p_stream->read.p_first->p_block->i_buffer);
2295
2296         box_gather(traf, tfhd);
2297
2298         /* *** add /moof/traf/trun *** */
2299         if (p_stream->read.p_first)
2300         {
2301             uint16_t i_trun_flags = 0x0;
2302
2303             if (p_stream->b_hasiframes && !(p_stream->read.p_first->p_block->i_flags & BLOCK_FLAG_TYPE_I))
2304                 i_trun_flags |= MP4_TRUN_FIRST_FLAGS;
2305
2306             if (!b_allsamelength ||
2307                 ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_DURATION) && p_stream->i_trex_length == 0 ))
2308                 i_trun_flags |= MP4_TRUN_SAMPLE_DURATION;
2309
2310             if (!b_allsamesize ||
2311                 ( !(i_tfhd_flags & MP4_TFHD_DFLT_SAMPLE_SIZE) && p_stream->i_trex_size == 0 ))
2312                 i_trun_flags |= MP4_TRUN_SAMPLE_SIZE;
2313
2314             if (p_stream->b_hasbframes)
2315                 i_trun_flags |= MP4_TRUN_SAMPLE_TIME_OFFSET;
2316
2317             if (i_fixupoffset == 0)
2318                 i_trun_flags |= MP4_TRUN_DATA_OFFSET;
2319
2320             bo_t *trun = box_full_new("trun", 0, i_trun_flags);
2321
2322             /* count entries */
2323             uint32_t i_entry_count = 0;
2324             mtime_t i_run_time = p_stream->i_written_duration;
2325             mp4_fragentry_t *p_entry = p_stream->read.p_first;
2326             while(p_entry)
2327             {
2328                 if ( i_barrier_time && i_run_time + p_entry->p_block->i_length > i_barrier_time )
2329                     break;
2330                 i_entry_count++;
2331                 i_run_time += p_entry->p_block->i_length;
2332                 p_entry = p_entry->p_next;
2333             }
2334             bo_add_32be(trun, i_entry_count); // sample count
2335
2336             if (i_trun_flags & MP4_TRUN_DATA_OFFSET)
2337             {
2338                 i_fixupoffset = moof->len + traf->len + trun->len;
2339                 bo_add_32be(trun, 0xdeadbeef); // data offset
2340             }
2341
2342             if (i_trun_flags & MP4_TRUN_FIRST_FLAGS)
2343                 bo_add_32be(trun, 1<<16); // flag as non keyframe
2344
2345             while(p_stream->read.p_first && i_entry_count)
2346             {
2347                 DEQUEUE_ENTRY(p_stream->read, p_entry);
2348
2349                 if (i_trun_flags & MP4_TRUN_SAMPLE_DURATION)
2350                     bo_add_32be(trun, p_entry->p_block->i_length * p_stream->i_timescale / CLOCK_FREQ); // sample duration
2351
2352                 if (i_trun_flags & MP4_TRUN_SAMPLE_SIZE)
2353                     bo_add_32be(trun, p_entry->p_block->i_buffer); // sample size
2354
2355                 if (i_trun_flags & MP4_TRUN_SAMPLE_TIME_OFFSET)
2356                 {
2357                     uint32_t i_diff = 0;
2358                     if ( p_entry->p_block->i_dts  > VLC_TS_INVALID &&
2359                          p_entry->p_block->i_pts > p_entry->p_block->i_dts )
2360                     {
2361                         i_diff = p_entry->p_block->i_pts - p_entry->p_block->i_dts;
2362                     }
2363                     bo_add_32be(trun, i_diff * p_stream->i_timescale / CLOCK_FREQ); // ctts
2364                 }
2365
2366                 *pi_mdat_total_size += p_entry->p_block->i_buffer;
2367
2368                 ENQUEUE_ENTRY(p_stream->towrite, p_entry);
2369                 i_entry_count--;
2370                 i_sample++;
2371
2372                 /* Add keyframe entry if needed */
2373                 if (p_stream->b_hasiframes && (p_entry->p_block->i_flags & BLOCK_FLAG_TYPE_I) &&
2374                     (p_stream->fmt.i_cat == VIDEO_ES || p_stream->fmt.i_cat == AUDIO_ES))
2375                 {
2376                     AddKeyframeEntry(p_stream, i_write_pos, i_trak, i_sample, i_time);
2377                 }
2378
2379                 i_time += p_entry->p_block->i_length;
2380             }
2381
2382             box_gather(traf, trun);
2383         }
2384
2385         box_gather(moof, traf);
2386     }
2387
2388     box_fix(moof);
2389
2390     /* do tfhd base data offset fixup */
2391     if (i_fixupoffset)
2392     {
2393         /* mdat will follow moof */
2394         SetDWBE(moof->b->p_buffer + i_fixupoffset, moof->len + 8);
2395     }
2396
2397     /* set iframe flag, so the streaming server always starts from moof */
2398     moof->b->i_flags |= BLOCK_FLAG_TYPE_I;
2399
2400     return moof;
2401 }
2402
2403 static void WriteFragmentMDAT(sout_mux_t *p_mux, size_t i_total_size)
2404 {
2405     sout_mux_sys_t *p_sys = p_mux->p_sys;
2406
2407     /* Now add mdat header */
2408     bo_t *mdat = box_new("mdat");
2409     /* force update of real size */
2410     mdat->b->i_buffer = mdat->len;
2411     assert(mdat->len==8);
2412     mdat->len += i_total_size;
2413     box_fix(mdat);
2414     p_sys->i_pos += mdat->b->i_buffer;
2415     /* only write header */
2416     sout_AccessOutWrite(p_mux->p_access, mdat->b);
2417     free(mdat);
2418     /* Header and its size are written and good, now write content */
2419     for (unsigned int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++)
2420     {
2421         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
2422
2423         while(p_stream->towrite.p_first)
2424         {
2425             mp4_fragentry_t *p_entry = p_stream->towrite.p_first;
2426             p_sys->i_pos += p_entry->p_block->i_buffer;
2427             p_stream->i_written_duration += p_entry->p_block->i_length;
2428
2429             p_entry->p_block->i_flags &= ~BLOCK_FLAG_TYPE_I; // clear flag for http stream
2430             sout_AccessOutWrite(p_mux->p_access, p_entry->p_block);
2431
2432             p_stream->towrite.p_first = p_entry->p_next;
2433             free(p_entry);
2434             if (!p_stream->towrite.p_first)
2435                 p_stream->towrite.p_last = NULL;
2436         }
2437     }
2438 }
2439
2440 static bo_t *GetMfraBox(sout_mux_t *p_mux)
2441 {
2442     sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
2443     bo_t *mfra = NULL;
2444     for (unsigned int i = 0; i < p_sys->i_nb_streams; i++)
2445     {
2446         mp4_stream_t *p_stream = p_sys->pp_streams[i];
2447         if (p_stream->i_indexentries)
2448         {
2449             bo_t *tfra = box_full_new("tfra", 0, 0x0);
2450             if (!tfra) continue;
2451             bo_add_32be(tfra, p_stream->i_track_id);
2452             bo_add_32be(tfra, 0x3); // reserved + lengths (1,1,4)=>(0,0,3)
2453             bo_add_32be(tfra, p_stream->i_indexentries);
2454             for(uint32_t i_index=0; i_index<p_stream->i_indexentries; i_index++)
2455             {
2456                 const mp4_fragindex_t *p_indexentry = &p_stream->p_indexentries[i_index];
2457                 bo_add_32be(tfra, p_indexentry->i_time);
2458                 bo_add_32be(tfra, p_indexentry->i_moofoffset);
2459                 assert(sizeof(p_indexentry->i_traf==1)); /* guard against sys changes */
2460                 assert(sizeof(p_indexentry->i_trun==1));
2461                 assert(sizeof(p_indexentry->i_sample==4));
2462                 bo_add_8(tfra, p_indexentry->i_traf);
2463                 bo_add_8(tfra, p_indexentry->i_trun);
2464                 bo_add_32be(tfra, p_indexentry->i_sample);
2465             }
2466
2467             if (!mfra && !(mfra = box_new("mfra")))
2468             {
2469                 box_free(tfra);
2470                 return NULL;
2471             }
2472
2473             box_gather(mfra,tfra);
2474         }
2475     }
2476     return mfra;
2477 }
2478
2479 static void FlushHeader(sout_mux_t *p_mux)
2480 {
2481     sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
2482
2483     /* Now add ftyp header */
2484     bo_t *ftyp = box_new("ftyp");
2485     bo_add_fourcc(ftyp, "isom");
2486     bo_add_32be  (ftyp, 0); // minor version
2487     box_fix(ftyp);
2488
2489     bo_t *moov = GetMoovBox(p_mux);
2490
2491     /* merge into a single block */
2492     box_gather(ftyp, moov);
2493
2494     /* add header flag for streaming server */
2495     ftyp->b->i_flags |= BLOCK_FLAG_HEADER;
2496     p_sys->i_pos += ftyp->len;
2497     box_send(p_mux, ftyp);
2498     p_sys->b_header_sent = true;
2499 }
2500
2501 static int OpenFrag(vlc_object_t *p_this)
2502 {
2503     sout_mux_t *p_mux = (sout_mux_t*) p_this;
2504     sout_mux_sys_t *p_sys = malloc(sizeof(sout_mux_sys_t));
2505     if (!p_sys)
2506         return VLC_ENOMEM;
2507
2508     p_mux->p_sys = (sout_mux_sys_t *) p_sys;
2509     p_mux->pf_control   = Control;
2510     p_mux->pf_addstream = AddStream;
2511     p_mux->pf_delstream = DelStream;
2512     p_mux->pf_mux       = MuxFrag;
2513
2514     /* unused */
2515     p_sys->b_mov        = false;
2516     p_sys->b_3gp        = false;
2517     p_sys->b_64_ext     = false;
2518     /* !unused */
2519
2520     p_sys->i_pos        = 0;
2521     p_sys->i_nb_streams = 0;
2522     p_sys->pp_streams   = NULL;
2523     p_sys->i_mdat_pos   = 0;
2524     p_sys->i_read_duration   = 0;
2525     p_sys->i_written_duration= 0;
2526
2527     p_sys->b_header_sent = false;
2528     p_sys->b_fragmented  = true;
2529     p_sys->i_mfhd_sequence = 1;
2530
2531     return VLC_SUCCESS;
2532 }
2533
2534 static void WriteFragments(sout_mux_t *p_mux, bool b_flush)
2535 {
2536     sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
2537     bo_t *moof = NULL;
2538     mtime_t i_barrier_time = p_sys->i_written_duration + FRAGMENT_LENGTH;
2539     size_t i_mdat_size = 0;
2540     bool b_has_samples = false;
2541
2542     for (unsigned int i = 0; i < p_sys->i_nb_streams; i++)
2543     {
2544         const mp4_stream_t *p_stream = p_sys->pp_streams[i];
2545         if (p_stream->read.p_first)
2546         {
2547             b_has_samples = true;
2548
2549             /* set a barrier so we try to align to keyframe */
2550             if (p_stream->b_hasiframes &&
2551                     p_stream->i_last_iframe_time > p_stream->i_written_duration &&
2552                     (p_stream->fmt.i_cat == VIDEO_ES ||
2553                      p_stream->fmt.i_cat == AUDIO_ES) )
2554             {
2555                 i_barrier_time = __MIN(i_barrier_time, p_stream->i_last_iframe_time);
2556             }
2557         }
2558     }
2559
2560     if (!p_sys->b_header_sent)
2561         FlushHeader(p_mux);
2562
2563     if (b_has_samples)
2564         moof = GetMoofBox(p_mux, &i_mdat_size, (b_flush)?0:i_barrier_time, p_sys->i_pos);
2565
2566     if (moof && i_mdat_size == 0)
2567     {
2568         block_Release(moof->b);
2569         FREENULL(moof);
2570     }
2571
2572     if (moof)
2573     {
2574         msg_Dbg(p_mux, "writing moof @ %"PRId64, p_sys->i_pos);
2575         p_sys->i_pos += moof->len;
2576         assert(moof->b->i_flags & BLOCK_FLAG_TYPE_I); /* http sout */
2577         box_send(p_mux, moof);
2578         msg_Dbg(p_mux, "writing mdat @ %"PRId64, p_sys->i_pos);
2579         WriteFragmentMDAT(p_mux, i_mdat_size);
2580
2581         /* update iframe point */
2582         for (unsigned int i = 0; i < p_sys->i_nb_streams; i++)
2583         {
2584             mp4_stream_t *p_stream = p_sys->pp_streams[i];
2585             p_stream->i_last_iframe_time = 0;
2586         }
2587     }
2588 }
2589
2590 /* Do an entry length fixup using only its own info.
2591  * This is the end boundary case. */
2592 static void LengthLocalFixup(sout_mux_t *p_mux, const mp4_stream_t *p_stream, block_t *p_entrydata)
2593 {
2594     if ( p_stream->fmt.i_cat == VIDEO_ES )
2595     {
2596         p_entrydata->i_length = CLOCK_FREQ *
2597                 p_stream->fmt.video.i_frame_rate_base /
2598                 p_stream->fmt.video.i_frame_rate;
2599         msg_Dbg(p_mux, "video track %d fixup to %"PRId64" for sample %u",
2600                 p_stream->i_track_id, p_entrydata->i_length, p_stream->i_entry_count - 1);
2601     }
2602     else if (p_stream->fmt.i_cat == AUDIO_ES &&
2603              p_stream->fmt.audio.i_rate &&
2604              p_entrydata->i_nb_samples)
2605     {
2606         p_entrydata->i_length = CLOCK_FREQ * p_entrydata->i_nb_samples /
2607                 p_stream->fmt.audio.i_rate;
2608         msg_Dbg(p_mux, "audio track %d fixup to %"PRId64" for sample %u",
2609                 p_stream->i_track_id, p_entrydata->i_length, p_stream->i_entry_count - 1);
2610     }
2611     else
2612     {
2613         msg_Warn(p_mux, "unknown length for track %d sample %u",
2614                  p_stream->i_track_id, p_stream->i_entry_count - 1);
2615         p_entrydata->i_length = 1;
2616     }
2617 }
2618
2619 static void CleanupFrag(sout_mux_sys_t *p_sys)
2620 {
2621     for (unsigned int i = 0; i < p_sys->i_nb_streams; i++)
2622     {
2623         mp4_stream_t *p_stream = p_sys->pp_streams[i];
2624         if (p_stream->p_held_entry)
2625         {
2626             block_Release(p_stream->p_held_entry->p_block);
2627             free(p_stream->p_held_entry);
2628         }
2629         while(p_stream->read.p_first)
2630         {
2631             mp4_fragentry_t *p_next = p_stream->read.p_first->p_next;
2632             block_Release(p_stream->read.p_first->p_block);
2633             free(p_stream->read.p_first);
2634             p_stream->read.p_first = p_next;
2635         }
2636         while(p_stream->towrite.p_first)
2637         {
2638             mp4_fragentry_t *p_next = p_stream->towrite.p_first->p_next;
2639             block_Release(p_stream->towrite.p_first->p_block);
2640             free(p_stream->towrite.p_first);
2641             p_stream->towrite.p_first = p_next;
2642         }
2643         free(p_stream->p_indexentries);
2644     }
2645     free(p_sys);
2646 }
2647
2648 static void CloseFrag(vlc_object_t *p_this)
2649 {
2650     sout_mux_t *p_mux = (sout_mux_t *) p_this;
2651     sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
2652
2653     /* Flush remaining entries */
2654     for (unsigned int i = 0; i < p_sys->i_nb_streams; i++)
2655     {
2656         mp4_stream_t *p_stream = p_sys->pp_streams[i];
2657         if (p_stream->p_held_entry)
2658         {
2659             if (p_stream->p_held_entry->p_block->i_length < 1)
2660                 LengthLocalFixup(p_mux, p_stream, p_stream->p_held_entry->p_block);
2661             ENQUEUE_ENTRY(p_stream->read, p_stream->p_held_entry);
2662             p_stream->p_held_entry = NULL;
2663         }
2664     }
2665
2666     /* and force creating a fragment from it */
2667     WriteFragments(p_mux, true);
2668
2669     /* Write indexes, but only for non streamed content
2670        as they refer to moof by absolute position */
2671     if (!strcmp(p_mux->psz_mux, "mp4frag"))
2672     {
2673         bo_t *mfra = GetMfraBox(p_mux);
2674         if (mfra)
2675         {
2676             bo_t *mfro = box_full_new("mfro", 0, 0x0);
2677             if (mfro)
2678             {
2679                 box_fix(mfra);
2680                 bo_add_32be(mfro, mfra->len + MP4_MFRO_BOXSIZE);
2681                 box_gather(mfra, mfro);
2682             }
2683             box_send(p_mux, mfra);
2684         }
2685     }
2686
2687     CleanupFrag(p_sys);
2688 }
2689
2690 static int MuxFrag(sout_mux_t *p_mux)
2691 {
2692     sout_mux_sys_t *p_sys = (sout_mux_sys_t*) p_mux->p_sys;
2693
2694     int i_stream = sout_MuxGetStream(p_mux, 1, NULL);
2695     if (i_stream < 0)
2696         return VLC_SUCCESS;
2697     sout_input_t *p_input  = p_mux->pp_inputs[i_stream];
2698     mp4_stream_t *p_stream = (mp4_stream_t*) p_input->p_sys;
2699     block_t *p_currentblock = block_FifoGet(p_input->p_fifo);
2700
2701     /* do block conversion */
2702     switch(p_stream->fmt.i_codec)
2703     {
2704     case VLC_CODEC_H264:
2705     case VLC_CODEC_HEVC:
2706         p_currentblock = ConvertFromAnnexB(p_currentblock);
2707         break;
2708     case VLC_CODEC_SUBT:
2709         p_currentblock = ConvertSUBT(p_currentblock);
2710         break;
2711     default:
2712         break;
2713     }
2714
2715     /* If we have a previous entry for outgoing queue */
2716     if (p_stream->p_held_entry)
2717     {
2718         block_t *p_heldblock = p_stream->p_held_entry->p_block;
2719
2720         /* Fix previous block length from current */
2721         if (p_heldblock->i_length < 1)
2722         {
2723
2724             /* Fix using dts if not on a boundary */
2725             if ((p_currentblock->i_flags & BLOCK_FLAG_DISCONTINUITY) == 0)
2726                 p_heldblock->i_length = p_currentblock->i_dts - p_heldblock->i_dts;
2727
2728             if (p_heldblock->i_length < 1)
2729                 LengthLocalFixup(p_mux, p_stream, p_heldblock);
2730         }
2731
2732         /* enqueue */
2733         ENQUEUE_ENTRY(p_stream->read, p_stream->p_held_entry);
2734         p_stream->p_held_entry = NULL;
2735
2736         if (p_stream->b_hasiframes && (p_heldblock->i_flags & BLOCK_FLAG_TYPE_I) &&
2737             p_stream->i_read_duration - p_sys->i_written_duration < FRAGMENT_LENGTH)
2738         {
2739             /* Flag the last iframe time, we'll use it as boundary so it will start
2740                next fragment */
2741             p_stream->i_last_iframe_time = p_stream->i_read_duration;
2742         }
2743
2744         /* update buffered time */
2745         p_stream->i_read_duration += __MAX(0, p_heldblock->i_length);
2746     }
2747
2748
2749     /* set temp entry */
2750     p_stream->p_held_entry = malloc(sizeof(mp4_fragentry_t));
2751     if (unlikely(!p_stream->p_held_entry))
2752         return VLC_ENOMEM;
2753
2754     p_stream->p_held_entry->p_block  = p_currentblock;
2755     p_stream->p_held_entry->i_run    = p_stream->i_current_run;
2756     p_stream->p_held_entry->p_next   = NULL;
2757
2758     if (p_stream->fmt.i_cat == VIDEO_ES )
2759     {
2760         if (!p_stream->b_hasiframes && (p_currentblock->i_flags & BLOCK_FLAG_TYPE_I))
2761             p_stream->b_hasiframes = true;
2762
2763         if (!p_stream->b_hasbframes && p_currentblock->i_dts > VLC_TS_INVALID &&
2764             p_currentblock->i_pts > p_currentblock->i_dts)
2765             p_stream->b_hasbframes = true;
2766     }
2767
2768     /* Update the global fragment/media duration */
2769     mtime_t i_min_read_duration = p_stream->i_read_duration;
2770     mtime_t i_min_written_duration = p_stream->i_written_duration;
2771     for (unsigned int i=0; i<p_sys->i_nb_streams; i++)
2772     {
2773         const mp4_stream_t *p_s = p_sys->pp_streams[i];
2774         if (p_s->fmt.i_cat != VIDEO_ES && p_s->fmt.i_cat != AUDIO_ES)
2775             continue;
2776         if (p_s->i_read_duration < i_min_read_duration)
2777             i_min_read_duration = p_s->i_read_duration;
2778
2779         if (p_s->i_written_duration < i_min_written_duration)
2780             i_min_written_duration = p_s->i_written_duration;
2781     }
2782     p_sys->i_read_duration = i_min_read_duration;
2783     p_sys->i_written_duration = i_min_written_duration;
2784
2785     /* we have prerolled enough to know all streams, and have enough date to create a fragment */
2786     if (p_stream->read.p_first && p_sys->i_read_duration - p_sys->i_written_duration >= FRAGMENT_LENGTH)
2787         WriteFragments(p_mux, false);
2788
2789     return VLC_SUCCESS;
2790 }