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