mux: mp4: fix use after free
[vlc.git] / modules / mux / mp4 / libmp4mux.c
blob3519e5098378f7a8c1073bb2f621c142df496874
1 /*****************************************************************************
2 * libmp4mux.c: mp4/mov muxer
3 *****************************************************************************
4 * Copyright (C) 2001, 2002, 2003, 2006, 20115 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Gildas Bazin <gbazin at videolan dot org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include "libmp4mux.h"
28 #include "../../demux/mp4/libmp4.h" /* flags */
29 #include "../../packetizer/hevc_nal.h"
30 #include "../../packetizer/h264_nal.h" /* h264_AnnexB_get_spspps */
31 #include "../../packetizer/hxxx_nal.h"
32 #include "../../packetizer/iso_color_tables.h"
34 #include <vlc_es.h>
35 #include <vlc_iso_lang.h>
36 #include <vlc_bits.h>
37 #include <vlc_arrays.h>
38 #include <vlc_text_style.h>
39 #include <assert.h>
40 #include <time.h>
42 struct mp4mux_trackinfo_t
44 unsigned i_track_id;
45 es_format_t fmt;
47 /* index */
48 unsigned int i_samples_count;
49 unsigned int i_samples_max;
50 mp4mux_sample_t *samples;
52 /* XXX: needed for other codecs too, see lavf */
53 struct
55 size_t i_data;
56 uint8_t *p_data;
57 } sample_priv;
59 /* stats */
60 vlc_tick_t i_read_duration;
61 uint32_t i_timescale;
62 bool b_hasbframes;
64 /* frags */
65 vlc_tick_t i_trex_default_length;
66 uint32_t i_trex_default_size;
68 /* edit list */
69 unsigned int i_edits_count;
70 mp4mux_edit_t *p_edits;
74 struct mp4mux_handle_t
76 unsigned options;
77 vlc_array_t tracks;
78 struct
80 vlc_fourcc_t i_major;
81 uint32_t i_minor;
82 DECL_ARRAY(vlc_fourcc_t) extra;
83 } brands;
86 static void mp4mux_AddExtraBrandForFormat(mp4mux_handle_t *h, const es_format_t *fmt)
88 switch(fmt->i_codec)
90 case VLC_CODEC_H264:
91 mp4mux_AddExtraBrand(h, BRAND_avc1);
92 break;
93 case VLC_CODEC_HEVC:
94 mp4mux_AddExtraBrand(h, BRAND_hevc);
95 break;
96 case VLC_CODEC_AV1:
97 mp4mux_AddExtraBrand(h, BRAND_av01);
98 mp4mux_AddExtraBrand(h, BRAND_iso6);
99 break;
100 case VLC_CODEC_MP4V:
101 case VLC_CODEC_DIV1:
102 case VLC_CODEC_DIV2:
103 case VLC_CODEC_DIV3:
104 case VLC_CODEC_H263:
105 mp4mux_AddExtraBrand(h, BRAND_mp41);
106 break;
107 case VLC_CODEC_MP4A:
108 mp4mux_AddExtraBrand(h, BRAND_mp41);
109 if(vlc_array_count(&h->tracks) == 1)
110 mp4mux_AddExtraBrand(h, BRAND_M4A);
111 break;
112 default:
113 break;
117 static bool mp4mux_trackinfo_Init(mp4mux_trackinfo_t *p_stream, unsigned i_id,
118 uint32_t i_timescale)
120 memset(p_stream, 0, sizeof(*p_stream));
121 p_stream->i_track_id = i_id;
123 p_stream->i_timescale = i_timescale;
124 es_format_Init(&p_stream->fmt, 0, 0);
126 return true;
129 static void mp4mux_trackinfo_Clear(mp4mux_trackinfo_t *p_stream)
131 es_format_Clean(&p_stream->fmt);
132 mp4mux_track_SetSamplePriv(p_stream, NULL, 0);
133 free(p_stream->samples);
134 free(p_stream->p_edits);
137 mp4mux_trackinfo_t * mp4mux_track_Add(mp4mux_handle_t *h, unsigned id,
138 const es_format_t *fmt, uint32_t timescale)
140 mp4mux_trackinfo_t *t = malloc(sizeof(*t));
141 if(!mp4mux_trackinfo_Init(t, 0, 0))
143 free(t);
144 return NULL;
146 t->i_track_id = id;
147 t->i_timescale = timescale;
148 es_format_Init(&t->fmt, fmt->i_cat, fmt->i_codec);
149 es_format_Copy(&t->fmt, fmt);
150 vlc_array_append(&h->tracks, t);
151 mp4mux_AddExtraBrandForFormat(h, fmt);
152 return t;
155 bool mp4mux_track_AddEdit(mp4mux_trackinfo_t *t, const mp4mux_edit_t *p_newedit)
157 mp4mux_edit_t *p_realloc = realloc( t->p_edits, sizeof(mp4mux_edit_t) *
158 (t->i_edits_count + 1) );
159 if(unlikely(!p_realloc))
160 return false;
162 t->p_edits = p_realloc;
163 t->p_edits[t->i_edits_count++] = *p_newedit;
165 return true;
168 const mp4mux_edit_t *mp4mux_track_GetLastEdit(const mp4mux_trackinfo_t *t)
170 if(t->i_edits_count)
171 return &t->p_edits[t->i_edits_count - 1];
172 else return NULL;
175 void mp4mux_track_DebugEdits(vlc_object_t *obj, const mp4mux_trackinfo_t *t)
177 for( unsigned i=0; i<t->i_edits_count; i++ )
179 msg_Dbg(obj, "tk %d elst media time %" PRId64 " duration %" PRIu64 " offset %" PRId64 ,
180 t->i_track_id,
181 t->p_edits[i].i_start_time,
182 t->p_edits[i].i_duration,
183 t->p_edits[i].i_start_offset);
187 bool mp4mux_track_AddSample(mp4mux_trackinfo_t *t, const mp4mux_sample_t *entry)
189 /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
190 if (t->i_samples_count + 2 >= t->i_samples_max)
192 mp4mux_sample_t *p_realloc =
193 realloc(t->samples, sizeof(*p_realloc) * (t->i_samples_max + 1000));
194 if(!p_realloc)
195 return false;
196 t->samples = p_realloc;
197 t->i_samples_max += 1000;
199 t->samples[t->i_samples_count++] = *entry;
200 if(!t->b_hasbframes && entry->i_pts_dts != 0)
201 t->b_hasbframes = true;
202 t->i_read_duration += __MAX(0, entry->i_length);
203 return true;
206 const mp4mux_sample_t *mp4mux_track_GetLastSample(const mp4mux_trackinfo_t *t)
208 if(t->i_samples_count)
209 return &t->samples[t->i_samples_count - 1];
210 else return NULL;
213 unsigned mp4mux_track_GetSampleCount(const mp4mux_trackinfo_t *t)
215 return t->i_samples_count;
218 void mp4mux_track_UpdateLastSample(mp4mux_trackinfo_t *t,
219 const mp4mux_sample_t *entry)
221 if(t->i_samples_count)
223 mp4mux_sample_t *e = &t->samples[t->i_samples_count - 1];
224 t->i_read_duration -= e->i_length;
225 t->i_read_duration += entry->i_length;
226 *e = *entry;
230 vlc_tick_t mp4mux_track_GetDefaultSampleDuration(const mp4mux_trackinfo_t *t)
232 return t->i_trex_default_length;
235 uint32_t mp4mux_track_GetDefaultSampleSize(const mp4mux_trackinfo_t *t)
237 return t->i_trex_default_size;
240 const es_format_t * mp4mux_track_GetFmt(const mp4mux_trackinfo_t *t)
242 return &t->fmt;
245 bool mp4mux_track_HasBFrames(const mp4mux_trackinfo_t *t)
247 return t->b_hasbframes;
250 void mp4mux_track_SetHasBFrames(mp4mux_trackinfo_t *t)
252 t->b_hasbframes = true;
255 uint32_t mp4mux_track_GetTimescale(const mp4mux_trackinfo_t *t)
257 return t->i_timescale;
260 vlc_tick_t mp4mux_track_GetDuration(const mp4mux_trackinfo_t *t)
262 return t->i_read_duration;
265 void mp4mux_track_ForceDuration(mp4mux_trackinfo_t *t, vlc_tick_t d)
267 t->i_read_duration = d;
270 uint32_t mp4mux_track_GetID(const mp4mux_trackinfo_t *t)
272 return t->i_track_id;
275 void mp4mux_track_SetSamplePriv(mp4mux_trackinfo_t *t,
276 const uint8_t *p_data, size_t i_data)
278 if(t->sample_priv.p_data)
280 free(t->sample_priv.p_data);
281 t->sample_priv.p_data = NULL;
282 t->sample_priv.i_data = 0;
285 if(p_data && i_data)
287 t->sample_priv.p_data = malloc(i_data);
288 if(i_data)
290 memcpy(t->sample_priv.p_data, p_data, i_data);
291 t->sample_priv.i_data = i_data;
296 bool mp4mux_track_HasSamplePriv(const mp4mux_trackinfo_t *t)
298 return t->sample_priv.i_data != 0;
301 void mp4mux_ShiftSamples(mp4mux_handle_t *h, int64_t offset)
303 for(size_t i_track = 0; i_track < vlc_array_count(&h->tracks); i_track++)
305 mp4mux_trackinfo_t *t = vlc_array_item_at_index(&h->tracks, i_track);
306 for (unsigned i = 0; i < t->i_samples_count; i++)
308 mp4mux_sample_t *sample = t->samples;
309 sample[i].i_pos += offset;
314 mp4mux_handle_t * mp4mux_New(enum mp4mux_options options)
316 mp4mux_handle_t *h = malloc(sizeof(*h));
317 vlc_array_init(&h->tracks);
318 ARRAY_INIT(h->brands.extra);
319 h->brands.i_major = 0;
320 h->brands.i_minor = 0;
321 h->options = options;
322 return h;
325 void mp4mux_Delete(mp4mux_handle_t *h)
327 for(size_t i=0; i<vlc_array_count(&h->tracks); i++)
329 mp4mux_trackinfo_t *t = vlc_array_item_at_index(&h->tracks, i);
330 mp4mux_trackinfo_Clear(t);
331 free(t);
333 vlc_array_clear(&h->tracks);
334 ARRAY_RESET(h->brands.extra);
335 free(h);
338 void mp4mux_Set64BitExt(mp4mux_handle_t *h)
340 /* FIXME FIXME
341 * Quicktime actually doesn't like the 64 bits extensions !!! */
342 if(h->options & QUICKTIME)
343 return;
345 h->options |= USE64BITEXT;
348 bool mp4mux_Is(mp4mux_handle_t *h, enum mp4mux_options o)
350 return h->options & o;
353 void mp4mux_SetBrand(mp4mux_handle_t *h, vlc_fourcc_t i_major, uint32_t i_minor)
355 h->brands.i_major = i_major;
356 h->brands.i_minor = i_minor;
357 mp4mux_AddExtraBrand(h, i_major);
360 void mp4mux_AddExtraBrand(mp4mux_handle_t *h, vlc_fourcc_t b)
362 for(int i=0; i<h->brands.extra.i_size; i++)
363 if(h->brands.extra.p_elems[i] == b)
364 return;
365 ARRAY_APPEND(h->brands.extra, b);
368 bo_t *box_new(const char *fcc)
370 bo_t *box = malloc(sizeof(*box));
371 if (!box)
372 return NULL;
374 if(!bo_init(box, 1024))
376 bo_free(box);
377 return NULL;
380 bo_add_32be (box, 0);
381 bo_add_fourcc(box, fcc);
383 return box;
386 bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f)
388 bo_t *box = box_new(fcc);
389 if (!box)
390 return NULL;
392 bo_add_8 (box, v);
393 bo_add_24be (box, f);
395 return box;
398 void box_fix(bo_t *box, uint32_t i_size)
400 bo_set_32be(box, 0, i_size);
403 void box_gather (bo_t *box, bo_t *box2)
405 if(box2 && box2->b && box && box->b)
407 box_fix(box2, bo_size( box2 ));
408 size_t i_offset = bo_size( box );
409 box->b = block_Realloc(box->b, 0, box->b->i_buffer + box2->b->i_buffer);
410 if(likely(box->b))
411 memcpy(&box->b->p_buffer[i_offset], box2->b->p_buffer, box2->b->i_buffer);
413 bo_free(box2);
416 static inline void bo_add_mp4_tag_descr(bo_t *box, uint8_t tag, uint32_t size)
418 bo_add_8(box, tag);
419 for (int i = 3; i>0; i--)
420 bo_add_8(box, (size>>(7*i)) | 0x80);
421 bo_add_8(box, size & 0x7F);
424 static int64_t get_timestamp(void)
426 int64_t i_timestamp = time(NULL);
428 i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
429 // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
431 return i_timestamp;
434 /****************************************************************************/
436 static void matrix_apply_rotation(es_format_t *fmt, uint32_t mvhd_matrix[9])
438 enum video_orientation_t orientation = ORIENT_NORMAL;
439 if (fmt->i_cat == VIDEO_ES)
440 orientation = fmt->video.orientation;
442 #define ATAN(a, b) \
443 do { \
444 mvhd_matrix[1] = ((uint32_t)(a)) << 16; \
445 mvhd_matrix[0] = ((uint32_t)(b)) << 16; \
446 } while(0)
448 switch (orientation) {
449 case ORIENT_ROTATED_90: ATAN( 1, 0); break;
450 case ORIENT_ROTATED_180: ATAN( 0, -1); break;
451 case ORIENT_ROTATED_270: ATAN(-1, 0); break;
452 default: ATAN( 0, 1); break;
455 mvhd_matrix[3] = mvhd_matrix[0] ? 0 : 0x10000;
456 mvhd_matrix[4] = mvhd_matrix[1] ? 0 : 0x10000;
459 static void AddEdit(bo_t *elst,
460 int64_t i_movie_scaled_duration,
461 int64_t i_media_scaled_time,
462 bool b_64_ext)
464 if(b_64_ext)
466 bo_add_64be(elst, i_movie_scaled_duration);
467 bo_add_64be(elst, i_media_scaled_time);
469 else
471 bo_add_32be(elst, i_movie_scaled_duration);
472 bo_add_32be(elst, i_media_scaled_time);
474 bo_add_16be(elst, 1);
475 bo_add_16be(elst, 0);
478 static bo_t *GetEDTS( mp4mux_trackinfo_t *p_track, uint32_t i_movietimescale, bool b_64_ext)
480 if(p_track->i_edits_count == 0)
481 return NULL;
483 bo_t *edts = box_new("edts");
484 bo_t *elst = box_full_new("elst", b_64_ext ? 1 : 0, 0);
485 if(!elst || !edts)
487 bo_free(elst);
488 bo_free(edts);
489 return NULL;
492 uint32_t i_total_edits = p_track->i_edits_count;
493 for(unsigned i=0; i<p_track->i_edits_count; i++)
495 /* !WARN! media time must start sample time 0, we need a -1 edit for start offsets */
496 if(p_track->p_edits[i].i_start_offset != 0)
497 i_total_edits++;
500 bo_add_32be(elst, i_total_edits);
502 for(unsigned i=0; i<p_track->i_edits_count; i++)
504 if(p_track->p_edits[i].i_start_offset != 0)
506 AddEdit(elst,
507 samples_from_vlc_tick(p_track->p_edits[i].i_start_offset, i_movietimescale),
509 b_64_ext);
512 /* !WARN AGAIN! Uses different Timescales ! */
513 AddEdit(elst,
514 samples_from_vlc_tick(p_track->p_edits[i].i_duration, i_movietimescale),
515 samples_from_vlc_tick(p_track->p_edits[i].i_start_time, p_track->i_timescale),
516 b_64_ext);
519 box_gather(edts, elst);
520 return edts;
523 static bo_t *GetESDS(mp4mux_trackinfo_t *p_track)
525 bo_t *esds;
527 /* */
528 int i_decoder_specific_info_size = (p_track->fmt.i_extra > 0) ? 5 + p_track->fmt.i_extra : 0;
530 esds = box_full_new("esds", 0, 0);
531 if(!esds)
532 return NULL;
534 /* Compute Max bitrate */
535 int64_t i_bitrate_avg = 0;
536 int64_t i_bitrate_max = 0;
537 /* Compute avg/max bitrate */
538 for (unsigned i = 0; i < p_track->i_samples_count; i++) {
539 i_bitrate_avg += p_track->samples[i].i_size;
540 if (p_track->samples[i].i_length > 0) {
541 int64_t i_bitrate = CLOCK_FREQ * 8 * p_track->samples[i].i_size / p_track->samples[i].i_length;
542 if (i_bitrate > i_bitrate_max)
543 i_bitrate_max = i_bitrate;
547 if (p_track->i_read_duration > 0)
548 i_bitrate_avg = CLOCK_FREQ * 8 * i_bitrate_avg / p_track->i_read_duration;
549 else
550 i_bitrate_avg = 0;
551 if (i_bitrate_max <= 1)
552 i_bitrate_max = 0x7fffffff;
554 /* ES_Descr */
555 bo_add_mp4_tag_descr(esds, 0x03, 3 + 5 + 13 + i_decoder_specific_info_size + 5 + 1);
556 bo_add_16be(esds, p_track->i_track_id);
557 bo_add_8 (esds, 0x1f); // flags=0|streamPriority=0x1f
559 /* DecoderConfigDescr */
560 bo_add_mp4_tag_descr(esds, 0x04, 13 + i_decoder_specific_info_size);
562 int i_object_type_indication;
563 switch(p_track->fmt.i_codec)
565 case VLC_CODEC_MP4V:
566 i_object_type_indication = 0x20;
567 break;
568 case VLC_CODEC_MPGV:
569 if(p_track->fmt.i_original_fourcc == VLC_CODEC_MP1V)
571 i_object_type_indication = 0x6b;
572 break;
574 /* fallthrough */
575 case VLC_CODEC_MP2V:
576 /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
577 i_object_type_indication = 0x65;
578 break;
579 case VLC_CODEC_MP1V:
580 /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
581 i_object_type_indication = 0x6b;
582 break;
583 case VLC_CODEC_MP4A:
584 /* FIXME for mpeg2-aac == 0x66->0x68 */
585 i_object_type_indication = 0x40;
586 break;
587 case VLC_CODEC_MPGA:
588 i_object_type_indication =
589 p_track->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b;
590 break;
591 case VLC_CODEC_DTS:
592 i_object_type_indication = 0xa9;
593 break;
594 default:
595 i_object_type_indication = 0xFE; /* No profile specified */
596 break;
599 uint8_t i_stream_type;
600 switch(p_track->fmt.i_cat)
602 case VIDEO_ES:
603 i_stream_type = 0x04;
604 break;
605 case AUDIO_ES:
606 i_stream_type = 0x05;
607 break;
608 case SPU_ES:
609 i_stream_type = 0x0D;
610 break;
611 default:
612 i_stream_type = 0x20; /* Private */
613 break;
616 bo_add_8 (esds, i_object_type_indication);
617 bo_add_8 (esds, (i_stream_type << 2) | 1);
618 bo_add_24be(esds, 1024 * 1024); // bufferSizeDB
619 bo_add_32be(esds, i_bitrate_max); // maxBitrate
620 bo_add_32be(esds, i_bitrate_avg); // avgBitrate
622 if (p_track->fmt.i_extra > 0) {
623 /* DecoderSpecificInfo */
624 bo_add_mp4_tag_descr(esds, 0x05, p_track->fmt.i_extra);
626 for (int i = 0; i < p_track->fmt.i_extra; i++)
627 bo_add_8(esds, ((uint8_t*)p_track->fmt.p_extra)[i]);
630 /* SL_Descr mandatory */
631 bo_add_mp4_tag_descr(esds, 0x06, 1);
632 bo_add_8 (esds, 0x02); // sl_predefined
634 return esds;
637 static bo_t *GetWaveTag(mp4mux_trackinfo_t *p_track)
639 bo_t *wave;
640 bo_t *box;
642 wave = box_new("wave");
643 if(wave)
645 box = box_new("frma");
646 if(box)
648 bo_add_fourcc(box, "mp4a");
649 box_gather(wave, box);
652 box = box_new("mp4a");
653 if(box)
655 bo_add_32be(box, 0);
656 box_gather(wave, box);
659 box = GetESDS(p_track);
660 box_gather(wave, box);
662 box = box_new("srcq");
663 if(box)
665 bo_add_32be(box, 0x40);
666 box_gather(wave, box);
669 /* wazza ? */
670 bo_add_32be(wave, 8); /* new empty box */
671 bo_add_32be(wave, 0); /* box label */
673 return wave;
676 static bo_t *GetDamrTag(es_format_t *p_fmt)
678 bo_t *damr = box_new("damr");
679 if(!damr)
680 return NULL;
682 bo_add_fourcc(damr, "REFC");
683 bo_add_8(damr, 0);
685 if (p_fmt->i_codec == VLC_CODEC_AMR_NB)
686 bo_add_16be(damr, 0x81ff); /* Mode set (all modes for AMR_NB) */
687 else
688 bo_add_16be(damr, 0x83ff); /* Mode set (all modes for AMR_WB) */
689 bo_add_16be(damr, 0x1); /* Mode change period (no restriction) */
691 return damr;
694 static bo_t *GetD263Tag(void)
696 bo_t *d263 = box_new("d263");
697 if(!d263)
698 return NULL;
700 bo_add_fourcc(d263, "VLC ");
701 bo_add_16be(d263, 0xa);
702 bo_add_8(d263, 0);
704 return d263;
707 static bo_t *GetHvcCTag(const uint8_t *p_extra, size_t i_extra,
708 bool b_completeness)
711 /* Generate hvcC box matching iso/iec 14496-15 3rd edition */
712 bo_t *hvcC = box_new("hvcC");
713 if(!hvcC || !i_extra)
714 return hvcC;
716 /* Extradata is already an HEVCDecoderConfigurationRecord */
717 if(hevc_ishvcC(p_extra, i_extra))
719 (void) bo_add_mem(hvcC, i_extra, p_extra);
720 return hvcC;
723 struct hevc_dcr_params params = { 0 };
724 const uint8_t *p_nal;
725 size_t i_nal;
727 hxxx_iterator_ctx_t it;
728 hxxx_iterator_init(&it, p_extra, i_extra, 0);
729 while(hxxx_annexb_iterate_next(&it, &p_nal, &i_nal))
731 switch (hevc_getNALType(p_nal))
733 case HEVC_NAL_VPS:
734 if(params.i_vps_count != HEVC_DCR_VPS_COUNT)
736 params.p_vps[params.i_vps_count] = p_nal;
737 params.rgi_vps[params.i_vps_count] = i_nal;
738 params.i_vps_count++;
740 break;
741 case HEVC_NAL_SPS:
742 if(params.i_sps_count != HEVC_DCR_SPS_COUNT)
744 params.p_sps[params.i_sps_count] = p_nal;
745 params.rgi_sps[params.i_sps_count] = i_nal;
746 params.i_sps_count++;
748 break;
749 case HEVC_NAL_PPS:
750 if(params.i_pps_count != HEVC_DCR_PPS_COUNT)
752 params.p_pps[params.i_pps_count] = p_nal;
753 params.rgi_pps[params.i_pps_count] = i_nal;
754 params.i_pps_count++;
756 break;
757 case HEVC_NAL_PREF_SEI:
758 if(params.i_seipref_count != HEVC_DCR_SEI_COUNT)
760 params.p_seipref[params.i_seipref_count] = p_nal;
761 params.rgi_seipref[params.i_seipref_count] = i_nal;
762 params.i_seipref_count++;
764 break;
765 case HEVC_NAL_SUFF_SEI:
766 if(params.i_seisuff_count != HEVC_DCR_SEI_COUNT)
768 params.p_seisuff[params.i_seisuff_count] = p_nal;
769 params.rgi_seisuff[params.i_seisuff_count] = i_nal;
770 params.i_seisuff_count++;
772 break;
774 default:
775 break;
779 size_t i_dcr;
780 uint8_t *p_dcr = hevc_create_dcr(&params, 4, b_completeness, &i_dcr);
781 if(!p_dcr)
783 bo_free(hvcC);
784 return NULL;
787 bo_add_mem(hvcC, i_dcr, p_dcr);
788 free(p_dcr);
790 return hvcC;
793 static bo_t *GetWaveFormatExTag(es_format_t *p_fmt, const char *tag)
795 bo_t *box = box_new(tag);
796 if(!box)
797 return NULL;
799 uint16_t wFormatTag;
800 fourcc_to_wf_tag(p_fmt->i_codec, &wFormatTag);
801 bo_add_16le(box, wFormatTag); //wFormatTag
802 bo_add_16le(box, p_fmt->audio.i_channels); //nChannels
803 bo_add_32le(box, p_fmt->audio.i_rate); //nSamplesPerSec
804 bo_add_32le(box, p_fmt->i_bitrate / 8); //nAvgBytesPerSec
805 bo_add_16le(box, p_fmt->audio.i_blockalign); //nBlockAlign
806 bo_add_16le(box, p_fmt->audio.i_bitspersample); //wBitsPerSample
807 bo_add_16le(box, p_fmt->i_extra); //cbSize
809 bo_add_mem(box, p_fmt->i_extra, p_fmt->p_extra);
811 return box;
814 static bo_t *GetxxxxTag(const uint8_t *p_extra, size_t i_extra,
815 const char *tag)
817 bo_t *box = box_new(tag);
818 if(!box)
819 return NULL;
820 bo_add_mem(box, i_extra, p_extra);
821 return box;
824 static bo_t *GetColrBox(const video_format_t *p_vfmt, bool b_mov)
826 bo_t *p_box = box_new("colr");
827 if(p_box)
829 bo_add_mem(p_box, 4, b_mov ? "nclc" : "nclx");
830 bo_add_16be(p_box, vlc_primaries_to_iso_23001_8_cp(p_vfmt->primaries));
831 bo_add_16be(p_box, vlc_xfer_to_iso_23001_8_tc(p_vfmt->transfer));
832 bo_add_16be(p_box, vlc_coeffs_to_iso_23001_8_mc(p_vfmt->space));
833 bo_add_8(p_box, p_vfmt->color_range == COLOR_RANGE_FULL ? 0x80 : 0x00);
835 return p_box;
838 static bo_t *GetMdcv(const video_format_t *p_vfmt)
840 if(!p_vfmt->mastering.max_luminance)
841 return NULL;
842 bo_t *p_box = box_new("mdcv");
843 if(p_box)
845 for(int i=0; i<6; i++)
846 bo_add_16be(p_box, p_vfmt->mastering.primaries[i]);
847 bo_add_16be(p_box, p_vfmt->mastering.white_point[0]);
848 bo_add_16be(p_box, p_vfmt->mastering.white_point[1]);
849 bo_add_32be(p_box, p_vfmt->mastering.max_luminance);
850 bo_add_32be(p_box, p_vfmt->mastering.min_luminance);
852 return p_box;
855 static bo_t *GetClli(const video_format_t *p_vfmt)
857 if(!p_vfmt->lighting.MaxFALL)
858 return NULL;
859 bo_t *p_box = box_new("clli");
860 if(p_box)
862 bo_add_16be(p_box, p_vfmt->lighting.MaxCLL);
863 bo_add_16be(p_box, p_vfmt->lighting.MaxFALL);
865 return p_box;
868 static bo_t *GetAvcCTag(const uint8_t *p_extra, size_t i_extra)
870 bo_t *avcC = box_new("avcC");/* FIXME use better value */
871 if(!avcC)
872 return NULL;
873 const uint8_t *p_sps, *p_pps, *p_ext;
874 size_t i_sps_size, i_pps_size, i_ext_size;
876 if(! h264_AnnexB_get_spspps(p_extra, i_extra,
877 &p_sps, &i_sps_size,
878 &p_pps, &i_pps_size,
879 &p_ext, &i_ext_size ) )
881 p_sps = p_pps = p_ext = NULL;
882 i_sps_size = i_pps_size = i_ext_size = 0;
885 bo_add_8(avcC, 1); /* configuration version */
886 bo_add_8(avcC, i_sps_size > 3 ? p_sps[1] : PROFILE_H264_MAIN);
887 bo_add_8(avcC, i_sps_size > 3 ? p_sps[2] : 64);
888 bo_add_8(avcC, i_sps_size > 3 ? p_sps[3] : 30); /* level, 5.1 */
889 bo_add_8(avcC, 0xff); /* 0b11111100 | lengthsize = 0x11 */
891 bo_add_8(avcC, 0xe0 | (i_sps_size > 0 ? 1 : 0)); /* 0b11100000 | sps_count */
892 if (i_sps_size > 0) {
893 bo_add_16be(avcC, i_sps_size);
894 bo_add_mem(avcC, i_sps_size, p_sps);
897 bo_add_8(avcC, (i_pps_size > 0 ? 1 : 0)); /* pps_count */
898 if (i_pps_size > 0) {
899 bo_add_16be(avcC, i_pps_size);
900 bo_add_mem(avcC, i_pps_size, p_pps);
903 if( i_sps_size > 3 &&
904 (p_sps[1] == PROFILE_H264_HIGH ||
905 p_sps[1] == PROFILE_H264_HIGH_10 ||
906 p_sps[1] == PROFILE_H264_HIGH_422 ||
907 p_sps[1] == PROFILE_H264_HIGH_444 ||
908 p_sps[1] == PROFILE_H264_HIGH_444_PREDICTIVE) )
910 h264_sequence_parameter_set_t *p_spsdata = h264_decode_sps( p_sps, i_sps_size, true );
911 if( p_spsdata )
913 uint8_t data[3];
914 if( h264_get_chroma_luma( p_spsdata, &data[0], &data[1], &data[2]) )
916 bo_add_8(avcC, 0xFC | data[0]);
917 bo_add_8(avcC, 0xF8 | (data[1] - 8));
918 bo_add_8(avcC, 0xF8 | (data[2] - 8));
919 bo_add_8(avcC, (i_ext_size > 0 ? 1 : 0));
920 if (i_ext_size > 0) {
921 bo_add_16be(avcC, i_ext_size);
922 bo_add_mem(avcC, i_ext_size, p_ext);
925 h264_release_sps( p_spsdata );
929 return avcC;
932 /* TODO: No idea about these values */
933 static bo_t *GetSVQ3Tag(const uint8_t *p_extra, size_t i_extra)
935 bo_t *smi = box_new("SMI ");
936 if(!smi)
937 return NULL;
939 if (i_extra > 0x4e) {
940 const uint8_t *p_end = &p_extra[i_extra];
941 const uint8_t *p = &p_extra[0x46];
943 while (p + 8 < p_end) {
944 int i_size = GetDWBE(p);
945 if (i_size <= 1) /* FIXME handle 1 as long size */
946 break;
947 if (!strncmp((const char *)&p[4], "SMI ", 4)) {
948 bo_add_mem(smi, p_end - p - 8, &p[8]);
949 return smi;
951 p += i_size;
955 /* Create a dummy one in fallback */
956 bo_add_fourcc(smi, "SEQH");
957 bo_add_32be(smi, 0x5);
958 bo_add_32be(smi, 0xe2c0211d);
959 bo_add_8(smi, 0xc0);
961 return smi;
964 static bo_t *GetUdtaTag(mp4mux_handle_t *muxh)
966 bo_t *udta = box_new("udta");
967 if (!udta)
968 return NULL;
970 /* Requirements */
971 for (unsigned int i = 0; i < vlc_array_count(&muxh->tracks); i++) {
972 mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&muxh->tracks, i);
973 vlc_fourcc_t codec = p_stream->fmt.i_codec;
975 if (codec == VLC_CODEC_MP4V || codec == VLC_CODEC_MP4A) {
976 bo_t *box = box_new("\251req");
977 if(!box)
978 break;
979 /* String length */
980 bo_add_16be(box, sizeof("QuickTime 6.0 or greater") - 1);
981 bo_add_16be(box, 0);
982 bo_add_mem(box, sizeof("QuickTime 6.0 or greater") - 1,
983 (uint8_t *)"QuickTime 6.0 or greater");
984 box_gather(udta, box);
985 break;
989 /* Encoder */
991 bo_t *box = box_new("\251enc");
992 if(box)
994 /* String length */
995 bo_add_16be(box, sizeof(PACKAGE_STRING " stream output") - 1);
996 bo_add_16be(box, 0);
997 bo_add_mem(box, sizeof(PACKAGE_STRING " stream output") - 1,
998 (uint8_t*)PACKAGE_STRING " stream output");
999 box_gather(udta, box);
1002 #if 0
1003 /* Misc atoms */
1004 vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
1005 if (p_meta) {
1006 #define ADD_META_BOX(type, box_string) { \
1007 bo_t *box = NULL; \
1008 if (vlc_meta_Get(p_meta, vlc_meta_##type)) \
1009 box = box_new("\251" box_string); \
1010 if (box) { \
1011 bo_add_16be(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type))); \
1012 bo_add_16be(box, 0); \
1013 bo_add_mem(box, strlen(vlc_meta_Get(p_meta, vlc_meta_##type)), \
1014 (uint8_t*)(vlc_meta_Get(p_meta, vlc_meta_##type))); \
1015 box_gather(udta, box); \
1018 ADD_META_BOX(Title, "nam");
1019 ADD_META_BOX(Artist, "ART");
1020 ADD_META_BOX(Genre, "gen");
1021 ADD_META_BOX(Copyright, "cpy");
1022 ADD_META_BOX(Description, "des");
1023 ADD_META_BOX(Date, "day");
1024 ADD_META_BOX(URL, "url");
1025 #undef ADD_META_BOX
1027 #endif
1028 return udta;
1031 static bo_t *GetSounBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b_mov)
1033 VLC_UNUSED(p_obj);
1035 bool b_descr = true;
1036 vlc_fourcc_t codec = p_track->fmt.i_codec;
1037 char fcc[4];
1039 if (codec == VLC_CODEC_MPGA) {
1040 if (b_mov) {
1041 b_descr = false;
1042 memcpy(fcc, ".mp3", 4);
1043 } else
1044 memcpy(fcc, "mp4a", 4);
1045 } else if (codec == VLC_CODEC_A52) {
1046 memcpy(fcc, "ac-3", 4);
1047 } else if (codec == VLC_CODEC_EAC3) {
1048 memcpy(fcc, "ec-3", 4);
1049 } else if (codec == VLC_CODEC_DTS) {
1050 memcpy(fcc, "DTS ", 4);
1051 } else if (codec == VLC_CODEC_WMAP) {
1052 memcpy(fcc, "wma ", 4);
1053 } else
1054 vlc_fourcc_to_char(codec, fcc);
1056 bo_t *soun = box_new(fcc);
1057 if(!soun)
1058 return NULL;
1059 for (int i = 0; i < 6; i++)
1060 bo_add_8(soun, 0); // reserved;
1061 bo_add_16be(soun, 1); // data-reference-index
1063 /* SoundDescription */
1064 if (b_mov && codec == VLC_CODEC_MP4A)
1065 bo_add_16be(soun, 1); // version 1;
1066 else
1067 bo_add_16be(soun, 0); // version 0;
1068 bo_add_16be(soun, 0); // revision level (0)
1069 bo_add_32be(soun, 0); // vendor
1070 // channel-count
1071 bo_add_16be(soun, p_track->fmt.audio.i_channels);
1072 // sample size
1073 bo_add_16be(soun, p_track->fmt.audio.i_bitspersample ?
1074 p_track->fmt.audio.i_bitspersample : 16);
1075 bo_add_16be(soun, -2); // compression id
1076 bo_add_16be(soun, 0); // packet size (0)
1077 bo_add_16be(soun, p_track->fmt.audio.i_rate); // sampleratehi
1078 bo_add_16be(soun, 0); // sampleratelo
1080 /* Extended data for SoundDescription V1 */
1081 if (b_mov && p_track->fmt.i_codec == VLC_CODEC_MP4A) {
1082 /* samples per packet */
1083 bo_add_32be(soun, p_track->fmt.audio.i_frame_length);
1084 bo_add_32be(soun, 1536); /* bytes per packet */
1085 bo_add_32be(soun, 2); /* bytes per frame */
1086 /* bytes per sample */
1087 bo_add_32be(soun, 2 /*p_fmt->audio.i_bitspersample/8 */);
1090 /* Add an ES Descriptor */
1091 if (b_descr) {
1092 bo_t *box;
1094 /* codec specific extradata */
1095 const uint8_t *p_extradata = p_track->fmt.p_extra;
1096 size_t i_extradata = p_track->fmt.i_extra;
1097 if(p_track->sample_priv.i_data)
1099 p_extradata = p_track->sample_priv.p_data;
1100 i_extradata = p_track->sample_priv.i_data;
1103 if (b_mov && codec == VLC_CODEC_MP4A)
1104 box = GetWaveTag(p_track);
1105 else if (codec == VLC_CODEC_AMR_NB)
1106 box = GetDamrTag(&p_track->fmt);
1107 else if (codec == VLC_CODEC_A52 && i_extradata >= 3)
1108 box = GetxxxxTag(p_extradata, i_extradata, "dac3");
1109 else if (codec == VLC_CODEC_EAC3 && i_extradata >= 5)
1110 box = GetxxxxTag(p_extradata, i_extradata, "dec3");
1111 else if (codec == VLC_CODEC_WMAP)
1112 box = GetWaveFormatExTag(&p_track->fmt, "wfex");
1113 else
1114 box = GetESDS(p_track);
1116 if (box)
1117 box_gather(soun, box);
1120 return soun;
1123 static bo_t *GetVideBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b_mov)
1125 VLC_UNUSED(p_obj);
1126 VLC_UNUSED(b_mov);
1128 char fcc[4];
1130 switch(p_track->fmt.i_codec)
1132 case VLC_CODEC_MP4V:
1133 case VLC_CODEC_MPGV: memcpy(fcc, "mp4v", 4); break;
1134 case VLC_CODEC_MJPG: memcpy(fcc, "mjpa", 4); break;
1135 case VLC_CODEC_SVQ1: memcpy(fcc, "SVQ1", 4); break;
1136 case VLC_CODEC_SVQ3: memcpy(fcc, "SVQ3", 4); break;
1137 case VLC_CODEC_H263: memcpy(fcc, "s263", 4); break;
1138 case VLC_CODEC_H264: memcpy(fcc, "avc1", 4); break;
1139 case VLC_CODEC_VC1 : memcpy(fcc, "vc-1", 4); break;
1140 /* FIXME: find a way to know if no non-VCL units are in the stream (->hvc1)
1141 * see 14496-15 8.4.1.1.1 */
1142 case VLC_CODEC_HEVC: memcpy(fcc, "hev1", 4); break;
1143 case VLC_CODEC_YV12: memcpy(fcc, "yv12", 4); break;
1144 case VLC_CODEC_YUYV: memcpy(fcc, "yuy2", 4); break;
1145 default:
1146 vlc_fourcc_to_char(p_track->fmt.i_codec, fcc);
1147 break;
1150 bo_t *vide = box_new(fcc);
1151 if(!vide)
1152 return NULL;
1153 for (int i = 0; i < 6; i++)
1154 bo_add_8(vide, 0); // reserved;
1155 bo_add_16be(vide, 1); // data-reference-index
1157 bo_add_16be(vide, 0); // predefined;
1158 bo_add_16be(vide, 0); // reserved;
1159 for (int i = 0; i < 3; i++)
1160 bo_add_32be(vide, 0); // predefined;
1162 bo_add_16be(vide, p_track->fmt.video.i_width); // i_width
1163 bo_add_16be(vide, p_track->fmt.video.i_height); // i_height
1165 bo_add_32be(vide, 0x00480000); // h 72dpi
1166 bo_add_32be(vide, 0x00480000); // v 72dpi
1168 bo_add_32be(vide, 0); // data size, always 0
1169 bo_add_16be(vide, 1); // frames count per sample
1171 // compressor name;
1172 uint8_t compressor_name[32] = {0};
1173 switch (p_track->fmt.i_codec)
1175 case VLC_CODEC_AV1:
1176 memcpy(compressor_name, "\012AOM Coding", 11);
1177 break;
1178 default:
1179 break;
1181 bo_add_mem(vide, 32, compressor_name);
1183 bo_add_16be(vide, 0x18); // depth
1184 bo_add_16be(vide, 0xffff); // predefined
1186 /* codec specific extradata */
1187 const uint8_t *p_extradata = p_track->fmt.p_extra;
1188 size_t i_extradata = p_track->fmt.i_extra;
1189 if(p_track->sample_priv.i_data)
1191 p_extradata = p_track->sample_priv.p_data;
1192 i_extradata = p_track->sample_priv.i_data;
1195 /* add an ES Descriptor */
1196 switch(p_track->fmt.i_codec)
1198 case VLC_CODEC_AV1:
1199 box_gather(vide, GetxxxxTag(p_extradata, i_extradata, "av1C"));
1200 box_gather(vide, GetColrBox(&p_track->fmt.video, b_mov));
1201 box_gather(vide, GetMdcv(&p_track->fmt.video));
1202 box_gather(vide, GetClli(&p_track->fmt.video));
1203 break;
1205 case VLC_CODEC_MP4V:
1206 case VLC_CODEC_MPGV:
1207 box_gather(vide, GetESDS(p_track));
1208 break;
1210 case VLC_CODEC_H263:
1211 box_gather(vide, GetD263Tag());
1212 break;
1214 case VLC_CODEC_SVQ3:
1215 box_gather(vide, GetSVQ3Tag(p_extradata, i_extradata));
1216 break;
1218 case VLC_CODEC_H264:
1219 box_gather(vide, GetAvcCTag(p_extradata, i_extradata));
1220 break;
1222 case VLC_CODEC_VC1:
1223 box_gather(vide, GetxxxxTag(p_extradata, i_extradata, "dvc1"));
1224 break;
1226 case VLC_CODEC_HEVC:
1227 /* Write HvcC without forcing VPS/SPS/PPS/SEI array_completeness */
1228 box_gather(vide, GetHvcCTag(p_extradata, i_extradata, false));
1229 break;
1232 return vide;
1235 static bo_t *GetTextBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b_mov)
1237 VLC_UNUSED(p_obj);
1238 if(p_track->fmt.i_codec == VLC_CODEC_QTXT)
1240 bo_t *text = box_new("text");
1241 if(!text)
1242 return NULL;
1244 /* Sample Entry Header */
1245 for (int i = 0; i < 6; i++)
1246 bo_add_8(text, 0); // reserved;
1247 bo_add_16be(text, 1); // data-reference-index
1249 if(p_track->fmt.i_extra >= 44)
1251 /* Copy the original sample description format */
1252 bo_add_mem(text, p_track->fmt.i_extra, p_track->fmt.p_extra);
1254 else
1256 for (int i = 0; i < 6; i++)
1257 bo_add_8(text, 0); // reserved;
1258 bo_add_16be(text, 1); // data-reference-index
1260 bo_add_32be(text, 0); // display flags
1261 bo_add_32be(text, 0); // justification
1262 for (int i = 0; i < 3; i++)
1263 bo_add_16be(text, 0); // background color
1265 bo_add_64be(text, 0); // box text
1266 bo_add_64be(text, 0); // reserved
1268 bo_add_16be(text, 0); // font-number
1269 bo_add_16be(text, 0); // font-face
1270 bo_add_8(text, 0); // reserved
1271 bo_add_16be(text, 0); // reserved
1273 for (int i = 0; i < 3; i++)
1274 bo_add_16be(text, 0xff); // foreground color
1276 bo_add_8(text, 5);
1277 bo_add_mem(text, 5, (void*)"Serif");
1279 return text;
1281 else if(p_track->fmt.i_codec == VLC_CODEC_SPU ||
1282 p_track->fmt.i_codec == VLC_CODEC_TX3G)
1284 bo_t *tx3g = box_new("tx3g");
1285 if(!tx3g)
1286 return NULL;
1288 /* Sample Entry Header */
1289 for (int i = 0; i < 6; i++)
1290 bo_add_8(tx3g, 0); // reserved;
1291 bo_add_16be(tx3g, 1); // data-reference-index
1293 if(p_track->fmt.i_codec == VLC_CODEC_TX3G &&
1294 p_track->fmt.i_extra >= 32)
1296 /* Copy the original sample description format */
1297 bo_add_mem(tx3g, p_track->fmt.i_extra, p_track->fmt.p_extra);
1299 else /* Build TTXT(tx3g) sample desc */
1301 /* tx3g sample description */
1302 bo_add_32be(tx3g, 0); // display flags
1303 bo_add_16be(tx3g, 0); // justification
1305 bo_add_32be(tx3g, 0); // background color
1307 /* BoxRecord */
1308 bo_add_64be(tx3g, 0);
1310 /* StyleRecord*/
1311 bo_add_16be(tx3g, 0); // startChar
1312 bo_add_16be(tx3g, 0); // endChar
1313 bo_add_16be(tx3g, 0); // default font ID
1314 bo_add_8(tx3g, 0); // face style flags
1315 bo_add_8(tx3g, STYLE_DEFAULT_FONT_SIZE); // font size
1316 bo_add_32be(tx3g, 0xFFFFFFFFU);// foreground color
1318 /* FontTableBox */
1319 bo_t *ftab = box_new("ftab");
1320 if(ftab)
1322 bo_add_16be(ftab, b_mov ? 2 : 3); // Entry Count
1323 /* Font Record */
1324 bo_add_8(ftab, 5);
1325 bo_add_mem(ftab, 5, (void*)"Serif");
1326 bo_add_8(ftab, 10);
1327 bo_add_mem(ftab, 10, (void*) (b_mov ? "Sans-Serif" : "Sans-serif"));
1328 if(!b_mov) /* qt only allows "Serif" and "Sans-Serif" */
1330 bo_add_8(ftab, 9);
1331 bo_add_mem(ftab, 9, (void*)"Monospace");
1334 box_gather(tx3g, ftab);
1338 return tx3g;
1340 else if(p_track->fmt.i_codec == VLC_CODEC_WEBVTT)
1342 bo_t *wvtt = box_new("wvtt");
1343 if(!wvtt)
1344 return NULL;
1346 /* Sample Entry Header */
1347 for (int i = 0; i < 6; i++)
1348 bo_add_8(wvtt, 0); // reserved;
1349 bo_add_16be(wvtt, 1); // data-reference-index
1351 bo_t *ftab = box_new("vttc");
1352 box_gather(wvtt, ftab);
1354 return wvtt;
1356 else if(p_track->fmt.i_codec == VLC_CODEC_TTML)
1358 bo_t *stpp = box_new("stpp");
1359 if(!stpp)
1360 return NULL;
1362 /* Sample Entry Header */
1363 for (int i = 0; i < 6; i++)
1364 bo_add_8(stpp, 0); // reserved;
1365 bo_add_16be(stpp, 1); // data-reference-index
1367 return stpp;
1370 return NULL;
1373 static int64_t GetScaledEntryDuration( const mp4mux_sample_t *p_entry, uint32_t i_timescale,
1374 vlc_tick_t *pi_total_mtime, int64_t *pi_total_scaled )
1376 const vlc_tick_t i_totalscaledtototalmtime = vlc_tick_from_samples(*pi_total_scaled, i_timescale);
1377 const vlc_tick_t i_diff = *pi_total_mtime - i_totalscaledtototalmtime;
1379 /* Ensure to compensate the drift due to loss from time, and from scale, conversions */
1380 int64_t i_scaled = samples_from_vlc_tick(p_entry->i_length + i_diff, i_timescale);
1381 *pi_total_mtime += p_entry->i_length;
1382 *pi_total_scaled += i_scaled;
1384 return i_scaled;
1387 static bo_t *GetStblBox(vlc_object_t *p_obj, mp4mux_trackinfo_t *p_track, bool b_mov, bool b_stco64)
1389 /* sample description */
1390 bo_t *stsd = box_full_new("stsd", 0, 0);
1391 if(!stsd)
1392 return NULL;
1393 bo_add_32be(stsd, 1);
1394 if (p_track->fmt.i_cat == AUDIO_ES)
1395 box_gather(stsd, GetSounBox(p_obj, p_track, b_mov));
1396 else if (p_track->fmt.i_cat == VIDEO_ES)
1397 box_gather(stsd, GetVideBox(p_obj, p_track, b_mov));
1398 else if (p_track->fmt.i_cat == SPU_ES)
1399 box_gather(stsd, GetTextBox(p_obj, p_track, b_mov));
1401 /* chunk offset table */
1402 bo_t *stco;
1404 if (b_stco64) {
1405 /* 64 bits version */
1406 stco = box_full_new("co64", 0, 0);
1407 } else {
1408 /* 32 bits version */
1409 stco = box_full_new("stco", 0, 0);
1411 if(!stco)
1413 bo_free(stsd);
1414 return NULL;
1416 bo_add_32be(stco, 0); // entry-count (fixed latter)
1418 /* sample to chunk table */
1419 bo_t *stsc = box_full_new("stsc", 0, 0);
1420 if(!stsc)
1422 bo_free(stco);
1423 bo_free(stsd);
1424 return NULL;
1426 bo_add_32be(stsc, 0); // entry-count (fixed latter)
1428 unsigned i_chunk = 0;
1429 unsigned i_stsc_last_val = 0, i_stsc_entries = 0;
1430 for (unsigned i = 0; i < p_track->i_samples_count; i_chunk++) {
1431 mp4mux_sample_t *entry = p_track->samples;
1432 int i_first = i;
1434 if (b_stco64)
1435 bo_add_64be(stco, entry[i].i_pos);
1436 else
1437 bo_add_32be(stco, entry[i].i_pos);
1439 for (; i < p_track->i_samples_count; i++)
1440 if (i >= p_track->i_samples_count - 1 ||
1441 entry[i].i_pos + entry[i].i_size != entry[i+1].i_pos) {
1442 i++;
1443 break;
1446 /* Add entry to the stsc table */
1447 if (i_stsc_last_val != i - i_first) {
1448 bo_add_32be(stsc, 1 + i_chunk); // first-chunk
1449 bo_add_32be(stsc, i - i_first) ; // samples-per-chunk
1450 bo_add_32be(stsc, 1); // sample-descr-index
1451 i_stsc_last_val = i - i_first;
1452 i_stsc_entries++;
1456 /* Fix stco entry count */
1457 bo_swap_32be(stco, 12, i_chunk);
1458 if(p_obj)
1459 msg_Dbg(p_obj, "created %d chunks (stco)", i_chunk);
1461 /* Fix stsc entry count */
1462 bo_swap_32be(stsc, 12, i_stsc_entries );
1464 /* add stts */
1465 bo_t *stts = box_full_new("stts", 0, 0);
1466 if(!stts)
1468 bo_free(stsd);
1469 bo_free(stco);
1470 bo_free(stsc);
1471 return NULL;
1473 bo_add_32be(stts, 0); // entry-count (fixed latter)
1475 vlc_tick_t i_total_mtime = 0;
1476 int64_t i_total_scaled = 0;
1477 unsigned i_index = 0;
1478 for (unsigned i = 0; i < p_track->i_samples_count; i_index++) {
1479 int i_first = i;
1481 int64_t i_scaled = GetScaledEntryDuration(&p_track->samples[i], p_track->i_timescale,
1482 &i_total_mtime, &i_total_scaled);
1483 for (unsigned j=i+1; j < p_track->i_samples_count; j++)
1485 vlc_tick_t i_total_mtime_next = i_total_mtime;
1486 int64_t i_total_scaled_next = i_total_scaled;
1487 int64_t i_scalednext = GetScaledEntryDuration(&p_track->samples[j], p_track->i_timescale,
1488 &i_total_mtime_next, &i_total_scaled_next);
1489 if( i_scalednext != i_scaled )
1490 break;
1492 i_total_mtime = i_total_mtime_next;
1493 i_total_scaled = i_total_scaled_next;
1494 i = j;
1497 bo_add_32be(stts, ++i - i_first); // sample-count
1498 bo_add_32be(stts, i_scaled); // sample-delta
1500 bo_swap_32be(stts, 12, i_index);
1502 //msg_Dbg(p_obj, "total sout duration %"PRId64" reconverted from scaled %"PRId64,
1503 // i_total_mtime, vlc_tick_from_samples(i_total_scaled, p_track->i_timescale) );
1505 /* composition time handling */
1506 bo_t *ctts = NULL;
1507 if ( p_track->b_hasbframes && (ctts = box_full_new("ctts", 0, 0)) )
1509 bo_add_32be(ctts, 0);
1510 i_index = 0;
1511 for (unsigned i = 0; i < p_track->i_samples_count; i_index++)
1513 int i_first = i;
1514 vlc_tick_t i_offset = p_track->samples[i].i_pts_dts;
1516 for (; i < p_track->i_samples_count; ++i)
1517 if (i == p_track->i_samples_count || p_track->samples[i].i_pts_dts != i_offset)
1518 break;
1520 bo_add_32be(ctts, i - i_first); // sample-count
1521 bo_add_32be(ctts, samples_from_vlc_tick(i_offset, p_track->i_timescale) ); // sample-offset
1523 bo_swap_32be(ctts, 12, i_index);
1526 bo_t *stsz = box_full_new("stsz", 0, 0);
1527 if(!stsz)
1529 bo_free(stsd);
1530 bo_free(stco);
1531 bo_free(stts);
1532 return NULL;
1534 int i_size = 0;
1535 for (unsigned i = 0; i < p_track->i_samples_count; i++)
1537 if ( i == 0 )
1538 i_size = p_track->samples[i].i_size;
1539 else if ( p_track->samples[i].i_size != i_size )
1541 i_size = 0;
1542 break;
1545 bo_add_32be(stsz, i_size); // sample-size
1546 bo_add_32be(stsz, p_track->i_samples_count); // sample-count
1547 if ( i_size == 0 ) // all samples have different size
1549 for (unsigned i = 0; i < p_track->i_samples_count; i++)
1550 bo_add_32be(stsz, p_track->samples[i].i_size); // sample-size
1553 /* create stss table */
1554 bo_t *stss = NULL;
1555 i_index = 0;
1556 if ( p_track->fmt.i_cat == VIDEO_ES || p_track->fmt.i_cat == AUDIO_ES )
1558 vlc_tick_t i_interval = -1;
1559 for (unsigned i = 0; i < p_track->i_samples_count; i++)
1561 if ( i_interval != -1 )
1563 i_interval += p_track->samples[i].i_length + p_track->samples[i].i_pts_dts;
1564 if ( i_interval < VLC_TICK_FROM_SEC(2) )
1565 continue;
1568 if (p_track->samples[i].i_flags & BLOCK_FLAG_TYPE_I) {
1569 if (stss == NULL) {
1570 stss = box_full_new("stss", 0, 0);
1571 if(!stss)
1572 break;
1573 bo_add_32be(stss, 0); /* fixed later */
1575 bo_add_32be(stss, 1 + i);
1576 i_index++;
1577 i_interval = 0;
1582 if (stss)
1583 bo_swap_32be(stss, 12, i_index);
1585 /* Now gather all boxes into stbl */
1586 bo_t *stbl = box_new("stbl");
1587 if(!stbl)
1589 bo_free(stsd);
1590 bo_free(stco);
1591 bo_free(stts);
1592 bo_free(stsz);
1593 bo_free(stss);
1594 bo_free(ctts);
1595 return NULL;
1597 box_gather(stbl, stsd);
1598 box_gather(stbl, stts);
1599 if (stss)
1600 box_gather(stbl, stss);
1601 if (ctts)
1602 box_gather(stbl, ctts);
1603 box_gather(stbl, stsc);
1604 box_gather(stbl, stsz);
1605 box_gather(stbl, stco);
1607 return stbl;
1610 bo_t * mp4mux_GetMoov(mp4mux_handle_t *h, vlc_object_t *p_obj, vlc_tick_t i_duration)
1612 bo_t *moov, *mvhd;
1614 uint32_t i_movie_timescale = 90000;
1615 int64_t i_timestamp = get_timestamp();
1617 /* Important for smooth streaming where its (not muxed here) media time offsets
1618 * are in timescale == track timescale */
1619 if( vlc_array_count(&h->tracks) == 1 )
1620 i_movie_timescale = ((mp4mux_trackinfo_t *)vlc_array_item_at_index(&h->tracks, 0))->i_timescale;
1622 moov = box_new("moov");
1623 if(!moov)
1624 return NULL;
1625 /* Create general info */
1626 if( i_duration == 0 && (h->options & FRAGMENTED) == 0 )
1628 for (unsigned int i = 0; i < vlc_array_count(&h->tracks); i++) {
1629 mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&h->tracks, 0);
1630 i_duration = __MAX(i_duration, p_stream->i_read_duration);
1632 if(p_obj)
1633 msg_Dbg(p_obj, "movie duration %"PRId64"s", SEC_FROM_VLC_TICK(i_duration));
1635 int64_t i_movie_duration = samples_from_vlc_tick(i_duration, i_movie_timescale);
1637 /* *** add /moov/mvhd *** */
1638 if ((h->options & USE64BITEXT) == 0) {
1639 mvhd = box_full_new("mvhd", 0, 0);
1640 if(!mvhd)
1642 bo_free(moov);
1643 return NULL;
1645 bo_add_32be(mvhd, i_timestamp); // creation time
1646 bo_add_32be(mvhd, i_timestamp); // modification time
1647 bo_add_32be(mvhd, i_movie_timescale); // timescale
1648 bo_add_32be(mvhd, i_movie_duration); // duration
1649 } else {
1650 mvhd = box_full_new("mvhd", 1, 0);
1651 if(!mvhd)
1653 bo_free(moov);
1654 return NULL;
1656 bo_add_64be(mvhd, i_timestamp); // creation time
1657 bo_add_64be(mvhd, i_timestamp); // modification time
1658 bo_add_32be(mvhd, i_movie_timescale); // timescale
1659 bo_add_64be(mvhd, i_movie_duration); // duration
1661 bo_add_32be(mvhd, 0x10000); // rate
1662 bo_add_16be(mvhd, 0x100); // volume
1663 bo_add_16be(mvhd, 0); // reserved
1664 for (int i = 0; i < 2; i++)
1665 bo_add_32be(mvhd, 0); // reserved
1667 uint32_t mvhd_matrix[9] = { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
1669 for (int i = 0; i < 9; i++)
1670 bo_add_32be(mvhd, mvhd_matrix[i]);// matrix
1671 for (int i = 0; i < 6; i++)
1672 bo_add_32be(mvhd, 0); // pre-defined
1674 /* Next available track id */
1675 const mp4mux_trackinfo_t *lasttrack = vlc_array_count(&h->tracks)
1676 ? vlc_array_item_at_index(&h->tracks, vlc_array_count(&h->tracks) - 1)
1677 : NULL;
1678 bo_add_32be(mvhd, lasttrack ? lasttrack->i_track_id + 1: 1); // next-track-id
1680 box_gather(moov, mvhd);
1682 for (unsigned int i_trak = 0; i_trak < vlc_array_count(&h->tracks); i_trak++) {
1683 mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&h->tracks, i_trak);
1685 int64_t i_stream_duration;
1686 if ( (h->options & FRAGMENTED) == 0 )
1687 i_stream_duration = samples_from_vlc_tick(p_stream->i_read_duration, i_movie_timescale);
1688 else
1689 i_stream_duration = 0;
1691 /* *** add /moov/trak *** */
1692 bo_t *trak = box_new("trak");
1693 if(!trak)
1694 continue;
1696 /* *** add /moov/trak/tkhd *** */
1697 bo_t *tkhd;
1698 if ((h->options & USE64BITEXT) == 0) {
1699 if (h->options & QUICKTIME)
1700 tkhd = box_full_new("tkhd", 0, 0x0f);
1701 else
1702 tkhd = box_full_new("tkhd", 0, 1);
1703 if(!tkhd)
1705 bo_free(trak);
1706 continue;
1708 bo_add_32be(tkhd, i_timestamp); // creation time
1709 bo_add_32be(tkhd, i_timestamp); // modification time
1710 bo_add_32be(tkhd, p_stream->i_track_id);
1711 bo_add_32be(tkhd, 0); // reserved 0
1712 bo_add_32be(tkhd, i_stream_duration); // duration
1713 } else {
1714 if (h->options & QUICKTIME)
1715 tkhd = box_full_new("tkhd", 1, 0x0f);
1716 else
1717 tkhd = box_full_new("tkhd", 1, 1);
1718 if(!tkhd)
1720 bo_free(trak);
1721 continue;
1723 bo_add_64be(tkhd, i_timestamp); // creation time
1724 bo_add_64be(tkhd, i_timestamp); // modification time
1725 bo_add_32be(tkhd, p_stream->i_track_id);
1726 bo_add_32be(tkhd, 0); // reserved 0
1727 bo_add_64be(tkhd, i_stream_duration); // duration
1730 for (int i = 0; i < 2; i++)
1731 bo_add_32be(tkhd, 0); // reserved
1732 bo_add_16be(tkhd, 0); // layer
1733 bo_add_16be(tkhd, 0); // pre-defined
1734 // volume
1735 bo_add_16be(tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0);
1736 bo_add_16be(tkhd, 0); // reserved
1737 matrix_apply_rotation(&p_stream->fmt, mvhd_matrix);
1738 for (int i = 0; i < 9; i++)
1739 bo_add_32be(tkhd, mvhd_matrix[i]); // matrix
1740 if (p_stream->fmt.i_cat == AUDIO_ES) {
1741 bo_add_32be(tkhd, 0); // width (presentation)
1742 bo_add_32be(tkhd, 0); // height(presentation)
1743 } else if (p_stream->fmt.i_cat == VIDEO_ES) {
1744 int i_width = p_stream->fmt.video.i_width << 16;
1745 if (p_stream->fmt.video.i_sar_num > 0 && p_stream->fmt.video.i_sar_den > 0) {
1746 i_width = (int64_t)p_stream->fmt.video.i_sar_num *
1747 ((int64_t)p_stream->fmt.video.i_width << 16) /
1748 p_stream->fmt.video.i_sar_den;
1750 // width (presentation)
1751 bo_add_32be(tkhd, i_width);
1752 // height(presentation)
1753 bo_add_32be(tkhd, p_stream->fmt.video.i_height << 16);
1754 } else {
1755 int i_width = 320 << 16;
1756 int i_height = 200;
1757 for (unsigned int i = 0; i < vlc_array_count(&h->tracks); i++) {
1758 const mp4mux_trackinfo_t *tk = vlc_array_item_at_index(&h->tracks, i);
1759 if (tk->fmt.i_cat == VIDEO_ES) {
1760 if (tk->fmt.video.i_sar_num > 0 &&
1761 tk->fmt.video.i_sar_den > 0)
1762 i_width = (int64_t)tk->fmt.video.i_sar_num *
1763 ((int64_t)tk->fmt.video.i_width << 16) /
1764 tk->fmt.video.i_sar_den;
1765 else
1766 i_width = tk->fmt.video.i_width << 16;
1767 i_height = tk->fmt.video.i_height;
1768 break;
1771 bo_add_32be(tkhd, i_width); // width (presentation)
1772 bo_add_32be(tkhd, i_height << 16); // height(presentation)
1775 box_gather(trak, tkhd);
1777 /* *** add /moov/trak/edts and elst */
1778 bo_t *edts = GetEDTS(p_stream, i_movie_timescale, h->options & USE64BITEXT);
1779 if(edts)
1780 box_gather(trak, edts);
1782 /* *** add /moov/trak/mdia *** */
1783 bo_t *mdia = box_new("mdia");
1784 if(!mdia)
1786 bo_free(trak);
1787 continue;
1790 /* media header */
1791 bo_t *mdhd;
1792 if ((h->options & USE64BITEXT) == 0) {
1793 mdhd = box_full_new("mdhd", 0, 0);
1794 if(!mdhd)
1796 bo_free(mdia);
1797 bo_free(trak);
1798 continue;
1800 bo_add_32be(mdhd, i_timestamp); // creation time
1801 bo_add_32be(mdhd, i_timestamp); // modification time
1802 bo_add_32be(mdhd, p_stream->i_timescale); // timescale
1803 bo_add_32be(mdhd, i_stream_duration * p_stream->i_timescale / i_movie_timescale); // duration
1804 } else {
1805 mdhd = box_full_new("mdhd", 1, 0);
1806 if(!mdhd)
1808 bo_free(mdia);
1809 bo_free(trak);
1810 continue;
1812 bo_add_64be(mdhd, i_timestamp); // creation time
1813 bo_add_64be(mdhd, i_timestamp); // modification time
1814 bo_add_32be(mdhd, p_stream->i_timescale); // timescale
1815 bo_add_64be(mdhd, i_stream_duration * p_stream->i_timescale / i_movie_timescale); // duration
1818 if (p_stream->fmt.psz_language) {
1819 char *psz = p_stream->fmt.psz_language;
1820 const iso639_lang_t *pl = NULL;
1821 uint16_t lang = 0x0;
1823 if (strlen(psz) == 2)
1824 pl = GetLang_1(psz);
1825 else if (strlen(psz) == 3) {
1826 pl = GetLang_2B(psz);
1827 if (!strcmp(pl->psz_iso639_1, "??"))
1828 pl = GetLang_2T(psz);
1831 if (pl && strcmp(pl->psz_iso639_1, "??"))
1832 lang = ((pl->psz_iso639_2T[0] - 0x60) << 10) |
1833 ((pl->psz_iso639_2T[1] - 0x60) << 5) |
1834 ((pl->psz_iso639_2T[2] - 0x60));
1835 bo_add_16be(mdhd, lang); // language
1836 } else
1837 bo_add_16be(mdhd, 0 ); // language
1838 bo_add_16be(mdhd, 0 ); // predefined
1839 box_gather(mdia, mdhd);
1841 /* handler reference */
1842 bo_t *hdlr = box_full_new("hdlr", 0, 0);
1843 if(!hdlr)
1845 bo_free(mdia);
1846 bo_free(trak);
1847 continue;
1850 if (h->options & QUICKTIME)
1851 bo_add_fourcc(hdlr, "mhlr"); // media handler
1852 else
1853 bo_add_32be(hdlr, 0);
1855 if (p_stream->fmt.i_cat == AUDIO_ES)
1856 bo_add_fourcc(hdlr, "soun");
1857 else if (p_stream->fmt.i_cat == VIDEO_ES)
1858 bo_add_fourcc(hdlr, "vide");
1859 else if (p_stream->fmt.i_cat == SPU_ES)
1861 /* text/tx3g 3GPP */
1862 /* sbtl/tx3g Apple subs */
1863 /* text/text Apple textmedia */
1864 if(p_stream->fmt.i_codec == VLC_CODEC_TX3G)
1865 bo_add_fourcc(hdlr, (h->options & QUICKTIME) ? "sbtl" : "text");
1866 else if(p_stream->fmt.i_codec == VLC_CODEC_TTML)
1867 bo_add_fourcc(hdlr, "sbtl");
1868 else
1869 bo_add_fourcc(hdlr, "text");
1872 bo_add_32be(hdlr, 0); // reserved
1873 bo_add_32be(hdlr, 0); // reserved
1874 bo_add_32be(hdlr, 0); // reserved
1876 if (h->options & QUICKTIME)
1877 bo_add_8(hdlr, 12); /* Pascal string for .mov */
1879 if (p_stream->fmt.i_cat == AUDIO_ES)
1880 bo_add_mem(hdlr, 12, (uint8_t*)"SoundHandler");
1881 else if (p_stream->fmt.i_cat == VIDEO_ES)
1882 bo_add_mem(hdlr, 12, (uint8_t*)"VideoHandler");
1883 else
1884 bo_add_mem(hdlr, 12, (uint8_t*)"Text Handler");
1886 if ((h->options & QUICKTIME) == 0)
1887 bo_add_8(hdlr, 0); /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
1889 box_gather(mdia, hdlr);
1891 /* minf*/
1892 bo_t *minf = box_new("minf");
1893 if(!minf)
1895 bo_free(mdia);
1896 bo_free(trak);
1897 continue;
1900 /* add smhd|vmhd */
1901 if (p_stream->fmt.i_cat == AUDIO_ES) {
1902 bo_t *smhd = box_full_new("smhd", 0, 0);
1903 if(smhd)
1905 bo_add_16be(smhd, 0); // balance
1906 bo_add_16be(smhd, 0); // reserved
1908 box_gather(minf, smhd);
1910 } else if (p_stream->fmt.i_cat == VIDEO_ES) {
1911 bo_t *vmhd = box_full_new("vmhd", 0, 1);
1912 if(vmhd)
1914 bo_add_16be(vmhd, 0); // graphicsmode
1915 for (int i = 0; i < 3; i++)
1916 bo_add_16be(vmhd, 0); // opcolor
1917 box_gather(minf, vmhd);
1919 } else if (p_stream->fmt.i_cat == SPU_ES) {
1920 if((h->options & QUICKTIME) &&
1921 (p_stream->fmt.i_codec == VLC_CODEC_SUBT||
1922 p_stream->fmt.i_codec == VLC_CODEC_TX3G||
1923 p_stream->fmt.i_codec == VLC_CODEC_QTXT))
1925 bo_t *gmin = box_full_new("gmin", 0, 1);
1926 if(gmin)
1928 bo_add_16be(gmin, 0); // graphicsmode
1929 for (int i = 0; i < 3; i++)
1930 bo_add_16be(gmin, 0); // opcolor
1931 bo_add_16be(gmin, 0); // balance
1932 bo_add_16be(gmin, 0); // reserved
1934 bo_t *gmhd = box_new("gmhd");
1935 if(gmhd)
1937 box_gather(gmhd, gmin);
1938 box_gather(minf, gmhd);
1940 else bo_free(gmin);
1945 /* dinf */
1946 bo_t *dref = box_full_new("dref", 0, 0);
1947 if(dref)
1949 bo_add_32be(dref, 1);
1951 bo_t *url = box_full_new("url ", 0, 0x01);
1952 if(url)
1953 box_gather(dref, url);
1955 bo_t *dinf = box_new("dinf");
1956 if(dinf)
1958 box_gather(dinf, dref);
1960 /* append dinf to mdia */
1961 box_gather(minf, dinf);
1963 else bo_free(dref);
1966 /* add stbl */
1967 bo_t *stbl;
1968 if (h->options & FRAGMENTED)
1970 uint32_t i_backup = p_stream->i_samples_count;
1971 p_stream->i_samples_count = 0;
1972 stbl = GetStblBox(p_obj, p_stream, h->options & QUICKTIME, h->options & USE64BITEXT);
1973 p_stream->i_samples_count = i_backup;
1975 else
1976 stbl = GetStblBox(p_obj, p_stream, h->options & QUICKTIME, h->options & USE64BITEXT);
1978 /* append stbl to minf */
1979 box_gather(minf, stbl);
1981 /* append minf to mdia */
1982 box_gather(mdia, minf);
1984 /* append mdia to trak */
1985 box_gather(trak, mdia);
1987 /* append trak to moov */
1988 box_gather(moov, trak);
1991 /* Add user data tags */
1992 box_gather(moov, GetUdtaTag(h));
1994 if ( h->options & FRAGMENTED )
1996 bo_t *mvex = box_new("mvex");
1997 if( mvex )
1999 if( i_movie_duration )
2001 bo_t *mehd = box_full_new("mehd", (h->options & USE64BITEXT) ? 1 : 0, 0);
2002 if(mehd)
2004 if((h->options & USE64BITEXT))
2005 bo_add_64be(mehd, i_movie_duration);
2006 else
2007 bo_add_32be(mehd, i_movie_duration);
2008 box_gather(mvex, mehd);
2012 for (unsigned int i = 0; mvex && i < vlc_array_count(&h->tracks); i++)
2014 mp4mux_trackinfo_t *p_stream = vlc_array_item_at_index(&h->tracks, i);
2016 /* Try to find some defaults */
2017 if ( p_stream->i_samples_count )
2019 // FIXME: find highest occurence
2020 p_stream->i_trex_default_length = p_stream->samples[0].i_length;
2021 p_stream->i_trex_default_size = p_stream->samples[0].i_size;
2023 else
2025 p_stream->i_trex_default_length = 1;
2026 p_stream->i_trex_default_size = 1;
2029 /* *** add /mvex/trex *** */
2030 bo_t *trex = box_full_new("trex", 0, 0);
2031 bo_add_32be(trex, p_stream->i_track_id);
2032 bo_add_32be(trex, 1); // sample desc index
2033 bo_add_32be(trex, samples_from_vlc_tick(p_stream->i_trex_default_length, p_stream->i_timescale)); // sample duration
2034 bo_add_32be(trex, p_stream->i_trex_default_size); // sample size
2035 bo_add_32be(trex, 0); // sample flags
2036 box_gather(mvex, trex);
2038 box_gather(moov, mvex);
2042 if(moov->b)
2043 box_fix(moov, bo_size(moov));
2044 return moov;
2047 bo_t *mp4mux_GetFtyp(const mp4mux_handle_t *h)
2049 bo_t *box = box_new("ftyp");
2050 if(box)
2052 bo_add_fourcc(box, &h->brands.i_major);
2053 bo_add_32be (box, h->brands.i_minor);
2054 for(int i=0; i<h->brands.extra.i_size; i++)
2055 bo_add_fourcc(box, &h->brands.extra.p_elems[i]);
2056 if(!box->b)
2058 free(box);
2059 return NULL;
2061 box_fix(box, bo_size(box));
2063 return box;
2066 bool mp4mux_CanMux(vlc_object_t *p_obj, const es_format_t *p_fmt,
2067 vlc_fourcc_t i_brand, bool b_fragmented)
2069 switch(p_fmt->i_codec)
2071 case VLC_CODEC_A52:
2072 case VLC_CODEC_DTS:
2073 case VLC_CODEC_EAC3:
2074 case VLC_CODEC_MP4A:
2075 case VLC_CODEC_MP4V:
2076 case VLC_CODEC_MPGA:
2077 case VLC_CODEC_MP3:
2078 case VLC_CODEC_MPGV:
2079 case VLC_CODEC_MP2V:
2080 case VLC_CODEC_MP1V:
2081 case VLC_CODEC_MJPG:
2082 case VLC_CODEC_MJPGB:
2083 case VLC_CODEC_SVQ1:
2084 case VLC_CODEC_SVQ3:
2085 case VLC_CODEC_H263:
2086 case VLC_CODEC_AMR_NB:
2087 case VLC_CODEC_AMR_WB:
2088 case VLC_CODEC_YV12:
2089 case VLC_CODEC_YUYV:
2090 case VLC_CODEC_VC1:
2091 case VLC_CODEC_WMAP:
2092 case VLC_CODEC_AV1:
2093 break;
2094 case VLC_CODEC_H264:
2095 if(!p_fmt->i_extra && p_obj)
2096 msg_Warn(p_obj, "H264 muxing from AnnexB source will set an incorrect default profile");
2097 break;
2098 case VLC_CODEC_HEVC:
2099 if(!p_fmt->i_extra)
2101 if(p_obj)
2102 msg_Err(p_obj, "HEVC muxing from AnnexB source is unsupported");
2103 return false;
2105 break;
2106 case VLC_CODEC_SUBT:
2107 if(p_obj)
2108 msg_Warn(p_obj, "subtitle track added like in .mov (even when creating .mp4)");
2109 return !b_fragmented;
2110 case VLC_CODEC_TTML:
2111 /* Special case with smooth headers where we need to force frag TTML */
2112 /* TTML currently not supported in sout, until we can keep original timestamps */
2113 return i_brand == BRAND_smoo;
2114 case VLC_CODEC_QTXT:
2115 case VLC_CODEC_TX3G:
2116 case VLC_CODEC_WEBVTT:
2117 return !b_fragmented;
2118 default:
2119 return false;
2121 return true;