]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
mux: mp4: compress stsz entries
[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
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48 #define FASTSTART_TEXT N_("Create \"Fast Start\" files")
49 #define FASTSTART_LONGTEXT N_(\
50     "Create \"Fast Start\" files. " \
51     "\"Fast Start\" files are optimized for downloads and allow the user " \
52     "to start previewing the file while it is downloading.")
53
54 static int  Open   (vlc_object_t *);
55 static void Close  (vlc_object_t *);
56
57 #define SOUT_CFG_PREFIX "sout-mp4-"
58
59 vlc_module_begin ()
60     set_description(N_("MP4/MOV muxer"))
61     set_category(CAT_SOUT)
62     set_subcategory(SUBCAT_SOUT_MUX)
63     set_shortname("MP4")
64
65     add_bool(SOUT_CFG_PREFIX "faststart", true,
66               FASTSTART_TEXT, FASTSTART_LONGTEXT,
67               true)
68     set_capability("sout mux", 5)
69     add_shortcut("mp4", "mov", "3gp")
70     set_callbacks(Open, Close)
71 vlc_module_end ()
72
73 /*****************************************************************************
74  * Exported prototypes
75  *****************************************************************************/
76 static const char *const ppsz_sout_options[] = {
77     "faststart", NULL
78 };
79
80 static int Control(sout_mux_t *, int, va_list);
81 static int AddStream(sout_mux_t *, sout_input_t *);
82 static int DelStream(sout_mux_t *, sout_input_t *);
83 static int Mux      (sout_mux_t *);
84
85 /*****************************************************************************
86  * Local prototypes
87  *****************************************************************************/
88 typedef struct
89 {
90     uint64_t i_pos;
91     int      i_size;
92
93     mtime_t  i_pts_dts;
94     mtime_t  i_length;
95     unsigned int i_flags;
96
97 } mp4_entry_t;
98
99 typedef struct
100 {
101     es_format_t   fmt;
102     int           i_track_id;
103
104     /* index */
105     unsigned int i_entry_count;
106     unsigned int i_entry_max;
107     mp4_entry_t  *entry;
108     int64_t      i_length_neg;
109
110     /* stats */
111     int64_t      i_dts_start;
112     int64_t      i_duration;
113
114     /* for later stco fix-up (fast start files) */
115     uint64_t i_stco_pos;
116     bool b_stco64;
117
118     /* for spu */
119     int64_t i_last_dts;
120
121 } mp4_stream_t;
122
123 struct sout_mux_sys_t
124 {
125     bool b_mov;
126     bool b_3gp;
127     bool b_64_ext;
128     bool b_fast_start;
129
130     uint64_t i_mdat_pos;
131     uint64_t i_pos;
132
133     int64_t  i_dts_start;
134
135     int          i_nb_streams;
136     mp4_stream_t **pp_streams;
137 };
138
139 typedef struct bo_t
140 {
141     block_t    *b;
142     size_t     len;
143 } bo_t;
144
145 static void bo_init     (bo_t *);
146 static void bo_add_8    (bo_t *, uint8_t);
147 static void bo_add_16be (bo_t *, uint16_t);
148 static void bo_add_24be (bo_t *, uint32_t);
149 static void bo_add_32be (bo_t *, uint32_t);
150 static void bo_add_64be (bo_t *, uint64_t);
151 static void bo_add_fourcc(bo_t *, const char *);
152 static void bo_add_mem  (bo_t *, int , uint8_t *);
153 static void bo_add_descr(bo_t *, uint8_t , uint32_t);
154
155 static void bo_fix_32be (bo_t *, int , uint32_t);
156
157 static bo_t *box_new     (const char *fcc);
158 static bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f);
159 static void  box_fix     (bo_t *box);
160 static void  box_gather  (bo_t *box, bo_t *box2);
161
162 static void box_send(sout_mux_t *p_mux,  bo_t *box);
163
164 static bo_t *GetMoovBox(sout_mux_t *p_mux);
165
166 static block_t *ConvertSUBT(block_t *);
167 static block_t *ConvertFromAnnexB(block_t *);
168
169 static const char avc1_start_code[4] = { 0, 0, 0, 1 };
170
171 /*****************************************************************************
172  * Open:
173  *****************************************************************************/
174 static int Open(vlc_object_t *p_this)
175 {
176     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
177     sout_mux_sys_t  *p_sys;
178     bo_t            *box;
179
180     msg_Dbg(p_mux, "Mp4 muxer opened");
181     config_ChainParse(p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg);
182
183     p_mux->pf_control   = Control;
184     p_mux->pf_addstream = AddStream;
185     p_mux->pf_delstream = DelStream;
186     p_mux->pf_mux       = Mux;
187     p_mux->p_sys        = p_sys = malloc(sizeof(sout_mux_sys_t));
188     if (!p_sys)
189         return VLC_ENOMEM;
190     p_sys->i_pos        = 0;
191     p_sys->i_nb_streams = 0;
192     p_sys->pp_streams   = NULL;
193     p_sys->i_mdat_pos   = 0;
194     p_sys->b_mov        = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "mov");
195     p_sys->b_3gp        = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "3gp");
196     p_sys->i_dts_start  = 0;
197
198
199     if (!p_sys->b_mov) {
200         /* Now add ftyp header */
201         box = box_new("ftyp");
202         if (p_sys->b_3gp)
203             bo_add_fourcc(box, "3gp6");
204         else
205             bo_add_fourcc(box, "isom");
206         bo_add_32be  (box, 0);
207         if (p_sys->b_3gp)
208             bo_add_fourcc(box, "3gp4");
209         else
210             bo_add_fourcc(box, "mp41");
211         bo_add_fourcc(box, "avc1");
212         bo_add_fourcc(box, "qt  ");
213         box_fix(box);
214
215         p_sys->i_pos += box->len;
216         p_sys->i_mdat_pos = p_sys->i_pos;
217
218         box_send(p_mux, box);
219     }
220
221     /* FIXME FIXME
222      * Quicktime actually doesn't like the 64 bits extensions !!! */
223     p_sys->b_64_ext = false;
224
225     /* Now add mdat header */
226     box = box_new("mdat");
227     bo_add_64be  (box, 0); // enough to store an extended size
228
229     p_sys->i_pos += box->len;
230
231     box_send(p_mux, box);
232
233     return VLC_SUCCESS;
234 }
235
236 /*****************************************************************************
237  * Close:
238  *****************************************************************************/
239 static void Close(vlc_object_t *p_this)
240 {
241     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
242     sout_mux_sys_t  *p_sys = p_mux->p_sys;
243
244     msg_Dbg(p_mux, "Close");
245
246     /* Update mdat size */
247     bo_t bo;
248     bo_init(&bo);
249     if (p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32)) {
250         /* Extended size */
251         bo_add_32be  (&bo, 1);
252         bo_add_fourcc(&bo, "mdat");
253         bo_add_64be  (&bo, p_sys->i_pos - p_sys->i_mdat_pos);
254     } else {
255         bo_add_32be  (&bo, 8);
256         bo_add_fourcc(&bo, "wide");
257         bo_add_32be  (&bo, p_sys->i_pos - p_sys->i_mdat_pos - 8);
258         bo_add_fourcc(&bo, "mdat");
259     }
260
261     bo.b->i_buffer = bo.len;
262     sout_AccessOutSeek(p_mux->p_access, p_sys->i_mdat_pos);
263     sout_AccessOutWrite(p_mux->p_access, bo.b);
264
265     /* Create MOOV header */
266     uint64_t i_moov_pos = p_sys->i_pos;
267     bo_t *moov = GetMoovBox(p_mux);
268
269     /* Check we need to create "fast start" files */
270     p_sys->b_fast_start = var_GetBool(p_this, SOUT_CFG_PREFIX "faststart");
271     while (p_sys->b_fast_start) {
272         /* Move data to the end of the file so we can fit the moov header
273          * at the start */
274         int64_t i_size = p_sys->i_pos - p_sys->i_mdat_pos;
275         int i_moov_size = moov->len;
276
277         while (i_size > 0) {
278             int64_t i_chunk = __MIN(32768, i_size);
279             block_t *p_buf = block_Alloc(i_chunk);
280             sout_AccessOutSeek(p_mux->p_access,
281                                 p_sys->i_mdat_pos + i_size - i_chunk);
282             if (sout_AccessOutRead(p_mux->p_access, p_buf) < i_chunk) {
283                 msg_Warn(p_this, "read() not supported by access output, "
284                           "won't create a fast start file");
285                 p_sys->b_fast_start = false;
286                 block_Release(p_buf);
287                 break;
288             }
289             sout_AccessOutSeek(p_mux->p_access, p_sys->i_mdat_pos + i_size +
290                                 i_moov_size - i_chunk);
291             sout_AccessOutWrite(p_mux->p_access, p_buf);
292             i_size -= i_chunk;
293         }
294
295         if (!p_sys->b_fast_start)
296             break;
297
298         /* Fix-up samples to chunks table in MOOV header */
299         for (int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
300             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
301
302             moov->len = p_stream->i_stco_pos;
303             for (unsigned i = 0; i < p_stream->i_entry_count; ) {
304                 mp4_entry_t *entry = p_stream->entry;
305                 if (p_stream->b_stco64)
306                     bo_add_64be(moov, entry[i].i_pos + i_moov_size);
307                 else
308                     bo_add_32be(moov, entry[i].i_pos + i_moov_size);
309
310                 for (; i < p_stream->i_entry_count; i++)
311                     if (i >= p_stream->i_entry_count - 1 ||
312                         entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
313                         i++;
314                         break;
315                     }
316             }
317         }
318
319         moov->len = i_moov_size;
320         i_moov_pos = p_sys->i_mdat_pos;
321         p_sys->b_fast_start = false;
322     }
323
324     /* Write MOOV header */
325     sout_AccessOutSeek(p_mux->p_access, i_moov_pos);
326     box_send(p_mux, moov);
327
328     /* Clean-up */
329     for (int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
330         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
331
332         es_format_Clean(&p_stream->fmt);
333         free(p_stream->entry);
334         free(p_stream);
335     }
336     if (p_sys->i_nb_streams)
337         free(p_sys->pp_streams);
338     free(p_sys);
339 }
340
341 /*****************************************************************************
342  * Control:
343  *****************************************************************************/
344 static int Control(sout_mux_t *p_mux, int i_query, va_list args)
345 {
346     VLC_UNUSED(p_mux);
347     bool *pb_bool;
348
349     switch(i_query)
350     {
351     case MUX_CAN_ADD_STREAM_WHILE_MUXING:
352         pb_bool = (bool*)va_arg(args, bool *);
353         *pb_bool = false;
354         return VLC_SUCCESS;
355
356     case MUX_GET_ADD_STREAM_WAIT:
357         pb_bool = (bool*)va_arg(args, bool *);
358         *pb_bool = true;
359         return VLC_SUCCESS;
360
361     case MUX_GET_MIME:   /* Not needed, as not streamable */
362     default:
363         return VLC_EGENERIC;
364     }
365 }
366
367 /*****************************************************************************
368  * AddStream:
369  *****************************************************************************/
370 static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input)
371 {
372     sout_mux_sys_t  *p_sys = p_mux->p_sys;
373     mp4_stream_t    *p_stream;
374
375     switch(p_input->p_fmt->i_codec)
376     {
377     case VLC_CODEC_MP4A:
378     case VLC_CODEC_MP4V:
379     case VLC_CODEC_MPGA:
380     case VLC_CODEC_MPGV:
381     case VLC_CODEC_MP2V:
382     case VLC_CODEC_MP1V:
383     case VLC_CODEC_MJPG:
384     case VLC_CODEC_MJPGB:
385     case VLC_CODEC_SVQ1:
386     case VLC_CODEC_SVQ3:
387     case VLC_CODEC_H263:
388     case VLC_CODEC_H264:
389     case VLC_CODEC_HEVC:
390     case VLC_CODEC_AMR_NB:
391     case VLC_CODEC_AMR_WB:
392     case VLC_CODEC_YV12:
393     case VLC_CODEC_YUYV:
394         break;
395     case VLC_CODEC_SUBT:
396         msg_Warn(p_mux, "subtitle track added like in .mov (even when creating .mp4)");
397         break;
398     default:
399         msg_Err(p_mux, "unsupported codec %4.4s in mp4",
400                  (char*)&p_input->p_fmt->i_codec);
401         return VLC_EGENERIC;
402     }
403
404     p_stream = malloc(sizeof(mp4_stream_t));
405     if (!p_stream)
406         return VLC_ENOMEM;
407     es_format_Copy(&p_stream->fmt, p_input->p_fmt);
408     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
409     p_stream->i_length_neg  = 0;
410     p_stream->i_entry_count = 0;
411     p_stream->i_entry_max   = 1000;
412     p_stream->entry         =
413         calloc(p_stream->i_entry_max, sizeof(mp4_entry_t));
414     p_stream->i_dts_start   = 0;
415     p_stream->i_duration    = 0;
416
417     p_input->p_sys          = p_stream;
418
419     msg_Dbg(p_mux, "adding input");
420
421     TAB_APPEND(p_sys->i_nb_streams, p_sys->pp_streams, p_stream);
422     return VLC_SUCCESS;
423 }
424
425 /*****************************************************************************
426  * DelStream:
427  *****************************************************************************/
428 static int DelStream(sout_mux_t *p_mux, sout_input_t *p_input)
429 {
430     VLC_UNUSED(p_input);
431     msg_Dbg(p_mux, "removing input");
432     return VLC_SUCCESS;
433 }
434
435 /*****************************************************************************
436  * Mux:
437  *****************************************************************************/
438 static int Mux(sout_mux_t *p_mux)
439 {
440     sout_mux_sys_t *p_sys = p_mux->p_sys;
441
442     for (;;) {
443         int i_stream = sout_MuxGetStream(p_mux, 2, NULL);
444         if (i_stream < 0)
445             return(VLC_SUCCESS);
446
447         sout_input_t *p_input  = p_mux->pp_inputs[i_stream];
448         mp4_stream_t *p_stream = (mp4_stream_t*)p_input->p_sys;
449
450         block_t *p_data;
451         do {
452             p_data = block_FifoGet(p_input->p_fifo);
453             if (p_stream->fmt.i_codec == VLC_CODEC_H264 ||
454                 p_stream->fmt.i_codec == VLC_CODEC_HEVC)
455                 p_data = ConvertFromAnnexB(p_data);
456             else if (p_stream->fmt.i_codec == VLC_CODEC_SUBT)
457                 p_data = ConvertSUBT(p_data);
458         } while (!p_data);
459
460         if (p_stream->fmt.i_cat != SPU_ES) {
461             /* Fix length of the sample */
462             if (block_FifoCount(p_input->p_fifo) > 0) {
463                 block_t *p_next = block_FifoShow(p_input->p_fifo);
464                 int64_t i_diff  = p_next->i_dts - p_data->i_dts;
465
466                 if (i_diff < CLOCK_FREQ) /* protection */
467                     p_data->i_length = i_diff;
468             }
469             if (p_data->i_length <= 0) {
470                 msg_Warn(p_mux, "i_length <= 0");
471                 p_stream->i_length_neg += p_data->i_length - 1;
472                 p_data->i_length = 1;
473             } else if (p_stream->i_length_neg < 0) {
474                 int64_t i_recover = __MIN(p_data->i_length / 4, - p_stream->i_length_neg);
475
476                 p_data->i_length -= i_recover;
477                 p_stream->i_length_neg += i_recover;
478             }
479         }
480
481         /* Save starting time */
482         if (p_stream->i_entry_count == 0) {
483             p_stream->i_dts_start = p_data->i_dts;
484
485             /* Update global dts_start */
486             if (p_sys->i_dts_start <= 0 || p_stream->i_dts_start < p_sys->i_dts_start)
487                 p_sys->i_dts_start = p_stream->i_dts_start;
488         }
489
490         if (p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0) {
491             int64_t i_length = p_data->i_dts - p_stream->i_last_dts;
492
493             if (i_length <= 0) /* FIXME handle this broken case */
494                 i_length = 1;
495
496             /* Fix last entry */
497             if (p_stream->entry[p_stream->i_entry_count-1].i_length <= 0)
498                 p_stream->entry[p_stream->i_entry_count-1].i_length = i_length;
499         }
500
501         /* add index entry */
502         mp4_entry_t *e = &p_stream->entry[p_stream->i_entry_count];
503         e->i_pos    = p_sys->i_pos;
504         e->i_size   = p_data->i_buffer;
505         e->i_pts_dts = p_data->i_pts - p_data->i_dts;
506         if (e->i_pts_dts < 0)
507             e->i_pts_dts = 0;
508         e->i_length = p_data->i_length;
509         e->i_flags  = p_data->i_flags;
510
511         p_stream->i_entry_count++;
512         /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
513         if (p_stream->i_entry_count >= p_stream->i_entry_max - 1) {
514             p_stream->i_entry_max += 1000;
515             p_stream->entry = xrealloc(p_stream->entry,
516                          p_stream->i_entry_max * sizeof(mp4_entry_t));
517         }
518
519         /* update */
520         p_stream->i_duration = p_stream->i_last_dts - p_stream->i_dts_start + p_data->i_length;
521         p_sys->i_pos += p_data->i_buffer;
522
523         /* Save the DTS */
524         p_stream->i_last_dts = p_data->i_dts;
525
526         /* write data */
527         sout_AccessOutWrite(p_mux->p_access, p_data);
528
529         if (p_stream->fmt.i_cat == SPU_ES) {
530             int64_t i_length = p_stream->entry[p_stream->i_entry_count-1].i_length;
531
532             if (i_length != 0) {
533                 /* TODO */
534                 msg_Dbg(p_mux, "writing an empty sub") ;
535
536                 /* Append a idx entry */
537                 mp4_entry_t *e = &p_stream->entry[p_stream->i_entry_count];
538                 e->i_pos    = p_sys->i_pos;
539                 e->i_size   = 3;
540                 e->i_pts_dts= 0;
541                 e->i_length = 0;
542                 e->i_flags  = 0;
543
544                 /* XXX: No need to grow the entry here */
545                 p_stream->i_entry_count++;
546
547                 /* Fix last dts */
548                 p_stream->i_last_dts += i_length;
549
550                 /* Write a " " */
551                 p_data = block_Alloc(3);
552                 p_data->p_buffer[0] = 0;
553                 p_data->p_buffer[1] = 1;
554                 p_data->p_buffer[2] = ' ';
555
556                 p_sys->i_pos += p_data->i_buffer;
557
558                 sout_AccessOutWrite(p_mux->p_access, p_data);
559             }
560
561             /* Fix duration */
562             p_stream->i_duration = p_stream->i_last_dts - p_stream->i_dts_start;
563         }
564     }
565
566     return(VLC_SUCCESS);
567 }
568
569 /*****************************************************************************
570  *
571  *****************************************************************************/
572 static block_t *ConvertSUBT(block_t *p_block)
573 {
574     p_block = block_Realloc(p_block, 2, p_block->i_buffer);
575
576     /* No trailling '\0' */
577     if (p_block->i_buffer > 2 && p_block->p_buffer[p_block->i_buffer-1] == '\0')
578         p_block->i_buffer--;
579
580     p_block->p_buffer[0] = ((p_block->i_buffer - 2) >> 8)&0xff;
581     p_block->p_buffer[1] = ((p_block->i_buffer - 2)     )&0xff;
582
583     return p_block;
584 }
585
586 static block_t *ConvertFromAnnexB(block_t *p_block)
587 {
588     uint8_t *last = p_block->p_buffer;  /* Assume it starts with 0x00000001 */
589     uint8_t *dat  = &p_block->p_buffer[4];
590     uint8_t *end = &p_block->p_buffer[p_block->i_buffer];
591
592
593     /* Replace the 4 bytes start code with 4 bytes size,
594      * FIXME are all startcodes 4 bytes ? (I don't think :(*/
595     while (dat < end) {
596         while (dat < end - 4) {
597             if (!memcmp(dat, avc1_start_code, 4))
598                 break;
599             dat++;
600         }
601         if (dat >= end - 4)
602             dat = end;
603
604         /* Fix size */
605         int i_size = dat - &last[4];
606         last[0] = (i_size >> 24)&0xff;
607         last[1] = (i_size >> 16)&0xff;
608         last[2] = (i_size >>  8)&0xff;
609         last[3] = (i_size      )&0xff;
610
611         /* Skip blocks with SPS/PPS */
612         //if ((last[4]&0x1f) == 7 || (last[4]&0x1f) == 8)
613         //    ; // FIXME Find a way to skip dat without frelling everything
614         last = dat;
615         dat += 4;
616     }
617     return p_block;
618 }
619
620 static bo_t *GetESDS(mp4_stream_t *p_stream)
621 {
622     bo_t *esds;
623     int64_t i_bitrate_avg = 0;
624     int64_t i_bitrate_max = 0;
625
626     /* Compute avg/max bitrate */
627     for (unsigned i = 0; i < p_stream->i_entry_count; i++) {
628         i_bitrate_avg += p_stream->entry[i].i_size;
629         if (p_stream->entry[i].i_length > 0) {
630             int64_t i_bitrate = INT64_C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
631             if (i_bitrate > i_bitrate_max)
632                 i_bitrate_max = i_bitrate;
633         }
634     }
635
636     if (p_stream->i_duration > 0)
637         i_bitrate_avg = INT64_C(8000000) * i_bitrate_avg / p_stream->i_duration;
638     else
639         i_bitrate_avg = 0;
640     if (i_bitrate_max <= 1)
641         i_bitrate_max = 0x7fffffff;
642
643     /* */
644     int i_decoder_specific_info_size = (p_stream->fmt.i_extra > 0) ? 5 + p_stream->fmt.i_extra : 0;
645
646     esds = box_full_new("esds", 0, 0);
647
648     /* ES_Descr */
649     bo_add_descr(esds, 0x03, 3 + 5 + 13 + i_decoder_specific_info_size + 5 + 1);
650     bo_add_16be(esds, p_stream->i_track_id);
651     bo_add_8   (esds, 0x1f);      // flags=0|streamPriority=0x1f
652
653     /* DecoderConfigDescr */
654     bo_add_descr(esds, 0x04, 13 + i_decoder_specific_info_size);
655
656     int  i_object_type_indication;
657     switch(p_stream->fmt.i_codec)
658     {
659     case VLC_CODEC_MP4V:
660         i_object_type_indication = 0x20;
661         break;
662     case VLC_CODEC_MP2V:
663         /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
664         i_object_type_indication = 0x65;
665         break;
666     case VLC_CODEC_MP1V:
667         /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
668         i_object_type_indication = 0x6b;
669         break;
670     case VLC_CODEC_MP4A:
671         /* FIXME for mpeg2-aac == 0x66->0x68 */
672         i_object_type_indication = 0x40;
673         break;
674     case VLC_CODEC_MPGA:
675         i_object_type_indication =
676             p_stream->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b;
677         break;
678     default:
679         i_object_type_indication = 0x00;
680         break;
681     }
682     int i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05;
683
684     bo_add_8   (esds, i_object_type_indication);
685     bo_add_8   (esds, (i_stream_type << 2) | 1);
686     bo_add_24be(esds, 1024 * 1024);       // bufferSizeDB
687     bo_add_32be(esds, i_bitrate_max);     // maxBitrate
688     bo_add_32be(esds, i_bitrate_avg);     // avgBitrate
689
690     if (p_stream->fmt.i_extra > 0) {
691         /* DecoderSpecificInfo */
692         bo_add_descr(esds, 0x05, p_stream->fmt.i_extra);
693
694         for (int i = 0; i < p_stream->fmt.i_extra; i++)
695             bo_add_8(esds, ((uint8_t*)p_stream->fmt.p_extra)[i]);
696     }
697
698     /* SL_Descr mandatory */
699     bo_add_descr(esds, 0x06, 1);
700     bo_add_8    (esds, 0x02);  // sl_predefined
701
702     return esds;
703 }
704
705 static bo_t *GetWaveTag(mp4_stream_t *p_stream)
706 {
707     bo_t *wave;
708     bo_t *box;
709
710     wave = box_new("wave");
711
712     box = box_new("frma");
713     bo_add_fourcc(box, "mp4a");
714     box_gather(wave, box);
715
716     box = box_new("mp4a");
717     bo_add_32be(box, 0);
718     box_gather(wave, box);
719
720     box = GetESDS(p_stream);
721     box_gather(wave, box);
722
723     box = box_new("srcq");
724     bo_add_32be(box, 0x40);
725     box_gather(wave, box);
726
727     /* wazza ? */
728     bo_add_32be(wave, 8); /* new empty box */
729     bo_add_32be(wave, 0); /* box label */
730
731     return wave;
732 }
733
734 static bo_t *GetDamrTag(mp4_stream_t *p_stream)
735 {
736     bo_t *damr;
737
738     damr = box_new("damr");
739
740     bo_add_fourcc(damr, "REFC");
741     bo_add_8(damr, 0);
742
743     if (p_stream->fmt.i_codec == VLC_CODEC_AMR_NB)
744         bo_add_16be(damr, 0x81ff); /* Mode set (all modes for AMR_NB) */
745     else
746         bo_add_16be(damr, 0x83ff); /* Mode set (all modes for AMR_WB) */
747     bo_add_16be(damr, 0x1); /* Mode change period (no restriction) */
748
749     return damr;
750 }
751
752 static bo_t *GetD263Tag(void)
753 {
754     bo_t *d263;
755
756     d263 = box_new("d263");
757
758     bo_add_fourcc(d263, "VLC ");
759     bo_add_16be(d263, 0xa);
760     bo_add_8(d263, 0);
761
762     return d263;
763 }
764
765 static void hevcParseVPS(uint8_t * p_buffer, size_t i_buffer, uint8_t *general,
766                          uint8_t * numTemporalLayer, bool * temporalIdNested)
767 {
768     const size_t i_decoded_nal_size = 512;
769     uint8_t p_dec_nal[i_decoded_nal_size];
770     size_t i_size = (i_buffer < i_decoded_nal_size)?i_buffer:i_decoded_nal_size;
771     nal_decode(p_buffer, p_dec_nal, i_size);
772
773     /* first two bytes are the NAL header, 3rd and 4th are:
774         vps_video_parameter_set_id(4)
775         vps_reserved_3_2bis(2)
776         vps_max_layers_minus1(6)
777         vps_max_sub_layers_minus1(3)
778         vps_temporal_id_nesting_flags
779     */
780     *numTemporalLayer =  ((p_dec_nal[3] & 0x0E) >> 1) + 1;
781     *temporalIdNested = (bool)(p_dec_nal[3] & 0x01);
782
783     /* 5th & 6th are reserved 0xffff */
784     /* copy the first 12 bytes of profile tier */
785     memcpy(general, &p_dec_nal[6], 12);
786 }
787
788 static void hevcParseSPS(uint8_t * p_buffer, size_t i_buffer, uint8_t * chroma_idc,
789                          uint8_t *bit_depth_luma_minus8, uint8_t *bit_depth_chroma_minus8)
790 {
791     const size_t i_decoded_nal_size = 512;
792     uint8_t p_dec_nal[i_decoded_nal_size];
793     size_t i_size = (i_buffer < i_decoded_nal_size)?i_buffer-2:i_decoded_nal_size;
794     nal_decode(p_buffer+2, p_dec_nal, i_size);
795     bs_t bs;
796     bs_init(&bs, p_dec_nal, i_size);
797
798     /* skip vps id */
799     bs_skip(&bs, 4);
800     uint32_t sps_max_sublayer_minus1 = bs_read(&bs, 3);
801
802     /* skip nesting flag */
803     bs_skip(&bs, 1);
804
805     hevc_skip_profile_tiers_level(&bs, sps_max_sublayer_minus1);
806
807     /* skip sps id */
808     (void) read_ue( &bs );
809
810     *chroma_idc = read_ue(&bs);
811     if (*chroma_idc == 3)
812         bs_skip(&bs, 1);
813
814     /* skip width and heigh */
815     (void) read_ue( &bs );
816     (void) read_ue( &bs );
817
818     uint32_t conformance_window_flag = bs_read1(&bs);
819     if (conformance_window_flag) {
820         /* skip offsets*/
821         (void) read_ue(&bs);
822         (void) read_ue(&bs);
823         (void) read_ue(&bs);
824         (void) read_ue(&bs);
825     }
826     *bit_depth_luma_minus8 = read_ue(&bs);
827     *bit_depth_chroma_minus8 = read_ue(&bs);
828 }
829
830 static bo_t *GetHvcCTag(mp4_stream_t *p_stream)
831 {
832     /* Generate hvcC box matching iso/iec 14496-15 3rd edition */
833     bo_t *hvcC = box_new("hvcC");
834     if(!p_stream->fmt.i_extra)
835         return hvcC;
836
837     struct nal {
838         size_t i_buffer;
839         uint8_t * p_buffer;
840     };
841
842     /* According to the specification HEVC stream can have
843      * 16 vps id and an "unlimited" number of sps and pps id using ue(v) id*/
844     struct nal p_vps[16], *p_sps = NULL, *p_pps = NULL, *p_sei = NULL,
845                *p_nal = NULL;
846     size_t i_vps = 0, i_sps = 0, i_pps = 0, i_sei = 0;
847     uint8_t i_num_arrays = 0;
848
849     uint8_t * p_buffer = p_stream->fmt.p_extra;
850     size_t i_buffer = p_stream->fmt.i_extra;
851
852     uint8_t general_configuration[12] = {0};
853     uint8_t i_numTemporalLayer = 0;
854     uint8_t i_chroma_idc = 1;
855     uint8_t i_bit_depth_luma_minus8 = 0;
856     uint8_t i_bit_depth_chroma_minus8 = 0;
857     bool b_temporalIdNested = false;
858
859     uint32_t cmp = 0xFFFFFFFF;
860     while (i_buffer) {
861         /* look for start code 0X0000001 */
862         while (i_buffer) {
863             cmp = (cmp << 8) | *p_buffer;
864             if((cmp ^ UINT32_C(0x100)) <= UINT32_C(0xFF))
865                 break;
866             p_buffer++;
867             i_buffer--;
868         }
869         if (p_nal)
870             p_nal->i_buffer = p_buffer - p_nal->p_buffer - ((i_buffer)?3:0);
871
872         switch (*p_buffer & 0x72) {
873             /* VPS */
874         case 0x40:
875             p_nal = &p_vps[i_vps++];
876             p_nal->p_buffer = p_buffer;
877             /* Only keep the general profile from the first VPS
878              * if there are several (this shouldn't happen so soon) */
879             if (i_vps == 1) {
880                 hevcParseVPS(p_buffer, i_buffer, general_configuration,
881                              &i_numTemporalLayer, &b_temporalIdNested);
882                 i_num_arrays++;
883             }
884             break;
885             /* SPS */
886         case 0x42: {
887             struct nal * p_tmp =  realloc(p_sps, sizeof(struct nal) * (i_sps + 1));
888             if (!p_tmp)
889                 break;
890             p_sps = p_tmp;
891             p_nal = &p_sps[i_sps++];
892             p_nal->p_buffer = p_buffer;
893             if (i_sps == 1 && i_buffer > 15) {
894                 /* Get Chroma_idc and bitdepths */
895                 hevcParseSPS(p_buffer, i_buffer, &i_chroma_idc,
896                              &i_bit_depth_luma_minus8, &i_bit_depth_chroma_minus8);
897                 i_num_arrays++;
898             }
899             break;
900             }
901         /* PPS */
902         case 0x44: {
903             struct nal * p_tmp =  realloc(p_pps, sizeof(struct nal) * (i_pps + 1));
904             if (!p_tmp)
905                 break;
906             p_pps = p_tmp;
907             p_nal = &p_pps[i_pps++];
908             p_nal->p_buffer = p_buffer;
909             if (i_pps == 1)
910                 i_num_arrays++;
911             break;
912             }
913         /* SEI */
914         case 0x4E:
915         case 0x50: {
916             struct nal * p_tmp =  realloc(p_sei, sizeof(struct nal) * (i_sei + 1));
917             if (!p_tmp)
918                 break;
919             p_sei = p_tmp;
920             p_nal = &p_sei[i_sei++];
921             p_nal->p_buffer = p_buffer;
922             if(i_sei == 1)
923                 i_num_arrays++;
924             break;
925         }
926         default:
927             p_nal = NULL;
928             break;
929         }
930     }
931     bo_add_8(hvcC, 0x01);
932     bo_add_mem(hvcC, 12, general_configuration);
933     /* Don't set min spatial segmentation */
934     bo_add_16be(hvcC, 0xF000);
935     /* Don't set parallelism type since segmentation isn't set */
936     bo_add_8(hvcC, 0xFC);
937     bo_add_8(hvcC, (0xFC | (i_chroma_idc & 0x03)));
938     bo_add_8(hvcC, (0xF8 | (i_bit_depth_luma_minus8 & 0x07)));
939     bo_add_8(hvcC, (0xF8 | (i_bit_depth_chroma_minus8 & 0x07)));
940
941     /* Don't set framerate */
942     bo_add_16be(hvcC, 0x0000);
943     /* Force NAL size of 4 bytes that replace the startcode */
944     bo_add_8(hvcC, (((i_numTemporalLayer & 0x07) << 3) |
945                     (b_temporalIdNested << 2) | 0x03));
946     bo_add_8(hvcC, i_num_arrays);
947
948     if (i_vps)
949     {
950         /* Write VPS without forcing array_completeness */
951         bo_add_8(hvcC, 32);
952         bo_add_16be(hvcC, i_vps);
953         for (size_t i = 0; i < i_vps; i++) {
954             p_nal = &p_vps[i];
955             bo_add_16be(hvcC, p_nal->i_buffer);
956             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
957         }
958     }
959
960     if (i_sps) {
961         /* Write SPS without forcing array_completeness */
962         bo_add_8(hvcC, 33);
963         bo_add_16be(hvcC, i_sps);
964         for (size_t i = 0; i < i_sps; i++) {
965             p_nal = &p_sps[i];
966             bo_add_16be(hvcC, p_nal->i_buffer);
967             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
968         }
969     }
970
971     if (i_pps) {
972         /* Write PPS without forcing array_completeness */
973         bo_add_8(hvcC, 34);
974         bo_add_16be(hvcC, i_pps);
975         for (size_t i = 0; i < i_pps; i++) {
976             p_nal = &p_pps[i];
977             bo_add_16be(hvcC, p_nal->i_buffer);
978             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
979         }
980     }
981
982     if (i_sei) {
983         /* Write SEI without forcing array_completeness */
984         bo_add_8(hvcC, 39);
985         bo_add_16be(hvcC, i_sei);
986         for (size_t i = 0; i < i_sei; i++) {
987             p_nal = &p_sei[i];
988             bo_add_16be(hvcC, p_nal->i_buffer);
989             bo_add_mem(hvcC, p_nal->i_buffer, p_nal->p_buffer);
990         }
991     }
992     return hvcC;
993 }
994
995 static bo_t *GetAvcCTag(mp4_stream_t *p_stream)
996 {
997     bo_t    *avcC = NULL;
998     uint8_t *p_sps = NULL;
999     uint8_t *p_pps = NULL;
1000     int     i_sps_size = 0;
1001     int     i_pps_size = 0;
1002
1003     if (p_stream->fmt.i_extra > 0) {
1004         /* FIXME: take into account multiple sps/pps */
1005         uint8_t *p_buffer = p_stream->fmt.p_extra;
1006         int     i_buffer = p_stream->fmt.i_extra;
1007
1008         while (i_buffer > 3) {
1009             while (memcmp(p_buffer, &avc1_start_code[1], 3)) {
1010                  i_buffer--;
1011                  p_buffer++;
1012             }
1013             const int i_nal_type = p_buffer[3]&0x1f;
1014             int i_startcode = 0;
1015  
1016             for (int i_offset = 1; i_offset+2 < i_buffer ; i_offset++)
1017                 if (!memcmp(&p_buffer[i_offset], &avc1_start_code[1], 3)) {
1018                     /* we found another startcode */
1019                     i_startcode = i_offset;
1020                     while (p_buffer[i_startcode-1] == 0 && i_startcode > 0)
1021                         i_startcode--;
1022                     break;
1023                 }
1024
1025             int i_size = i_startcode ? i_startcode : i_buffer;
1026
1027             if (i_nal_type == 7) {
1028                 p_sps = &p_buffer[3];
1029                 i_sps_size = i_size - 3;
1030             }
1031             if (i_nal_type == 8) {
1032                 p_pps = &p_buffer[3];
1033                 i_pps_size = i_size - 3;
1034             }
1035             i_buffer -= i_size;
1036             p_buffer += i_size;
1037         }
1038     }
1039  
1040     /* FIXME use better value */
1041     avcC = box_new("avcC");
1042     bo_add_8(avcC, 1);      /* configuration version */
1043     bo_add_8(avcC, i_sps_size ? p_sps[1] : 77);
1044     bo_add_8(avcC, i_sps_size ? p_sps[2] : 64);
1045     bo_add_8(avcC, i_sps_size ? p_sps[3] : 30);       /* level, 5.1 */
1046     bo_add_8(avcC, 0xff);   /* 0b11111100 | lengthsize = 0x11 */
1047
1048     bo_add_8(avcC, 0xe0 | (i_sps_size > 0 ? 1 : 0));   /* 0b11100000 | sps_count */
1049     if (i_sps_size > 0) {
1050         bo_add_16be(avcC, i_sps_size);
1051         bo_add_mem(avcC, i_sps_size, p_sps);
1052     }
1053
1054     bo_add_8(avcC, (i_pps_size > 0 ? 1 : 0));   /* pps_count */
1055     if (i_pps_size > 0) {
1056         bo_add_16be(avcC, i_pps_size);
1057         bo_add_mem(avcC, i_pps_size, p_pps);
1058     }
1059
1060     return avcC;
1061 }
1062
1063 /* TODO: No idea about these values */
1064 static bo_t *GetSVQ3Tag(mp4_stream_t *p_stream)
1065 {
1066     bo_t *smi = box_new("SMI ");
1067
1068     if (p_stream->fmt.i_extra > 0x4e) {
1069         uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra];
1070         uint8_t *p     = &((uint8_t*)p_stream->fmt.p_extra)[0x46];
1071
1072         while (p + 8 < p_end) {
1073             int i_size = GetDWBE(p);
1074             if (i_size <= 1) /* FIXME handle 1 as long size */
1075                 break;
1076             if (!strncmp((const char *)&p[4], "SMI ", 4)) {
1077                 bo_add_mem(smi, p_end - p - 8, &p[8]);
1078                 return smi;
1079             }
1080             p += i_size;
1081         }
1082     }
1083
1084     /* Create a dummy one in fallback */
1085     bo_add_fourcc(smi, "SEQH");
1086     bo_add_32be(smi, 0x5);
1087     bo_add_32be(smi, 0xe2c0211d);
1088     bo_add_8(smi, 0xc0);
1089
1090     return smi;
1091 }
1092
1093 static bo_t *GetUdtaTag(sout_mux_t *p_mux)
1094 {
1095     sout_mux_sys_t *p_sys = p_mux->p_sys;
1096     bo_t *udta = box_new("udta");
1097
1098     /* Requirements */
1099     for (int i_track = 0; i_track < p_sys->i_nb_streams; i_track++) {
1100         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
1101         vlc_fourcc_t codec = p_stream->fmt.i_codec;
1102
1103         if (codec == VLC_CODEC_MP4V || codec == VLC_CODEC_MP4A) {
1104             bo_t *box = box_new("\251req");
1105             /* String length */
1106             bo_add_16be(box, sizeof("QuickTime 6.0 or greater") - 1);
1107             bo_add_16be(box, 0);
1108             bo_add_mem(box, sizeof("QuickTime 6.0 or greater") - 1,
1109                         (uint8_t *)"QuickTime 6.0 or greater");
1110             box_gather(udta, box);
1111             break;
1112         }
1113     }
1114
1115     /* Encoder */
1116     {
1117         bo_t *box = box_new("\251enc");
1118         /* String length */
1119         bo_add_16be(box, sizeof(PACKAGE_STRING " stream output") - 1);
1120         bo_add_16be(box, 0);
1121         bo_add_mem(box, sizeof(PACKAGE_STRING " stream output") - 1,
1122                     (uint8_t*)PACKAGE_STRING " stream output");
1123         box_gather(udta, box);
1124     }
1125 #if 0
1126     /* Misc atoms */
1127     vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
1128     if (p_meta) {
1129 #define ADD_META_BOX(type, box_string) { \
1130         bo_t *box = NULL;  \
1131         if (vlc_meta_Get(p_meta, vlc_meta_##type)) \
1132             box = box_new("\251" box_string); \
1133         if (box) { \
1134             bo_add_16be(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type))); \
1135             bo_add_16be(box, 0); \
1136             bo_add_mem(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type)), \
1137                         (uint8_t*)(vlc_meta_Get(p_meta, vlc_meta_##type))); \
1138             box_gather(udta, box); \
1139         } }
1140
1141         ADD_META_BOX(Title, "nam");
1142         ADD_META_BOX(Artist, "ART");
1143         ADD_META_BOX(Genre, "gen");
1144         ADD_META_BOX(Copyright, "cpy");
1145         ADD_META_BOX(Description, "des");
1146         ADD_META_BOX(Date, "day");
1147         ADD_META_BOX(URL, "url");
1148 #undef ADD_META_BOX
1149     }
1150 #endif
1151     return udta;
1152 }
1153
1154 static bo_t *GetSounBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
1155 {
1156     sout_mux_sys_t *p_sys = p_mux->p_sys;
1157     bool b_descr = true;
1158     vlc_fourcc_t codec = p_stream->fmt.i_codec;
1159     char fcc[4];
1160     vlc_fourcc_to_char(codec, fcc);
1161
1162     if (codec == VLC_CODEC_MPGA) {
1163         if (p_sys->b_mov) {
1164             b_descr = false;
1165             memcpy(fcc, ".mp3", 4);
1166         } else
1167             memcpy(fcc, "mp4a", 4);
1168     }
1169
1170     bo_t *soun = box_new(fcc);
1171     for (int i = 0; i < 6; i++)
1172         bo_add_8(soun, 0);        // reserved;
1173     bo_add_16be(soun, 1);         // data-reference-index
1174
1175     /* SoundDescription */
1176     if (p_sys->b_mov && codec == VLC_CODEC_MP4A)
1177         bo_add_16be(soun, 1);     // version 1;
1178     else
1179         bo_add_16be(soun, 0);     // version 0;
1180     bo_add_16be(soun, 0);         // revision level (0)
1181     bo_add_32be(soun, 0);         // vendor
1182     // channel-count
1183     bo_add_16be(soun, p_stream->fmt.audio.i_channels);
1184     // sample size
1185     bo_add_16be(soun, p_stream->fmt.audio.i_bitspersample ?
1186                  p_stream->fmt.audio.i_bitspersample : 16);
1187     bo_add_16be(soun, -2);        // compression id
1188     bo_add_16be(soun, 0);         // packet size (0)
1189     bo_add_16be(soun, p_stream->fmt.audio.i_rate); // sampleratehi
1190     bo_add_16be(soun, 0);                             // sampleratelo
1191
1192     /* Extended data for SoundDescription V1 */
1193     if (p_sys->b_mov && p_stream->fmt.i_codec == VLC_CODEC_MP4A) {
1194         /* samples per packet */
1195         bo_add_32be(soun, p_stream->fmt.audio.i_frame_length);
1196         bo_add_32be(soun, 1536); /* bytes per packet */
1197         bo_add_32be(soun, 2);    /* bytes per frame */
1198         /* bytes per sample */
1199         bo_add_32be(soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */);
1200     }
1201
1202     /* Add an ES Descriptor */
1203     if (b_descr) {
1204         bo_t *box;
1205
1206         if (p_sys->b_mov && codec == VLC_CODEC_MP4A)
1207             box = GetWaveTag(p_stream);
1208         else if (codec == VLC_CODEC_AMR_NB)
1209             box = GetDamrTag(p_stream);
1210         else
1211             box = GetESDS(p_stream);
1212         box_gather(soun, box);
1213     }
1214
1215     return soun;
1216 }
1217
1218 static bo_t *GetVideBox(mp4_stream_t *p_stream)
1219 {
1220     char fcc[4];
1221
1222     switch(p_stream->fmt.i_codec)
1223     {
1224     case VLC_CODEC_MP4V:
1225     case VLC_CODEC_MPGV: memcpy(fcc, "mp4v", 4); break;
1226     case VLC_CODEC_MJPG: memcpy(fcc, "mjpa", 4); break;
1227     case VLC_CODEC_SVQ1: memcpy(fcc, "SVQ1", 4); break;
1228     case VLC_CODEC_SVQ3: memcpy(fcc, "SVQ3", 4); break;
1229     case VLC_CODEC_H263: memcpy(fcc, "s263", 4); break;
1230     case VLC_CODEC_H264: memcpy(fcc, "avc1", 4); break;
1231     case VLC_CODEC_HEVC: memcpy(fcc, "hvc1", 4); break;
1232     case VLC_CODEC_YV12: memcpy(fcc, "yv12", 4); break;
1233     case VLC_CODEC_YUYV: memcpy(fcc, "yuy2", 4); break;
1234     default:
1235         vlc_fourcc_to_char(p_stream->fmt.i_codec, fcc);
1236         break;
1237     }
1238
1239     bo_t *vide = box_new(fcc);
1240     for (int i = 0; i < 6; i++)
1241         bo_add_8(vide, 0);        // reserved;
1242     bo_add_16be(vide, 1);         // data-reference-index
1243
1244     bo_add_16be(vide, 0);         // predefined;
1245     bo_add_16be(vide, 0);         // reserved;
1246     for (int i = 0; i < 3; i++)
1247         bo_add_32be(vide, 0);     // predefined;
1248
1249     bo_add_16be(vide, p_stream->fmt.video.i_width);  // i_width
1250     bo_add_16be(vide, p_stream->fmt.video.i_height); // i_height
1251
1252     bo_add_32be(vide, 0x00480000);                // h 72dpi
1253     bo_add_32be(vide, 0x00480000);                // v 72dpi
1254
1255     bo_add_32be(vide, 0);         // data size, always 0
1256     bo_add_16be(vide, 1);         // frames count per sample
1257
1258     // compressor name;
1259     for (int i = 0; i < 32; i++)
1260         bo_add_8(vide, 0);
1261
1262     bo_add_16be(vide, 0x18);      // depth
1263     bo_add_16be(vide, 0xffff);    // predefined
1264
1265     /* add an ES Descriptor */
1266     switch(p_stream->fmt.i_codec)
1267     {
1268     case VLC_CODEC_MP4V:
1269     case VLC_CODEC_MPGV:
1270         box_gather(vide, GetESDS(p_stream));
1271         break;
1272
1273     case VLC_CODEC_H263:
1274         box_gather(vide, GetD263Tag());
1275         break;
1276
1277     case VLC_CODEC_SVQ3:
1278         box_gather(vide, GetSVQ3Tag(p_stream));
1279         break;
1280
1281     case VLC_CODEC_H264:
1282         box_gather(vide, GetAvcCTag(p_stream));
1283         break;
1284
1285     case VLC_CODEC_HEVC:
1286         box_gather(vide, GetHvcCTag(p_stream));
1287         break;
1288     }
1289
1290     return vide;
1291 }
1292
1293 static bo_t *GetTextBox(void)
1294 {
1295     bo_t *text = box_new("text");
1296
1297     for (int i = 0; i < 6; i++)
1298         bo_add_8(text, 0);        // reserved;
1299     bo_add_16be(text, 1);         // data-reference-index
1300
1301     bo_add_32be(text, 0);         // display flags
1302     bo_add_32be(text, 0);         // justification
1303     for (int i = 0; i < 3; i++)
1304         bo_add_16be(text, 0);     // back ground color
1305
1306     bo_add_16be(text, 0);         // box text
1307     bo_add_16be(text, 0);         // box text
1308     bo_add_16be(text, 0);         // box text
1309     bo_add_16be(text, 0);         // box text
1310
1311     bo_add_64be(text, 0);         // reserved
1312     for (int i = 0; i < 3; i++)
1313         bo_add_16be(text, 0xff);  // foreground color
1314
1315     bo_add_8 (text, 9);
1316     bo_add_mem(text, 9, (uint8_t*)"Helvetica");
1317
1318     return text;
1319 }
1320
1321 static bo_t *GetStblBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
1322 {
1323     sout_mux_sys_t *p_sys = p_mux->p_sys;
1324
1325     /* sample description */
1326     bo_t *stsd = box_full_new("stsd", 0, 0);
1327     bo_add_32be(stsd, 1);
1328     if (p_stream->fmt.i_cat == AUDIO_ES)
1329         box_gather(stsd, GetSounBox(p_mux, p_stream));
1330     else if (p_stream->fmt.i_cat == VIDEO_ES)
1331         box_gather(stsd, GetVideBox(p_stream));
1332     else if (p_stream->fmt.i_cat == SPU_ES)
1333         box_gather(stsd, GetTextBox());
1334
1335     /* chunk offset table */
1336     bo_t *stco;
1337     if (p_sys->i_pos >= (((uint64_t)0x1) << 32)) {
1338         /* 64 bits version */
1339         p_stream->b_stco64 = true;
1340         stco = box_full_new("co64", 0, 0);
1341     } else {
1342         /* 32 bits version */
1343         p_stream->b_stco64 = false;
1344         stco = box_full_new("stco", 0, 0);
1345     }
1346     bo_add_32be(stco, 0);     // entry-count (fixed latter)
1347
1348     /* sample to chunk table */
1349     bo_t *stsc = box_full_new("stsc", 0, 0);
1350     bo_add_32be(stsc, 0);     // entry-count (fixed latter)
1351
1352     unsigned i_chunk = 0;
1353     unsigned i_stsc_last_val = 0, i_stsc_entries = 0;
1354     for (unsigned i = 0; i < p_stream->i_entry_count; i_chunk++) {
1355         mp4_entry_t *entry = p_stream->entry;
1356         int i_first = i;
1357
1358         if (p_stream->b_stco64)
1359             bo_add_64be(stco, entry[i].i_pos);
1360         else
1361             bo_add_32be(stco, entry[i].i_pos);
1362
1363         for (; i < p_stream->i_entry_count; i++)
1364             if (i >= p_stream->i_entry_count - 1 ||
1365                     entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
1366                 i++;
1367                 break;
1368             }
1369
1370         /* Add entry to the stsc table */
1371         if (i_stsc_last_val != i - i_first) {
1372             bo_add_32be(stsc, 1 + i_chunk);   // first-chunk
1373             bo_add_32be(stsc, i - i_first) ;  // samples-per-chunk
1374             bo_add_32be(stsc, 1);             // sample-descr-index
1375             i_stsc_last_val = i - i_first;
1376             i_stsc_entries++;
1377         }
1378     }
1379
1380     /* Fix stco entry count */
1381     bo_fix_32be(stco, 12, i_chunk);
1382     msg_Dbg(p_mux, "created %d chunks (stco)", i_chunk);
1383
1384     /* Fix stsc entry count */
1385     bo_fix_32be(stsc, 12, i_stsc_entries );
1386
1387     /* add stts */
1388     bo_t *stts = box_full_new("stts", 0, 0);
1389     bo_add_32be(stts, 0);     // entry-count (fixed latter)
1390
1391     uint32_t i_timescale;
1392     if (p_stream->fmt.i_cat == AUDIO_ES)
1393         i_timescale = p_stream->fmt.audio.i_rate;
1394     else
1395         i_timescale = CLOCK_FREQ;
1396
1397     unsigned i_index = 0;
1398     for (unsigned i = 0; i < p_stream->i_entry_count; i_index++) {
1399         int     i_first = i;
1400         mtime_t i_delta = p_stream->entry[i].i_length;
1401
1402         for (; i < p_stream->i_entry_count; ++i)
1403             if (i == p_stream->i_entry_count || p_stream->entry[i].i_length != i_delta)
1404                 break;
1405
1406         bo_add_32be(stts, i - i_first); // sample-count
1407         bo_add_32be(stts, i_delta * i_timescale / CLOCK_FREQ ); // sample-delta
1408     }
1409     bo_fix_32be(stts, 12, i_index);
1410
1411     /* FIXME add ctts ?? FIXME */
1412
1413     bo_t *stsz = box_full_new("stsz", 0, 0);
1414     int i_size = 0;
1415     for (unsigned i = 0; i < p_stream->i_entry_count; i++)
1416     {
1417         if ( i == 0 )
1418             i_size = p_stream->entry[i].i_size;
1419         else if ( p_stream->entry[i].i_size != i_size )
1420         {
1421             i_size = 0;
1422             break;
1423         }
1424     }
1425     bo_add_32be(stsz, i_size);                         // sample-size
1426     bo_add_32be(stsz, p_stream->i_entry_count);       // sample-count
1427     if ( i_size == 0 ) // all samples have different size
1428     {
1429         for (unsigned i = 0; i < p_stream->i_entry_count; i++)
1430             bo_add_32be(stsz, p_stream->entry[i].i_size); // sample-size
1431     }
1432
1433     /* create stss table */
1434     bo_t *stss = NULL;
1435     i_index = 0;
1436     for (unsigned i = 0; i < p_stream->i_entry_count; i++)
1437         if (p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I) {
1438             if (stss == NULL) {
1439                 stss = box_full_new("stss", 0, 0);
1440                 bo_add_32be(stss, 0); /* fixed later */
1441             }
1442             bo_add_32be(stss, 1 + i);
1443             i_index++;
1444         }
1445
1446     if (stss)
1447         bo_fix_32be(stss, 12, i_index);
1448
1449     /* Now gather all boxes into stbl */
1450     bo_t *stbl = box_new("stbl");
1451
1452     box_gather(stbl, stsd);
1453     box_gather(stbl, stts);
1454     if (stss)
1455         box_gather(stbl, stss);
1456     box_gather(stbl, stsc);
1457     box_gather(stbl, stsz);
1458     p_stream->i_stco_pos = stbl->len + 16;
1459     box_gather(stbl, stco);
1460
1461     return stbl;
1462 }
1463
1464 static int64_t get_timestamp(void);
1465
1466 static void matrix_apply_rotation(es_format_t *fmt, uint32_t mvhd_matrix[9])
1467 {
1468     enum video_orientation_t orientation = ORIENT_NORMAL;
1469     if (fmt->i_cat == VIDEO_ES)
1470         orientation = fmt->video.orientation;
1471
1472 #define ATAN(a, b) do { mvhd_matrix[1] = (a) << 16; \
1473     mvhd_matrix[0] = (b) << 16; \
1474     } while(0)
1475
1476     switch (orientation) {
1477     case ORIENT_ROTATED_90:  ATAN( 1,  0); break;
1478     case ORIENT_ROTATED_180: ATAN( 0, -1); break;
1479     case ORIENT_ROTATED_270: ATAN( -1, 0); break;
1480     default:                 ATAN( 0,  1); break;
1481     }
1482
1483     mvhd_matrix[3] = mvhd_matrix[0] ? 0 : 0x10000;
1484     mvhd_matrix[4] = mvhd_matrix[1] ? 0 : 0x10000;
1485 }
1486
1487 static bo_t *GetMoovBox(sout_mux_t *p_mux)
1488 {
1489     sout_mux_sys_t *p_sys = p_mux->p_sys;
1490
1491     bo_t            *moov, *mvhd;
1492
1493     uint32_t        i_movie_timescale = 90000;
1494     int64_t         i_movie_duration  = 0;
1495     int64_t         i_timestamp = get_timestamp();
1496
1497     moov = box_new("moov");
1498
1499     /* Create general info */
1500     for (int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
1501         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1502         i_movie_duration = __MAX(i_movie_duration, p_stream->i_duration);
1503     }
1504     msg_Dbg(p_mux, "movie duration %"PRId64"s", i_movie_duration / CLOCK_FREQ);
1505
1506     i_movie_duration = i_movie_duration * i_movie_timescale / CLOCK_FREQ;
1507
1508     /* *** add /moov/mvhd *** */
1509     if (!p_sys->b_64_ext) {
1510         mvhd = box_full_new("mvhd", 0, 0);
1511         bo_add_32be(mvhd, i_timestamp);   // creation time
1512         bo_add_32be(mvhd, i_timestamp);   // modification time
1513         bo_add_32be(mvhd, i_movie_timescale);  // timescale
1514         bo_add_32be(mvhd, i_movie_duration);  // duration
1515     } else {
1516         mvhd = box_full_new("mvhd", 1, 0);
1517         bo_add_64be(mvhd, i_timestamp);   // creation time
1518         bo_add_64be(mvhd, i_timestamp);   // modification time
1519         bo_add_32be(mvhd, i_movie_timescale);  // timescale
1520         bo_add_64be(mvhd, i_movie_duration);  // duration
1521     }
1522     bo_add_32be(mvhd, 0x10000);           // rate
1523     bo_add_16be(mvhd, 0x100);             // volume
1524     bo_add_16be(mvhd, 0);                 // reserved
1525     for (int i = 0; i < 2; i++)
1526         bo_add_32be(mvhd, 0);             // reserved
1527
1528     uint32_t mvhd_matrix[9] = { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
1529
1530     for (int i = 0; i < 9; i++)
1531         bo_add_32be(mvhd, mvhd_matrix[i]);// matrix
1532     for (int i = 0; i < 6; i++)
1533         bo_add_32be(mvhd, 0);             // pre-defined
1534
1535     /* Next available track id */
1536     bo_add_32be(mvhd, p_sys->i_nb_streams + 1); // next-track-id
1537
1538     box_gather(moov, mvhd);
1539
1540     for (int i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++) {
1541         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1542
1543         uint32_t i_timescale;
1544         if (p_stream->fmt.i_cat == AUDIO_ES)
1545             i_timescale = p_stream->fmt.audio.i_rate;
1546         else
1547             i_timescale = CLOCK_FREQ;
1548
1549         /* *** add /moov/trak *** */
1550         bo_t *trak = box_new("trak");
1551
1552         /* *** add /moov/trak/tkhd *** */
1553         bo_t *tkhd;
1554         if (!p_sys->b_64_ext) {
1555             if (p_sys->b_mov)
1556                 tkhd = box_full_new("tkhd", 0, 0x0f);
1557             else
1558                 tkhd = box_full_new("tkhd", 0, 1);
1559
1560             bo_add_32be(tkhd, i_timestamp);       // creation time
1561             bo_add_32be(tkhd, i_timestamp);       // modification time
1562             bo_add_32be(tkhd, p_stream->i_track_id);
1563             bo_add_32be(tkhd, 0);                     // reserved 0
1564             bo_add_32be(tkhd, p_stream->i_duration *
1565                          (int64_t)i_movie_timescale / CLOCK_FREQ); // duration
1566         } else {
1567             if (p_sys->b_mov)
1568                 tkhd = box_full_new("tkhd", 1, 0x0f);
1569             else
1570                 tkhd = box_full_new("tkhd", 1, 1);
1571
1572             bo_add_64be(tkhd, i_timestamp);       // creation time
1573             bo_add_64be(tkhd, i_timestamp);       // modification time
1574             bo_add_32be(tkhd, p_stream->i_track_id);
1575             bo_add_32be(tkhd, 0);                     // reserved 0
1576             bo_add_64be(tkhd, p_stream->i_duration *
1577                          (int64_t)i_movie_timescale / CLOCK_FREQ); // duration
1578         }
1579
1580         for (int i = 0; i < 2; i++)
1581             bo_add_32be(tkhd, 0);                 // reserved
1582         bo_add_16be(tkhd, 0);                     // layer
1583         bo_add_16be(tkhd, 0);                     // pre-defined
1584         // volume
1585         bo_add_16be(tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0);
1586         bo_add_16be(tkhd, 0);                     // reserved
1587         matrix_apply_rotation(&p_stream->fmt, mvhd_matrix);
1588         for (int i = 0; i < 9; i++)
1589             bo_add_32be(tkhd, mvhd_matrix[i]);    // matrix
1590         if (p_stream->fmt.i_cat == AUDIO_ES) {
1591             bo_add_32be(tkhd, 0);                 // width (presentation)
1592             bo_add_32be(tkhd, 0);                 // height(presentation)
1593         } else if (p_stream->fmt.i_cat == VIDEO_ES) {
1594             int i_width = p_stream->fmt.video.i_width << 16;
1595             if (p_stream->fmt.video.i_sar_num > 0 && p_stream->fmt.video.i_sar_den > 0) {
1596                 i_width = (int64_t)p_stream->fmt.video.i_sar_num *
1597                           ((int64_t)p_stream->fmt.video.i_width << 16) /
1598                           p_stream->fmt.video.i_sar_den;
1599             }
1600             // width (presentation)
1601             bo_add_32be(tkhd, i_width);
1602             // height(presentation)
1603             bo_add_32be(tkhd, p_stream->fmt.video.i_height << 16);
1604         } else {
1605             int i_width = 320 << 16;
1606             int i_height = 200;
1607             for (int i = 0; i < p_sys->i_nb_streams; i++) {
1608                 mp4_stream_t *tk = p_sys->pp_streams[i];
1609                 if (tk->fmt.i_cat == VIDEO_ES) {
1610                     if (tk->fmt.video.i_sar_num > 0 &&
1611                         tk->fmt.video.i_sar_den > 0)
1612                         i_width = (int64_t)tk->fmt.video.i_sar_num *
1613                                   ((int64_t)tk->fmt.video.i_width << 16) /
1614                                   tk->fmt.video.i_sar_den;
1615                     else
1616                         i_width = tk->fmt.video.i_width << 16;
1617                     i_height = tk->fmt.video.i_height;
1618                     break;
1619                 }
1620             }
1621             bo_add_32be(tkhd, i_width);     // width (presentation)
1622             bo_add_32be(tkhd, i_height << 16);    // height(presentation)
1623         }
1624
1625         box_gather(trak, tkhd);
1626
1627         /* *** add /moov/trak/edts and elst */
1628         bo_t *edts = box_new("edts");
1629         bo_t *elst = box_full_new("elst", p_sys->b_64_ext ? 1 : 0, 0);
1630         if (p_stream->i_dts_start > p_sys->i_dts_start) {
1631             bo_add_32be(elst, 2);
1632
1633             if (p_sys->b_64_ext) {
1634                 bo_add_64be(elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1635                              i_movie_timescale / CLOCK_FREQ);
1636                 bo_add_64be(elst, -1);
1637             } else {
1638                 bo_add_32be(elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1639                              i_movie_timescale / CLOCK_FREQ);
1640                 bo_add_32be(elst, -1);
1641             }
1642             bo_add_16be(elst, 1);
1643             bo_add_16be(elst, 0);
1644         } else {
1645             bo_add_32be(elst, 1);
1646         }
1647         if (p_sys->b_64_ext) {
1648             bo_add_64be(elst, p_stream->i_duration *
1649                          i_movie_timescale / CLOCK_FREQ);
1650             bo_add_64be(elst, 0);
1651         } else {
1652             bo_add_32be(elst, p_stream->i_duration *
1653                          i_movie_timescale / CLOCK_FREQ);
1654             bo_add_32be(elst, 0);
1655         }
1656         bo_add_16be(elst, 1);
1657         bo_add_16be(elst, 0);
1658
1659         box_gather(edts, elst);
1660         box_gather(trak, edts);
1661
1662         /* *** add /moov/trak/mdia *** */
1663         bo_t *mdia = box_new("mdia");
1664
1665         /* media header */
1666         bo_t *mdhd;
1667         if (!p_sys->b_64_ext) {
1668             mdhd = box_full_new("mdhd", 0, 0);
1669             bo_add_32be(mdhd, i_timestamp);   // creation time
1670             bo_add_32be(mdhd, i_timestamp);   // modification time
1671             bo_add_32be(mdhd, i_timescale);        // timescale
1672             bo_add_32be(mdhd, p_stream->i_duration * (int64_t)i_timescale /
1673                                CLOCK_FREQ);  // duration
1674         } else {
1675             mdhd = box_full_new("mdhd", 1, 0);
1676             bo_add_64be(mdhd, i_timestamp);   // creation time
1677             bo_add_64be(mdhd, i_timestamp);   // modification time
1678             bo_add_32be(mdhd, i_timescale);        // timescale
1679             bo_add_64be(mdhd, p_stream->i_duration * (int64_t)i_timescale /
1680                                CLOCK_FREQ);  // duration
1681         }
1682
1683         if (p_stream->fmt.psz_language) {
1684             char *psz = p_stream->fmt.psz_language;
1685             const iso639_lang_t *pl = NULL;
1686             uint16_t lang = 0x0;
1687
1688             if (strlen(psz) == 2)
1689                 pl = GetLang_1(psz);
1690             else if (strlen(psz) == 3) {
1691                 pl = GetLang_2B(psz);
1692                 if (!strcmp(pl->psz_iso639_1, "??"))
1693                     pl = GetLang_2T(psz);
1694             }
1695
1696             if (pl && strcmp(pl->psz_iso639_1, "??"))
1697                 lang = ((pl->psz_iso639_2T[0] - 0x60) << 10) |
1698                        ((pl->psz_iso639_2T[1] - 0x60) <<  5) |
1699                        ((pl->psz_iso639_2T[2] - 0x60));
1700             bo_add_16be(mdhd, lang);          // language
1701         } else
1702             bo_add_16be(mdhd, 0   );          // language
1703         bo_add_16be(mdhd, 0   );              // predefined
1704         box_gather(mdia, mdhd);
1705
1706         /* handler reference */
1707         bo_t *hdlr = box_full_new("hdlr", 0, 0);
1708
1709         if (p_sys->b_mov)
1710             bo_add_fourcc(hdlr, "mhlr");         // media handler
1711         else
1712             bo_add_32be(hdlr, 0);
1713
1714         if (p_stream->fmt.i_cat == AUDIO_ES)
1715             bo_add_fourcc(hdlr, "soun");
1716         else if (p_stream->fmt.i_cat == VIDEO_ES)
1717             bo_add_fourcc(hdlr, "vide");
1718         else if (p_stream->fmt.i_cat == SPU_ES)
1719             bo_add_fourcc(hdlr, "text");
1720
1721         bo_add_32be(hdlr, 0);         // reserved
1722         bo_add_32be(hdlr, 0);         // reserved
1723         bo_add_32be(hdlr, 0);         // reserved
1724
1725         if (p_sys->b_mov)
1726             bo_add_8(hdlr, 12);   /* Pascal string for .mov */
1727
1728         if (p_stream->fmt.i_cat == AUDIO_ES)
1729             bo_add_mem(hdlr, 12, (uint8_t*)"SoundHandler");
1730         else if (p_stream->fmt.i_cat == VIDEO_ES)
1731             bo_add_mem(hdlr, 12, (uint8_t*)"VideoHandler");
1732         else
1733             bo_add_mem(hdlr, 12, (uint8_t*)"Text Handler");
1734
1735         if (!p_sys->b_mov)
1736             bo_add_8(hdlr, 0);   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
1737
1738         box_gather(mdia, hdlr);
1739
1740         /* minf*/
1741         bo_t *minf = box_new("minf");
1742
1743         /* add smhd|vmhd */
1744         if (p_stream->fmt.i_cat == AUDIO_ES) {
1745             bo_t *smhd;
1746
1747             smhd = box_full_new("smhd", 0, 0);
1748             bo_add_16be(smhd, 0);     // balance
1749             bo_add_16be(smhd, 0);     // reserved
1750
1751             box_gather(minf, smhd);
1752         } else if (p_stream->fmt.i_cat == VIDEO_ES) {
1753             bo_t *vmhd;
1754
1755             vmhd = box_full_new("vmhd", 0, 1);
1756             bo_add_16be(vmhd, 0);     // graphicsmode
1757             for (int i = 0; i < 3; i++)
1758                 bo_add_16be(vmhd, 0); // opcolor
1759
1760             box_gather(minf, vmhd);
1761         } else if (p_stream->fmt.i_cat == SPU_ES) {
1762             bo_t *gmhd = box_new("gmhd");
1763             bo_t *gmin = box_full_new("gmin", 0, 1);
1764
1765             bo_add_16be(gmin, 0);     // graphicsmode
1766             for (int i = 0; i < 3; i++)
1767                 bo_add_16be(gmin, 0); // opcolor
1768             bo_add_16be(gmin, 0);     // balance
1769             bo_add_16be(gmin, 0);     // reserved
1770
1771             box_gather(gmhd, gmin);
1772
1773             box_gather(minf, gmhd);
1774         }
1775
1776         /* dinf */
1777         bo_t *dinf = box_new("dinf");
1778         bo_t *dref = box_full_new("dref", 0, 0);
1779         bo_add_32be(dref, 1);
1780         bo_t *url = box_full_new("url ", 0, 0x01);
1781         box_gather(dref, url);
1782         box_gather(dinf, dref);
1783
1784         /* append dinf to mdia */
1785         box_gather(minf, dinf);
1786
1787         /* add stbl */
1788         bo_t *stbl = GetStblBox(p_mux, p_stream);
1789
1790         /* append stbl to minf */
1791         p_stream->i_stco_pos += minf->len;
1792         box_gather(minf, stbl);
1793
1794         /* append minf to mdia */
1795         p_stream->i_stco_pos += mdia->len;
1796         box_gather(mdia, minf);
1797
1798         /* append mdia to trak */
1799         p_stream->i_stco_pos += trak->len;
1800         box_gather(trak, mdia);
1801
1802         /* append trak to moov */
1803         p_stream->i_stco_pos += moov->len;
1804         box_gather(moov, trak);
1805     }
1806
1807     /* Add user data tags */
1808     box_gather(moov, GetUdtaTag(p_mux));
1809
1810     box_fix(moov);
1811     return moov;
1812 }
1813
1814 /****************************************************************************/
1815
1816 static void bo_init(bo_t *p_bo)
1817 {
1818     p_bo->len = 0;
1819     p_bo->b = block_Alloc(1024);
1820 }
1821
1822 static void bo_add_8(bo_t *p_bo, uint8_t i)
1823 {
1824     if (p_bo->len >= p_bo->b->i_buffer)
1825         p_bo->b = block_Realloc(p_bo->b, 0, p_bo->b->i_buffer + 1024);
1826
1827     p_bo->b->p_buffer[p_bo->len++] = i;
1828 }
1829
1830 static void bo_add_16be(bo_t *p_bo, uint16_t i)
1831 {
1832     bo_add_8(p_bo, ((i >> 8) &0xff));
1833     bo_add_8(p_bo, i &0xff);
1834 }
1835
1836 static void bo_add_24be(bo_t *p_bo, uint32_t i)
1837 {
1838     bo_add_8(p_bo, ((i >> 16) &0xff));
1839     bo_add_8(p_bo, ((i >> 8) &0xff));
1840     bo_add_8(p_bo, (  i &0xff));
1841 }
1842 static void bo_add_32be(bo_t *p_bo, uint32_t i)
1843 {
1844     bo_add_16be(p_bo, ((i >> 16) &0xffff));
1845     bo_add_16be(p_bo, i &0xffff);
1846 }
1847
1848 static void bo_fix_32be (bo_t *p_bo, int i_pos, uint32_t i)
1849 {
1850     p_bo->b->p_buffer[i_pos    ] = (i >> 24)&0xff;
1851     p_bo->b->p_buffer[i_pos + 1] = (i >> 16)&0xff;
1852     p_bo->b->p_buffer[i_pos + 2] = (i >>  8)&0xff;
1853     p_bo->b->p_buffer[i_pos + 3] = (i      )&0xff;
1854 }
1855
1856 static void bo_add_64be(bo_t *p_bo, uint64_t i)
1857 {
1858     bo_add_32be(p_bo, ((i >> 32) &0xffffffff));
1859     bo_add_32be(p_bo, i &0xffffffff);
1860 }
1861
1862 static void bo_add_fourcc(bo_t *p_bo, const char *fcc)
1863 {
1864     bo_add_8(p_bo, fcc[0]);
1865     bo_add_8(p_bo, fcc[1]);
1866     bo_add_8(p_bo, fcc[2]);
1867     bo_add_8(p_bo, fcc[3]);
1868 }
1869
1870 static void bo_add_mem(bo_t *p_bo, int i_size, uint8_t *p_mem)
1871 {
1872     for (int i = 0; i < i_size; i++)
1873         bo_add_8(p_bo, p_mem[i]);
1874 }
1875
1876 static void bo_add_descr(bo_t *p_bo, uint8_t tag, uint32_t size)
1877 {
1878     bo_add_8(p_bo, tag);
1879     for (int i = 3; i>0; i--)
1880         bo_add_8(p_bo, (size>>(7*i)) | 0x80);
1881     bo_add_8(p_bo, size & 0x7F);
1882 }
1883
1884 static bo_t *box_new(const char *fcc)
1885 {
1886     bo_t *box = malloc(sizeof(*box));
1887     if (!box)
1888         return NULL;
1889
1890     bo_init(box);
1891
1892     bo_add_32be  (box, 0);
1893     bo_add_fourcc(box, fcc);
1894
1895     return box;
1896 }
1897
1898 static bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f)
1899 {
1900     bo_t *box = box_new(fcc);
1901     if (!box)
1902         return NULL;
1903
1904     bo_add_8     (box, v);
1905     bo_add_24be  (box, f);
1906
1907     return box;
1908 }
1909
1910 static void box_fix(bo_t *box)
1911 {
1912     box->b->p_buffer[0] = box->len >> 24;
1913     box->b->p_buffer[1] = box->len >> 16;
1914     box->b->p_buffer[2] = box->len >>  8;
1915     box->b->p_buffer[3] = box->len;
1916 }
1917
1918 static void box_gather (bo_t *box, bo_t *box2)
1919 {
1920     box_fix(box2);
1921     box->b = block_Realloc(box->b, 0, box->len + box2->len);
1922     memcpy(&box->b->p_buffer[box->len], box2->b->p_buffer, box2->len);
1923     box->len += box2->len;
1924     block_Release(box2->b);
1925     free(box2);
1926 }
1927
1928 static void box_send(sout_mux_t *p_mux,  bo_t *box)
1929 {
1930     box->b->i_buffer = box->len;
1931     sout_AccessOutWrite(p_mux->p_access, box->b);
1932     free(box);
1933 }
1934
1935 static int64_t get_timestamp(void)
1936 {
1937     int64_t i_timestamp = time(NULL);
1938
1939     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
1940     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
1941
1942     return i_timestamp;
1943 }