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 *****************************************************************************/
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"
35 #include <vlc_iso_lang.h>
37 #include <vlc_arrays.h>
38 #include <vlc_text_style.h>
42 struct mp4mux_trackinfo_t
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 */
60 vlc_tick_t i_read_duration
;
65 vlc_tick_t i_trex_default_length
;
66 uint32_t i_trex_default_size
;
69 unsigned int i_edits_count
;
70 mp4mux_edit_t
*p_edits
;
74 struct mp4mux_handle_t
82 DECL_ARRAY(vlc_fourcc_t
) extra
;
86 static void mp4mux_AddExtraBrandForFormat(mp4mux_handle_t
*h
, const es_format_t
*fmt
)
91 mp4mux_AddExtraBrand(h
, BRAND_avc1
);
94 mp4mux_AddExtraBrand(h
, BRAND_hevc
);
97 mp4mux_AddExtraBrand(h
, BRAND_av01
);
98 mp4mux_AddExtraBrand(h
, BRAND_iso6
);
105 mp4mux_AddExtraBrand(h
, BRAND_mp41
);
108 mp4mux_AddExtraBrand(h
, BRAND_mp41
);
109 if(vlc_array_count(&h
->tracks
) == 1)
110 mp4mux_AddExtraBrand(h
, BRAND_M4A
);
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);
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))
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
);
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
))
162 t
->p_edits
= p_realloc
;
163 t
->p_edits
[t
->i_edits_count
++] = *p_newedit
;
168 const mp4mux_edit_t
*mp4mux_track_GetLastEdit(const mp4mux_trackinfo_t
*t
)
171 return &t
->p_edits
[t
->i_edits_count
- 1];
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
,
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));
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
);
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];
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
;
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
)
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;
287 t
->sample_priv
.p_data
= malloc(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
;
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
);
333 vlc_array_clear(&h
->tracks
);
334 ARRAY_RESET(h
->brands
.extra
);
338 void mp4mux_Set64BitExt(mp4mux_handle_t
*h
)
341 * Quicktime actually doesn't like the 64 bits extensions !!! */
342 if(h
->options
& QUICKTIME
)
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
)
365 ARRAY_APPEND(h
->brands
.extra
, b
);
368 bo_t
*box_new(const char *fcc
)
370 bo_t
*box
= malloc(sizeof(*box
));
374 if(!bo_init(box
, 1024))
380 bo_add_32be (box
, 0);
381 bo_add_fourcc(box
, fcc
);
386 bo_t
*box_full_new(const char *fcc
, uint8_t v
, uint32_t f
)
388 bo_t
*box
= box_new(fcc
);
393 bo_add_24be (box
, f
);
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
);
411 memcpy(&box
->b
->p_buffer
[i_offset
], box2
->b
->p_buffer
, box2
->b
->i_buffer
);
416 static inline void bo_add_mp4_tag_descr(bo_t
*box
, uint8_t tag
, uint32_t size
)
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
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
;
444 mvhd_matrix[1] = ((uint32_t)(a)) << 16; \
445 mvhd_matrix[0] = ((uint32_t)(b)) << 16; \
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
,
466 bo_add_64be(elst
, i_movie_scaled_duration
);
467 bo_add_64be(elst
, i_media_scaled_time
);
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)
483 bo_t
*edts
= box_new("edts");
484 bo_t
*elst
= box_full_new("elst", b_64_ext
? 1 : 0, 0);
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)
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)
507 samples_from_vlc_tick(p_track
->p_edits
[i
].i_start_offset
, i_movietimescale
),
512 /* !WARN AGAIN! Uses different Timescales ! */
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
),
519 box_gather(edts
, elst
);
523 static bo_t
*GetESDS(mp4mux_trackinfo_t
*p_track
)
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);
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
;
551 if (i_bitrate_max
<= 1)
552 i_bitrate_max
= 0x7fffffff;
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
)
566 i_object_type_indication
= 0x20;
569 if(p_track
->fmt
.i_original_fourcc
== VLC_CODEC_MP1V
)
571 i_object_type_indication
= 0x6b;
576 /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
577 i_object_type_indication
= 0x65;
580 /* MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
581 i_object_type_indication
= 0x6b;
584 /* FIXME for mpeg2-aac == 0x66->0x68 */
585 i_object_type_indication
= 0x40;
588 i_object_type_indication
=
589 p_track
->fmt
.audio
.i_rate
< 32000 ? 0x69 : 0x6b;
592 i_object_type_indication
= 0xa9;
595 i_object_type_indication
= 0xFE; /* No profile specified */
599 uint8_t i_stream_type
;
600 switch(p_track
->fmt
.i_cat
)
603 i_stream_type
= 0x04;
606 i_stream_type
= 0x05;
609 i_stream_type
= 0x0D;
612 i_stream_type
= 0x20; /* Private */
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
637 static bo_t
*GetWaveTag(mp4mux_trackinfo_t
*p_track
)
642 wave
= box_new("wave");
645 box
= box_new("frma");
648 bo_add_fourcc(box
, "mp4a");
649 box_gather(wave
, box
);
652 box
= box_new("mp4a");
656 box_gather(wave
, box
);
659 box
= GetESDS(p_track
);
660 box_gather(wave
, box
);
662 box
= box_new("srcq");
665 bo_add_32be(box
, 0x40);
666 box_gather(wave
, box
);
670 bo_add_32be(wave
, 8); /* new empty box */
671 bo_add_32be(wave
, 0); /* box label */
676 static bo_t
*GetDamrTag(es_format_t
*p_fmt
)
678 bo_t
*damr
= box_new("damr");
682 bo_add_fourcc(damr
, "REFC");
685 if (p_fmt
->i_codec
== VLC_CODEC_AMR_NB
)
686 bo_add_16be(damr
, 0x81ff); /* Mode set (all modes for AMR_NB) */
688 bo_add_16be(damr
, 0x83ff); /* Mode set (all modes for AMR_WB) */
689 bo_add_16be(damr
, 0x1); /* Mode change period (no restriction) */
694 static bo_t
*GetD263Tag(void)
696 bo_t
*d263
= box_new("d263");
700 bo_add_fourcc(d263
, "VLC ");
701 bo_add_16be(d263
, 0xa);
707 static bo_t
*GetHvcCTag(const uint8_t *p_extra
, size_t i_extra
,
711 /* Generate hvcC box matching iso/iec 14496-15 3rd edition */
712 bo_t
*hvcC
= box_new("hvcC");
713 if(!hvcC
|| !i_extra
)
716 /* Extradata is already an HEVCDecoderConfigurationRecord */
717 if(hevc_ishvcC(p_extra
, i_extra
))
719 (void) bo_add_mem(hvcC
, i_extra
, p_extra
);
723 struct hevc_dcr_params params
= { 0 };
724 const uint8_t *p_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
))
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
++;
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
++;
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
++;
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
++;
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
++;
780 uint8_t *p_dcr
= hevc_create_dcr(¶ms
, 4, b_completeness
, &i_dcr
);
787 bo_add_mem(hvcC
, i_dcr
, p_dcr
);
793 static bo_t
*GetWaveFormatExTag(es_format_t
*p_fmt
, const char *tag
)
795 bo_t
*box
= box_new(tag
);
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
);
814 static bo_t
*GetxxxxTag(const uint8_t *p_extra
, size_t i_extra
,
817 bo_t
*box
= box_new(tag
);
820 bo_add_mem(box
, i_extra
, p_extra
);
824 static bo_t
*GetColrBox(const video_format_t
*p_vfmt
, bool b_mov
)
826 bo_t
*p_box
= box_new("colr");
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);
838 static bo_t
*GetMdcv(const video_format_t
*p_vfmt
)
840 if(!p_vfmt
->mastering
.max_luminance
)
842 bo_t
*p_box
= box_new("mdcv");
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
);
855 static bo_t
*GetClli(const video_format_t
*p_vfmt
)
857 if(!p_vfmt
->lighting
.MaxFALL
)
859 bo_t
*p_box
= box_new("clli");
862 bo_add_16be(p_box
, p_vfmt
->lighting
.MaxCLL
);
863 bo_add_16be(p_box
, p_vfmt
->lighting
.MaxFALL
);
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 */
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
,
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 );
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
);
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 ");
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 */
947 if (!strncmp((const char *)&p
[4], "SMI ", 4)) {
948 bo_add_mem(smi
, p_end
- p
- 8, &p
[8]);
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);
964 static bo_t
*GetUdtaTag(mp4mux_handle_t
*muxh
)
966 bo_t
*udta
= box_new("udta");
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");
980 bo_add_16be(box
, sizeof("QuickTime 6.0 or greater") - 1);
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
);
991 bo_t
*box
= box_new("\251enc");
995 bo_add_16be(box
, sizeof(PACKAGE_STRING
" stream output") - 1);
997 bo_add_mem(box
, sizeof(PACKAGE_STRING
" stream output") - 1,
998 (uint8_t*)PACKAGE_STRING
" stream output");
999 box_gather(udta
, box
);
1004 vlc_meta_t
*p_meta
= p_mux
->p_sout
->p_meta
;
1006 #define ADD_META_BOX(type, box_string) { \
1008 if (vlc_meta_Get(p_meta, vlc_meta_##type)) \
1009 box = box_new("\251" box_string); \
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");
1031 static bo_t
*GetSounBox(vlc_object_t
*p_obj
, mp4mux_trackinfo_t
*p_track
, bool b_mov
)
1035 bool b_descr
= true;
1036 vlc_fourcc_t codec
= p_track
->fmt
.i_codec
;
1039 if (codec
== VLC_CODEC_MPGA
) {
1042 memcpy(fcc
, ".mp3", 4);
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);
1054 vlc_fourcc_to_char(codec
, fcc
);
1056 bo_t
*soun
= box_new(fcc
);
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;
1067 bo_add_16be(soun
, 0); // version 0;
1068 bo_add_16be(soun
, 0); // revision level (0)
1069 bo_add_32be(soun
, 0); // vendor
1071 bo_add_16be(soun
, p_track
->fmt
.audio
.i_channels
);
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 */
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");
1114 box
= GetESDS(p_track
);
1117 box_gather(soun
, box
);
1123 static bo_t
*GetVideBox(vlc_object_t
*p_obj
, mp4mux_trackinfo_t
*p_track
, bool b_mov
)
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;
1146 vlc_fourcc_to_char(p_track
->fmt
.i_codec
, fcc
);
1150 bo_t
*vide
= box_new(fcc
);
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
1172 uint8_t compressor_name
[32] = {0};
1173 switch (p_track
->fmt
.i_codec
)
1176 memcpy(compressor_name
, "\012AOM Coding", 11);
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
)
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
));
1205 case VLC_CODEC_MP4V
:
1206 case VLC_CODEC_MPGV
:
1207 box_gather(vide
, GetESDS(p_track
));
1210 case VLC_CODEC_H263
:
1211 box_gather(vide
, GetD263Tag());
1214 case VLC_CODEC_SVQ3
:
1215 box_gather(vide
, GetSVQ3Tag(p_extradata
, i_extradata
));
1218 case VLC_CODEC_H264
:
1219 box_gather(vide
, GetAvcCTag(p_extradata
, i_extradata
));
1223 box_gather(vide
, GetxxxxTag(p_extradata
, i_extradata
, "dvc1"));
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));
1235 static bo_t
*GetTextBox(vlc_object_t
*p_obj
, mp4mux_trackinfo_t
*p_track
, bool b_mov
)
1238 if(p_track
->fmt
.i_codec
== VLC_CODEC_QTXT
)
1240 bo_t
*text
= box_new("text");
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
);
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
1277 bo_add_mem(text
, 5, (void*)"Serif");
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");
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
1308 bo_add_64be(tx3g
, 0);
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
1319 bo_t
*ftab
= box_new("ftab");
1322 bo_add_16be(ftab
, b_mov
? 2 : 3); // Entry Count
1325 bo_add_mem(ftab
, 5, (void*)"Serif");
1327 bo_add_mem(ftab
, 10, (void*) (b_mov
? "Sans-Serif" : "Sans-serif"));
1328 if(!b_mov
) /* qt only allows "Serif" and "Sans-Serif" */
1331 bo_add_mem(ftab
, 9, (void*)"Monospace");
1334 box_gather(tx3g
, ftab
);
1340 else if(p_track
->fmt
.i_codec
== VLC_CODEC_WEBVTT
)
1342 bo_t
*wvtt
= box_new("wvtt");
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
);
1356 else if(p_track
->fmt
.i_codec
== VLC_CODEC_TTML
)
1358 bo_t
*stpp
= box_new("stpp");
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
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
;
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);
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 */
1405 /* 64 bits version */
1406 stco
= box_full_new("co64", 0, 0);
1408 /* 32 bits version */
1409 stco
= box_full_new("stco", 0, 0);
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);
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
;
1435 bo_add_64be(stco
, entry
[i
].i_pos
);
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
) {
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
;
1456 /* Fix stco entry count */
1457 bo_swap_32be(stco
, 12, i_chunk
);
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
);
1465 bo_t
*stts
= box_full_new("stts", 0, 0);
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
++) {
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
)
1492 i_total_mtime
= i_total_mtime_next
;
1493 i_total_scaled
= i_total_scaled_next
;
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 */
1507 if ( p_track
->b_hasbframes
&& (ctts
= box_full_new("ctts", 0, 0)) )
1509 bo_add_32be(ctts
, 0);
1511 for (unsigned i
= 0; i
< p_track
->i_samples_count
; i_index
++)
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
)
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);
1535 for (unsigned i
= 0; i
< p_track
->i_samples_count
; i
++)
1538 i_size
= p_track
->samples
[i
].i_size
;
1539 else if ( p_track
->samples
[i
].i_size
!= i_size
)
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 */
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) )
1568 if (p_track
->samples
[i
].i_flags
& BLOCK_FLAG_TYPE_I
) {
1570 stss
= box_full_new("stss", 0, 0);
1573 bo_add_32be(stss
, 0); /* fixed later */
1575 bo_add_32be(stss
, 1 + i
);
1583 bo_swap_32be(stss
, 12, i_index
);
1585 /* Now gather all boxes into stbl */
1586 bo_t
*stbl
= box_new("stbl");
1597 box_gather(stbl
, stsd
);
1598 box_gather(stbl
, stts
);
1600 box_gather(stbl
, stss
);
1602 box_gather(stbl
, ctts
);
1603 box_gather(stbl
, stsc
);
1604 box_gather(stbl
, stsz
);
1605 box_gather(stbl
, stco
);
1610 bo_t
* mp4mux_GetMoov(mp4mux_handle_t
*h
, vlc_object_t
*p_obj
, vlc_tick_t i_duration
)
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");
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
);
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);
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
1650 mvhd
= box_full_new("mvhd", 1, 0);
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)
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
);
1689 i_stream_duration
= 0;
1691 /* *** add /moov/trak *** */
1692 bo_t
*trak
= box_new("trak");
1696 /* *** add /moov/trak/tkhd *** */
1698 if ((h
->options
& USE64BITEXT
) == 0) {
1699 if (h
->options
& QUICKTIME
)
1700 tkhd
= box_full_new("tkhd", 0, 0x0f);
1702 tkhd
= box_full_new("tkhd", 0, 1);
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
1714 if (h
->options
& QUICKTIME
)
1715 tkhd
= box_full_new("tkhd", 1, 0x0f);
1717 tkhd
= box_full_new("tkhd", 1, 1);
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
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);
1755 int i_width
= 320 << 16;
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
;
1766 i_width
= tk
->fmt
.video
.i_width
<< 16;
1767 i_height
= tk
->fmt
.video
.i_height
;
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
);
1780 box_gather(trak
, edts
);
1782 /* *** add /moov/trak/mdia *** */
1783 bo_t
*mdia
= box_new("mdia");
1792 if ((h
->options
& USE64BITEXT
) == 0) {
1793 mdhd
= box_full_new("mdhd", 0, 0);
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
1805 mdhd
= box_full_new("mdhd", 1, 0);
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
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);
1850 if (h
->options
& QUICKTIME
)
1851 bo_add_fourcc(hdlr
, "mhlr"); // media handler
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");
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");
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
);
1892 bo_t
*minf
= box_new("minf");
1901 if (p_stream
->fmt
.i_cat
== AUDIO_ES
) {
1902 bo_t
*smhd
= box_full_new("smhd", 0, 0);
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);
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);
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");
1937 box_gather(gmhd
, gmin
);
1938 box_gather(minf
, gmhd
);
1946 bo_t
*dref
= box_full_new("dref", 0, 0);
1949 bo_add_32be(dref
, 1);
1951 bo_t
*url
= box_full_new("url ", 0, 0x01);
1953 box_gather(dref
, url
);
1955 bo_t
*dinf
= box_new("dinf");
1958 box_gather(dinf
, dref
);
1960 /* append dinf to mdia */
1961 box_gather(minf
, dinf
);
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
;
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");
1999 if( i_movie_duration
)
2001 bo_t
*mehd
= box_full_new("mehd", (h
->options
& USE64BITEXT
) ? 1 : 0, 0);
2004 if((h
->options
& USE64BITEXT
))
2005 bo_add_64be(mehd
, i_movie_duration
);
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
;
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
);
2043 box_fix(moov
, bo_size(moov
));
2047 bo_t
*mp4mux_GetFtyp(const mp4mux_handle_t
*h
)
2049 bo_t
*box
= box_new("ftyp");
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
]);
2061 box_fix(box
, bo_size(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
)
2073 case VLC_CODEC_EAC3
:
2074 case VLC_CODEC_MP4A
:
2075 case VLC_CODEC_MP4V
:
2076 case VLC_CODEC_MPGA
:
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
:
2091 case VLC_CODEC_WMAP
:
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");
2098 case VLC_CODEC_HEVC
:
2102 msg_Err(p_obj
, "HEVC muxing from AnnexB source is unsupported");
2106 case VLC_CODEC_SUBT
:
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
;