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