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