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