3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg 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 GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "config_components.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
35 #include "iamf_writer.h"
41 #include "libavcodec/ac3_parser_internal.h"
42 #include "libavcodec/dnxhddata.h"
43 #include "libavcodec/flac.h"
44 #include "libavcodec/get_bits.h"
46 #include "libavcodec/internal.h"
47 #include "libavcodec/put_bits.h"
48 #include "libavcodec/vc1_common.h"
49 #include "libavcodec/raw.h"
51 #include "libavutil/avstring.h"
52 #include "libavutil/channel_layout.h"
53 #include "libavutil/csp.h"
54 #include "libavutil/intfloat.h"
55 #include "libavutil/mathematics.h"
56 #include "libavutil/libm.h"
57 #include "libavutil/mem.h"
58 #include "libavutil/opt.h"
59 #include "libavutil/dict.h"
60 #include "libavutil/pixdesc.h"
61 #include "libavutil/stereo3d.h"
62 #include "libavutil/timecode.h"
63 #include "libavutil/dovi_meta.h"
64 #include "libavutil/uuid.h"
69 #include "movenc_ttml.h"
77 static const AVOption options
[] = {
78 { "brand", "Override major brand", offsetof(MOVMuxContext
, major_brand
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, .flags
= AV_OPT_FLAG_ENCODING_PARAM
},
79 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext
, empty_hdlr_name
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM
},
80 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext
, encryption_key
), AV_OPT_TYPE_BINARY
, .flags
= AV_OPT_FLAG_ENCODING_PARAM
},
81 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext
, encryption_kid
), AV_OPT_TYPE_BINARY
, .flags
= AV_OPT_FLAG_ENCODING_PARAM
},
82 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext
, encryption_scheme_str
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, .flags
= AV_OPT_FLAG_ENCODING_PARAM
},
83 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext
, max_fragment_duration
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
84 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext
, frag_interleave
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
85 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext
, max_fragment_size
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
86 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext
, fragments
), AV_OPT_TYPE_INT
, {.i64
= 1}, 1, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
87 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext
, iods_audio_profile
), AV_OPT_TYPE_INT
, {.i64
= -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM
},
88 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext
, iods_video_profile
), AV_OPT_TYPE_INT
, {.i64
= -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM
},
89 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext
, ism_lookahead
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM
},
90 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext
, flags
), AV_OPT_TYPE_FLAGS
, {.i64
= 0}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
91 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_CMAF
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
92 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_DASH
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
93 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_DEFAULT_BASE_MOOF
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
94 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_DELAY_MOOV
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
95 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_DISABLE_CHPL
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
96 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_EMPTY_MOOV
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
97 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_FASTSTART
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
98 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_FRAG_CUSTOM
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
99 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_FRAG_DISCONT
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
100 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_FRAG_EVERY_FRAME
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
101 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_FRAG_KEYFRAME
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
102 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_GLOBAL_SIDX
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
103 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_ISML
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
104 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext
, reserved_moov_size
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= 0 },
105 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
106 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_OMIT_TFHD_OFFSET
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
107 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_PREFER_ICC
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
108 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_RTP_HINT
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
109 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_SEPARATE_MOOF
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
110 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_SKIP_SIDX
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
111 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_SKIP_TRAILER
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
112 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_USE_MDTA
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
113 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_WRITE_COLR
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
114 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_WRITE_GAMA
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
115 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST
, {.i64
= FF_MOV_FLAG_HYBRID_FRAGMENTED
}, INT_MIN
, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "movflags" },
116 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext
, min_fragment_duration
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
117 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext
, gamma
), AV_OPT_TYPE_FLOAT
, {.dbl
= 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM
},
118 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext
, movie_timescale
), AV_OPT_TYPE_INT
, {.i64
= MOV_TIMESCALE
}, 1, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
119 FF_RTP_FLAG_OPTS(MOVMuxContext
, rtp_flags
),
120 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext
, iods_skip
), AV_OPT_TYPE_BOOL
, {.i64
= 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM
},
121 { "use_editlist", "use edit list", offsetof(MOVMuxContext
, use_editlist
), AV_OPT_TYPE_BOOL
, {.i64
= -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM
},
122 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext
, use_stream_ids_as_track_ids
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM
},
123 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext
, video_track_timescale
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
124 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext
, write_btrt
), AV_OPT_TYPE_BOOL
, {.i64
= -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM
},
125 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext
, write_prft
), AV_OPT_TYPE_INT
, {.i64
= MOV_PRFT_NONE
}, 0, MOV_PRFT_NB
-1, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "prft"},
126 { "pts", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= MOV_PRFT_SRC_PTS
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "prft"},
127 { "wallclock", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= MOV_PRFT_SRC_WALLCLOCK
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= "prft"},
128 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext
, write_tmcd
), AV_OPT_TYPE_BOOL
, {.i64
= -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM
},
132 static const AVClass mov_isobmff_muxer_class
= {
133 .class_name
= "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
134 .item_name
= av_default_item_name
,
136 .version
= LIBAVUTIL_VERSION_INT
,
139 static int get_moov_size(AVFormatContext
*s
);
140 static int mov_write_single_packet(AVFormatContext
*s
, AVPacket
*pkt
);
142 static int utf8len(const uint8_t *b
)
147 GET_UTF8(val
, *b
++, return -1;)
153 //FIXME support 64 bit variant with wide placeholders
154 static int64_t update_size(AVIOContext
*pb
, int64_t pos
)
156 int64_t curpos
= avio_tell(pb
);
157 avio_seek(pb
, pos
, SEEK_SET
);
158 avio_wb32(pb
, curpos
- pos
); /* rewrite size */
159 avio_seek(pb
, curpos
, SEEK_SET
);
164 static int64_t update_size_and_version(AVIOContext
*pb
, int64_t pos
, int version
)
166 int64_t curpos
= avio_tell(pb
);
167 avio_seek(pb
, pos
, SEEK_SET
);
168 avio_wb32(pb
, curpos
- pos
); /* rewrite size */
170 avio_w8(pb
, version
); /* rewrite version */
171 avio_seek(pb
, curpos
, SEEK_SET
);
176 static int co64_required(const MOVTrack
*track
)
178 if (track
->entry
> 0 && track
->cluster
[track
->entry
- 1].pos
+ track
->data_offset
> UINT32_MAX
)
183 static int is_cover_image(const AVStream
*st
)
185 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
186 * is encoded as sparse video track */
187 return st
&& st
->disposition
== AV_DISPOSITION_ATTACHED_PIC
;
190 static int rtp_hinting_needed(const AVStream
*st
)
192 /* Add hint tracks for each real audio and video stream */
193 if (is_cover_image(st
))
195 return st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
||
196 st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
;
199 /* Chunk offset atom */
200 static int mov_write_stco_tag(AVIOContext
*pb
, MOVTrack
*track
)
203 int mode64
= co64_required(track
); // use 32 bit size variant if possible
204 int64_t pos
= avio_tell(pb
);
205 avio_wb32(pb
, 0); /* size */
207 ffio_wfourcc(pb
, "co64");
209 ffio_wfourcc(pb
, "stco");
210 avio_wb32(pb
, 0); /* version & flags */
211 avio_wb32(pb
, track
->chunkCount
); /* entry count */
212 for (i
= 0; i
< track
->entry
; i
++) {
213 if (!track
->cluster
[i
].chunkNum
)
216 avio_wb64(pb
, track
->cluster
[i
].pos
+ track
->data_offset
);
218 avio_wb32(pb
, track
->cluster
[i
].pos
+ track
->data_offset
);
220 return update_size(pb
, pos
);
223 /* Sample size atom */
224 static int mov_write_stsz_tag(AVIOContext
*pb
, MOVTrack
*track
)
227 int i
, j
, entries
= 0, tst
= -1, oldtst
= -1;
229 int64_t pos
= avio_tell(pb
);
230 avio_wb32(pb
, 0); /* size */
231 ffio_wfourcc(pb
, "stsz");
232 avio_wb32(pb
, 0); /* version & flags */
234 for (i
= 0; i
< track
->entry
; i
++) {
235 tst
= track
->cluster
[i
].size
/ track
->cluster
[i
].entries
;
236 if (oldtst
!= -1 && tst
!= oldtst
)
239 entries
+= track
->cluster
[i
].entries
;
241 if (equalChunks
&& track
->entry
) {
242 int sSize
= track
->entry
? track
->cluster
[0].size
/ track
->cluster
[0].entries
: 0;
243 sSize
= FFMAX(1, sSize
); // adpcm mono case could make sSize == 0
244 avio_wb32(pb
, sSize
); // sample size
245 avio_wb32(pb
, entries
); // sample count
247 avio_wb32(pb
, 0); // sample size
248 avio_wb32(pb
, entries
); // sample count
249 for (i
= 0; i
< track
->entry
; i
++) {
250 for (j
= 0; j
< track
->cluster
[i
].entries
; j
++) {
251 avio_wb32(pb
, track
->cluster
[i
].size
/
252 track
->cluster
[i
].entries
);
256 return update_size(pb
, pos
);
259 /* Sample to chunk atom */
260 static int mov_write_stsc_tag(AVIOContext
*pb
, MOVTrack
*track
)
262 int index
= 0, oldidx
= -1, oldval
= -1, i
;
263 int64_t entryPos
, curpos
;
265 int64_t pos
= avio_tell(pb
);
266 avio_wb32(pb
, 0); /* size */
267 ffio_wfourcc(pb
, "stsc");
268 avio_wb32(pb
, 0); // version & flags
269 entryPos
= avio_tell(pb
);
270 avio_wb32(pb
, track
->chunkCount
); // entry count
271 for (i
= 0; i
< track
->entry
; i
++) {
272 if ((oldval
!= track
->cluster
[i
].samples_in_chunk
||
273 oldidx
!= track
->cluster
[i
].stsd_index
) && track
->cluster
[i
].chunkNum
) {
274 avio_wb32(pb
, track
->cluster
[i
].chunkNum
); // first chunk
275 avio_wb32(pb
, track
->cluster
[i
].samples_in_chunk
); // samples per chunk
276 avio_wb32(pb
, track
->cluster
[i
].stsd_index
+ 1); // sample description index
277 oldval
= track
->cluster
[i
].samples_in_chunk
;
278 oldidx
= track
->cluster
[i
].stsd_index
;
282 curpos
= avio_tell(pb
);
283 avio_seek(pb
, entryPos
, SEEK_SET
);
284 avio_wb32(pb
, index
); // rewrite size
285 avio_seek(pb
, curpos
, SEEK_SET
);
287 return update_size(pb
, pos
);
290 /* Sync sample atom */
291 static int mov_write_stss_tag(AVIOContext
*pb
, MOVTrack
*track
, uint32_t flag
)
293 int64_t curpos
, entryPos
;
295 int64_t pos
= avio_tell(pb
);
296 avio_wb32(pb
, 0); // size
297 ffio_wfourcc(pb
, flag
== MOV_SYNC_SAMPLE
? "stss" : "stps");
298 avio_wb32(pb
, 0); // version & flags
299 entryPos
= avio_tell(pb
);
300 avio_wb32(pb
, track
->entry
); // entry count
301 for (i
= 0; i
< track
->entry
; i
++) {
302 if (track
->cluster
[i
].flags
& flag
) {
303 avio_wb32(pb
, i
+ 1);
307 curpos
= avio_tell(pb
);
308 avio_seek(pb
, entryPos
, SEEK_SET
);
309 avio_wb32(pb
, index
); // rewrite size
310 avio_seek(pb
, curpos
, SEEK_SET
);
311 return update_size(pb
, pos
);
314 /* Sample dependency atom */
315 static int mov_write_sdtp_tag(AVIOContext
*pb
, MOVTrack
*track
)
318 uint8_t leading
, dependent
, reference
, redundancy
;
319 int64_t pos
= avio_tell(pb
);
320 avio_wb32(pb
, 0); // size
321 ffio_wfourcc(pb
, "sdtp");
322 avio_wb32(pb
, 0); // version & flags
323 for (i
= 0; i
< track
->entry
; i
++) {
324 dependent
= MOV_SAMPLE_DEPENDENCY_YES
;
325 leading
= reference
= redundancy
= MOV_SAMPLE_DEPENDENCY_UNKNOWN
;
326 if (track
->cluster
[i
].flags
& MOV_DISPOSABLE_SAMPLE
) {
327 reference
= MOV_SAMPLE_DEPENDENCY_NO
;
329 if (track
->cluster
[i
].flags
& MOV_SYNC_SAMPLE
) {
330 dependent
= MOV_SAMPLE_DEPENDENCY_NO
;
332 avio_w8(pb
, (leading
<< 6) | (dependent
<< 4) |
333 (reference
<< 2) | redundancy
);
335 return update_size(pb
, pos
);
339 static int mov_write_iacb_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
342 int64_t pos
= avio_tell(pb
);
343 uint8_t *dyn_buf
= NULL
;
345 int ret
= avio_open_dyn_buf(&dyn_bc
);
350 ffio_wfourcc(pb
, "iacb");
351 avio_w8(pb
, 1); // configurationVersion
353 ret
= ff_iamf_write_descriptors(track
->iamf
, dyn_bc
, s
);
357 dyn_size
= avio_close_dyn_buf(dyn_bc
, &dyn_buf
);
358 ffio_write_leb(pb
, dyn_size
);
359 avio_write(pb
, dyn_buf
, dyn_size
);
362 return update_size(pb
, pos
);
366 static int mov_write_amr_tag(AVIOContext
*pb
, MOVTrack
*track
)
368 avio_wb32(pb
, 0x11); /* size */
369 if (track
->mode
== MODE_MOV
) ffio_wfourcc(pb
, "samr");
370 else ffio_wfourcc(pb
, "damr");
371 ffio_wfourcc(pb
, "FFMP");
372 avio_w8(pb
, 0); /* decoder version */
374 avio_wb16(pb
, 0x81FF); /* Mode set (all modes for AMR_NB) */
375 avio_w8(pb
, 0x00); /* Mode change period (no restriction) */
376 avio_w8(pb
, 0x01); /* Frames per sample */
385 /* Layout of the EC3SpecificBox */
386 /* maximum bitrate */
388 int8_t ac3_bit_rate_code
;
389 /* number of independent substreams */
392 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
394 /* bit stream identification 5 bits */
396 /* one bit reserved */
397 /* audio service mixing (not supported yet) 1 bit */
398 /* bit stream mode 3 bits */
400 /* audio coding mode 3 bits */
402 /* sub woofer on 1 bit */
404 /* 3 bits reserved */
405 /* number of dependent substreams associated with this substream 4 bits */
407 /* channel locations of the dependent substream(s), if any, 9 bits */
409 /* if there is no dependent substream, then one bit reserved instead */
410 } substream
[1]; /* TODO: support 8 independent substreams */
411 /* indicates the decoding complexity, 8 bits */
412 uint8_t complexity_index_type_a
;
415 static int mov_write_ac3_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
417 struct eac3_info
*info
= track
->eac3_priv
;
421 if (!info
|| !info
->ec3_done
) {
422 av_log(s
, AV_LOG_ERROR
,
423 "Cannot write moov atom before AC3 packets."
424 " Set the delay_moov flag to fix this.\n");
425 return AVERROR(EINVAL
);
428 if (info
->substream
[0].bsid
> 8) {
429 av_log(s
, AV_LOG_ERROR
,
430 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
431 "ISOBMFF specification in ETSI TS 102 366!\n",
432 info
->substream
[0].bsid
);
433 return AVERROR(EINVAL
);
436 if (info
->ac3_bit_rate_code
< 0) {
437 av_log(s
, AV_LOG_ERROR
,
438 "No valid AC3 bit rate code for data rate of %d!\n",
440 return AVERROR(EINVAL
);
444 ffio_wfourcc(pb
, "dac3");
446 init_put_bits(&pbc
, buf
, sizeof(buf
));
447 put_bits(&pbc
, 2, info
->substream
[0].fscod
);
448 put_bits(&pbc
, 5, info
->substream
[0].bsid
);
449 put_bits(&pbc
, 3, info
->substream
[0].bsmod
);
450 put_bits(&pbc
, 3, info
->substream
[0].acmod
);
451 put_bits(&pbc
, 1, info
->substream
[0].lfeon
);
452 put_bits(&pbc
, 5, info
->ac3_bit_rate_code
); // bit_rate_code
453 put_bits(&pbc
, 5, 0); // reserved
455 flush_put_bits(&pbc
);
456 avio_write(pb
, buf
, sizeof(buf
));
461 static int handle_eac3(MOVMuxContext
*mov
, AVPacket
*pkt
, MOVTrack
*track
)
463 AC3HeaderInfo
*hdr
= NULL
;
464 struct eac3_info
*info
;
467 if (!track
->eac3_priv
) {
468 if (!(track
->eac3_priv
= av_mallocz(sizeof(*info
))))
469 return AVERROR(ENOMEM
);
471 ((struct eac3_info
*)track
->eac3_priv
)->ac3_bit_rate_code
= -1;
473 info
= track
->eac3_priv
;
475 if (!info
->pkt
&& !(info
->pkt
= av_packet_alloc()))
476 return AVERROR(ENOMEM
);
478 if ((ret
= avpriv_ac3_parse_header(&hdr
, pkt
->data
, pkt
->size
)) < 0) {
479 if (ret
== AVERROR(ENOMEM
))
482 /* drop the packets until we see a good one */
484 av_log(mov
->fc
, AV_LOG_WARNING
, "Dropping invalid packet from start of the stream\n");
487 ret
= AVERROR_INVALIDDATA
;
491 info
->data_rate
= FFMAX(info
->data_rate
, hdr
->bit_rate
/ 1000);
492 info
->ac3_bit_rate_code
= FFMAX(info
->ac3_bit_rate_code
,
493 hdr
->ac3_bit_rate_code
);
494 info
->complexity_index_type_a
= hdr
->complexity_index_type_a
;
496 num_blocks
= hdr
->num_blocks
;
498 if (!info
->ec3_done
) {
499 /* AC-3 substream must be the first one */
500 if (hdr
->bitstream_id
<= 10 && hdr
->substreamid
!= 0) {
501 ret
= AVERROR(EINVAL
);
505 /* this should always be the case, given that our AC-3 parser
506 * concatenates dependent frames to their independent parent */
507 if (hdr
->frame_type
== EAC3_FRAME_TYPE_INDEPENDENT
||
508 hdr
->frame_type
== EAC3_FRAME_TYPE_AC3_CONVERT
) {
509 /* substream ids must be incremental */
510 if (hdr
->substreamid
> info
->num_ind_sub
+ 1) {
511 ret
= AVERROR(EINVAL
);
515 if (hdr
->substreamid
== info
->num_ind_sub
+ 1) {
516 //info->num_ind_sub++;
517 avpriv_request_sample(mov
->fc
, "Multiple independent substreams");
518 ret
= AVERROR_PATCHWELCOME
;
520 } else if (hdr
->substreamid
< info
->num_ind_sub
||
521 hdr
->substreamid
== 0 && info
->substream
[0].bsid
) {
526 if (hdr
->substreamid
!= 0) {
527 avpriv_request_sample(mov
->fc
, "Multiple non EAC3 independent substreams");
528 ret
= AVERROR_PATCHWELCOME
;
533 /* fill the info needed for the "dec3" atom */
534 info
->substream
[hdr
->substreamid
].fscod
= hdr
->sr_code
;
535 info
->substream
[hdr
->substreamid
].bsid
= hdr
->bitstream_id
;
536 info
->substream
[hdr
->substreamid
].bsmod
= hdr
->bitstream_mode
;
537 info
->substream
[hdr
->substreamid
].acmod
= hdr
->channel_mode
;
538 info
->substream
[hdr
->substreamid
].lfeon
= hdr
->lfe_on
;
540 if (track
->par
->codec_id
== AV_CODEC_ID_AC3
) {
541 // with AC-3 we only require the information of a single packet,
542 // so we can finish as soon as the basic values of the bit stream
543 // have been set to the track's informational structure.
548 /* Parse dependent substream(s), if any */
549 if (pkt
->size
!= hdr
->frame_size
) {
550 int cumul_size
= hdr
->frame_size
;
551 int parent
= hdr
->substreamid
;
553 while (cumul_size
!= pkt
->size
) {
554 ret
= avpriv_ac3_parse_header(&hdr
, pkt
->data
+ cumul_size
, pkt
->size
- cumul_size
);
557 if (hdr
->frame_type
!= EAC3_FRAME_TYPE_DEPENDENT
) {
558 ret
= AVERROR(EINVAL
);
561 info
->substream
[parent
].num_dep_sub
++;
564 /* get the dependent stream channel map, if exists */
565 if (hdr
->channel_map_present
)
566 info
->substream
[parent
].chan_loc
|= (hdr
->channel_map
>> 5) & 0x1f;
568 info
->substream
[parent
].chan_loc
|= hdr
->channel_mode
;
569 cumul_size
+= hdr
->frame_size
;
575 if (!info
->num_blocks
&& num_blocks
== 6) {
579 else if (info
->num_blocks
+ num_blocks
> 6) {
580 ret
= AVERROR_INVALIDDATA
;
584 if (!info
->num_blocks
) {
585 ret
= av_packet_ref(info
->pkt
, pkt
);
587 info
->num_blocks
= num_blocks
;
590 if ((ret
= av_grow_packet(info
->pkt
, pkt
->size
)) < 0)
592 memcpy(info
->pkt
->data
+ info
->pkt
->size
- pkt
->size
, pkt
->data
, pkt
->size
);
593 info
->num_blocks
+= num_blocks
;
594 info
->pkt
->duration
+= pkt
->duration
;
595 if (info
->num_blocks
!= 6)
597 av_packet_unref(pkt
);
598 av_packet_move_ref(pkt
, info
->pkt
);
599 info
->num_blocks
= 0;
609 static int mov_write_eac3_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
613 struct eac3_info
*info
;
616 if (!track
->eac3_priv
) {
617 av_log(s
, AV_LOG_ERROR
,
618 "Cannot write moov atom before EAC3 packets parsed.\n");
619 return AVERROR(EINVAL
);
622 info
= track
->eac3_priv
;
623 size
= 2 + (4 * (info
->num_ind_sub
+ 1)) + (2 * !!info
->complexity_index_type_a
);
624 buf
= av_malloc(size
);
626 return AVERROR(ENOMEM
);
629 init_put_bits(&pbc
, buf
, size
);
630 put_bits(&pbc
, 13, info
->data_rate
);
631 put_bits(&pbc
, 3, info
->num_ind_sub
);
632 for (i
= 0; i
<= info
->num_ind_sub
; i
++) {
633 put_bits(&pbc
, 2, info
->substream
[i
].fscod
);
634 put_bits(&pbc
, 5, info
->substream
[i
].bsid
);
635 put_bits(&pbc
, 1, 0); /* reserved */
636 put_bits(&pbc
, 1, 0); /* asvc */
637 put_bits(&pbc
, 3, info
->substream
[i
].bsmod
);
638 put_bits(&pbc
, 3, info
->substream
[i
].acmod
);
639 put_bits(&pbc
, 1, info
->substream
[i
].lfeon
);
640 put_bits(&pbc
, 3, 0); /* reserved */
641 put_bits(&pbc
, 4, info
->substream
[i
].num_dep_sub
);
642 if (!info
->substream
[i
].num_dep_sub
) {
643 put_bits(&pbc
, 1, 0); /* reserved */
645 put_bits(&pbc
, 9, info
->substream
[i
].chan_loc
);
648 if (info
->complexity_index_type_a
) {
649 put_bits(&pbc
, 7, 0); /* reserved */
650 put_bits(&pbc
, 1, 1); // flag_eac3_extension_type_a
651 put_bits(&pbc
, 8, info
->complexity_index_type_a
);
653 flush_put_bits(&pbc
);
654 size
= put_bytes_output(&pbc
);
656 avio_wb32(pb
, size
+ 8);
657 ffio_wfourcc(pb
, "dec3");
658 avio_write(pb
, buf
, size
);
666 * This function writes extradata "as is".
667 * Extradata must be formatted like a valid atom (with size and tag).
669 static int mov_write_extradata_tag(AVIOContext
*pb
, MOVTrack
*track
)
671 avio_write(pb
, track
->extradata
[track
->last_stsd_index
], track
->extradata_size
[track
->last_stsd_index
]);
672 return track
->extradata_size
[track
->last_stsd_index
];
675 static int mov_write_enda_tag(AVIOContext
*pb
)
678 ffio_wfourcc(pb
, "enda");
679 avio_wb16(pb
, 1); /* little endian */
683 static int mov_write_enda_tag_be(AVIOContext
*pb
)
686 ffio_wfourcc(pb
, "enda");
687 avio_wb16(pb
, 0); /* big endian */
691 static void put_descr(AVIOContext
*pb
, int tag
, unsigned int size
)
696 avio_w8(pb
, (size
>> (7 * i
)) | 0x80);
697 avio_w8(pb
, size
& 0x7F);
700 static unsigned compute_avg_bitrate(MOVTrack
*track
)
704 if (!track
->track_duration
)
706 for (i
= 0; i
< track
->entry
; i
++)
707 size
+= track
->cluster
[i
].size
;
708 return size
* 8 * track
->timescale
/ track
->track_duration
;
711 struct mpeg4_bit_rate_values
{
712 uint32_t buffer_size
; ///< Size of the decoding buffer for the elementary stream in bytes.
713 uint32_t max_bit_rate
; ///< Maximum rate in bits/second over any window of one second.
714 uint32_t avg_bit_rate
; ///< Average rate in bits/second over the entire presentation.
717 static struct mpeg4_bit_rate_values
calculate_mpeg4_bit_rates(MOVTrack
*track
)
719 const AVPacketSideData
*sd
= track
->st
?
720 av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
721 track
->st
->codecpar
->nb_coded_side_data
,
722 AV_PKT_DATA_CPB_PROPERTIES
) : NULL
;
723 AVCPBProperties
*props
= sd
? (AVCPBProperties
*)sd
->data
: NULL
;
724 struct mpeg4_bit_rate_values bit_rates
= { 0 };
726 bit_rates
.avg_bit_rate
= compute_avg_bitrate(track
);
727 if (!bit_rates
.avg_bit_rate
) {
728 // if the average bit rate cannot be calculated at this point, such as
729 // in the case of fragmented MP4, utilize the following values as
730 // fall-back in priority order:
732 // 1. average bit rate property
733 // 2. bit rate (usually average over the whole clip)
734 // 3. maximum bit rate property
736 if (props
&& props
->avg_bitrate
) {
737 bit_rates
.avg_bit_rate
= props
->avg_bitrate
;
738 } else if (track
->par
->bit_rate
) {
739 bit_rates
.avg_bit_rate
= track
->par
->bit_rate
;
740 } else if (props
&& props
->max_bitrate
) {
741 bit_rates
.avg_bit_rate
= props
->max_bitrate
;
745 // (FIXME should be max rate in any 1 sec window)
746 bit_rates
.max_bit_rate
= FFMAX(track
->par
->bit_rate
,
747 bit_rates
.avg_bit_rate
);
749 // utilize values from properties if we have them available
751 // no avg_bitrate signals that the track is VBR
752 if (!props
->avg_bitrate
)
753 bit_rates
.avg_bit_rate
= props
->avg_bitrate
;
754 bit_rates
.max_bit_rate
= FFMAX(bit_rates
.max_bit_rate
,
756 bit_rates
.buffer_size
= props
->buffer_size
/ 8;
762 static int mov_write_esds_tag(AVIOContext
*pb
, MOVTrack
*track
) // Basic
764 struct mpeg4_bit_rate_values bit_rates
= calculate_mpeg4_bit_rates(track
);
765 int64_t pos
= avio_tell(pb
);
766 int decoder_specific_info_len
= track
->extradata_size
[track
->last_stsd_index
] ?
767 5 + track
->extradata_size
[track
->last_stsd_index
] : 0;
769 avio_wb32(pb
, 0); // size
770 ffio_wfourcc(pb
, "esds");
771 avio_wb32(pb
, 0); // Version
774 put_descr(pb
, 0x03, 3 + 5+13 + decoder_specific_info_len
+ 5+1);
775 avio_wb16(pb
, track
->track_id
);
776 avio_w8(pb
, 0x00); // flags (= no flags)
778 // DecoderConfig descriptor
779 put_descr(pb
, 0x04, 13 + decoder_specific_info_len
);
781 // Object type indication
782 if ((track
->par
->codec_id
== AV_CODEC_ID_MP2
||
783 track
->par
->codec_id
== AV_CODEC_ID_MP3
) &&
784 track
->par
->sample_rate
> 24000)
785 avio_w8(pb
, 0x6B); // 11172-3
787 avio_w8(pb
, ff_codec_get_tag(ff_mp4_obj_type
, track
->par
->codec_id
));
789 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
790 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
791 if (track
->par
->codec_id
== AV_CODEC_ID_DVD_SUBTITLE
)
792 avio_w8(pb
, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
793 else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
)
794 avio_w8(pb
, 0x15); // flags (= Audiostream)
796 avio_w8(pb
, 0x11); // flags (= Visualstream)
798 avio_wb24(pb
, bit_rates
.buffer_size
); // Buffersize DB
799 avio_wb32(pb
, bit_rates
.max_bit_rate
); // maxbitrate
800 avio_wb32(pb
, bit_rates
.avg_bit_rate
);
802 if (track
->extradata_size
[track
->last_stsd_index
]) {
803 // DecoderSpecific info descriptor
804 put_descr(pb
, 0x05, track
->extradata_size
[track
->last_stsd_index
]);
805 avio_write(pb
, track
->extradata
[track
->last_stsd_index
],
806 track
->extradata_size
[track
->last_stsd_index
]);
810 put_descr(pb
, 0x06, 1);
812 return update_size(pb
, pos
);
815 static int mov_pcm_le_gt16(enum AVCodecID codec_id
)
817 return codec_id
== AV_CODEC_ID_PCM_S24LE
||
818 codec_id
== AV_CODEC_ID_PCM_S32LE
||
819 codec_id
== AV_CODEC_ID_PCM_F32LE
||
820 codec_id
== AV_CODEC_ID_PCM_F64LE
;
823 static int mov_pcm_be_gt16(enum AVCodecID codec_id
)
825 return codec_id
== AV_CODEC_ID_PCM_S24BE
||
826 codec_id
== AV_CODEC_ID_PCM_S32BE
||
827 codec_id
== AV_CODEC_ID_PCM_F32BE
||
828 codec_id
== AV_CODEC_ID_PCM_F64BE
;
831 static int mov_write_ms_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
834 int64_t pos
= avio_tell(pb
);
836 avio_wl32(pb
, track
->tag
); // store it byteswapped
837 track
->par
->codec_tag
= av_bswap16(track
->tag
>> 16);
838 if ((ret
= ff_put_wav_header(s
, pb
, track
->par
, 0)) < 0)
840 return update_size(pb
, pos
);
843 static int mov_write_wfex_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
846 int64_t pos
= avio_tell(pb
);
848 ffio_wfourcc(pb
, "wfex");
849 if ((ret
= ff_put_wav_header(s
, pb
, track
->st
->codecpar
, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX
)) < 0)
851 return update_size(pb
, pos
);
854 static int mov_write_dfla_tag(AVIOContext
*pb
, MOVTrack
*track
)
856 int64_t pos
= avio_tell(pb
);
858 ffio_wfourcc(pb
, "dfLa");
859 avio_w8(pb
, 0); /* version */
860 avio_wb24(pb
, 0); /* flags */
862 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
863 if (track
->extradata_size
[track
->last_stsd_index
] != FLAC_STREAMINFO_SIZE
)
864 return AVERROR_INVALIDDATA
;
866 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
867 avio_w8(pb
, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO
); /* LastMetadataBlockFlag << 7 | BlockType */
868 avio_wb24(pb
, track
->extradata_size
[track
->last_stsd_index
]); /* Length */
869 avio_write(pb
, track
->extradata
[track
->last_stsd_index
], track
->extradata_size
[track
->last_stsd_index
]); /* BlockData[Length] */
871 return update_size(pb
, pos
);
874 static int mov_write_dops_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
876 int64_t pos
= avio_tell(pb
);
877 int channels
, channel_map
;
879 ffio_wfourcc(pb
, "dOps");
880 avio_w8(pb
, 0); /* Version */
881 if (track
->extradata_size
[track
->last_stsd_index
] < 19) {
882 av_log(s
, AV_LOG_ERROR
, "invalid extradata size\n");
883 return AVERROR_INVALIDDATA
;
885 /* extradata contains an Ogg OpusHead, other than byte-ordering and
886 OpusHead's preceding magic/version, OpusSpecificBox is currently
888 channels
= AV_RB8(track
->extradata
[track
->last_stsd_index
] + 9);
889 channel_map
= AV_RB8(track
->extradata
[track
->last_stsd_index
] + 18);
891 avio_w8(pb
, channels
); /* OuputChannelCount */
892 avio_wb16(pb
, AV_RL16(track
->extradata
[track
->last_stsd_index
] + 10)); /* PreSkip */
893 avio_wb32(pb
, AV_RL32(track
->extradata
[track
->last_stsd_index
] + 12)); /* InputSampleRate */
894 avio_wb16(pb
, AV_RL16(track
->extradata
[track
->last_stsd_index
] + 16)); /* OutputGain */
895 avio_w8(pb
, channel_map
); /* ChannelMappingFamily */
896 /* Write the rest of the header out without byte-swapping. */
898 if (track
->extradata_size
[track
->last_stsd_index
] < 21 + channels
) {
899 av_log(s
, AV_LOG_ERROR
, "invalid extradata size\n");
900 return AVERROR_INVALIDDATA
;
902 avio_write(pb
, track
->extradata
[track
->last_stsd_index
] + 19, 2 + channels
); /* ChannelMappingTable */
905 return update_size(pb
, pos
);
908 static int mov_write_dmlp_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
910 int64_t pos
= avio_tell(pb
);
913 ffio_wfourcc(pb
, "dmlp");
915 if (track
->extradata_size
[track
->last_stsd_index
] < 20) {
916 av_log(s
, AV_LOG_ERROR
,
917 "Cannot write moov atom before TrueHD packets."
918 " Set the delay_moov flag to fix this.\n");
919 return AVERROR(EINVAL
);
922 length
= (AV_RB16(track
->extradata
[track
->last_stsd_index
]) & 0xFFF) * 2;
923 if (length
< 20 || length
> track
->extradata_size
[track
->last_stsd_index
])
924 return AVERROR_INVALIDDATA
;
926 // Only TrueHD is supported
927 if (AV_RB32(track
->extradata
[track
->last_stsd_index
] + 4) != 0xF8726FBA)
928 return AVERROR_INVALIDDATA
;
930 avio_wb32(pb
, AV_RB32(track
->extradata
[track
->last_stsd_index
] + 8)); /* format_info */
931 avio_wb16(pb
, AV_RB16(track
->extradata
[track
->last_stsd_index
] + 18) << 1); /* peak_data_rate */
932 avio_wb32(pb
, 0); /* reserved */
934 return update_size(pb
, pos
);
937 static int mov_write_SA3D_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
939 const AVDictionaryEntry
*str
= av_dict_get(track
->st
->metadata
, "SA3D", NULL
, 0);
940 AVChannelLayout ch_layout
= { 0 };
942 int ambisonic_order
, ambi_channels
, non_diegetic_channels
;
948 ret
= av_channel_layout_from_string(&ch_layout
, str
->value
);
950 if (ret
== AVERROR(EINVAL
)) {
952 av_log(s
, AV_LOG_ERROR
, "Invalid SA3D layout: \"%s\"\n", str
->value
);
955 av_channel_layout_uninit(&ch_layout
);
959 if (track
->st
->codecpar
->ch_layout
.nb_channels
!= ch_layout
.nb_channels
)
962 ambisonic_order
= av_channel_layout_ambisonic_order(&ch_layout
);
963 if (ambisonic_order
< 0)
966 ambi_channels
= (ambisonic_order
+ 1LL) * (ambisonic_order
+ 1LL);
967 non_diegetic_channels
= ch_layout
.nb_channels
- ambi_channels
;
968 if (non_diegetic_channels
&&
969 (non_diegetic_channels
!= 2 ||
970 av_channel_layout_subset(&ch_layout
, AV_CH_LAYOUT_STEREO
) != AV_CH_LAYOUT_STEREO
))
973 av_log(s
, AV_LOG_VERBOSE
, "Inserting SA3D box with layout: \"%s\"\n", str
->value
);
977 avio_wb32(pb
, 0); // Size
978 ffio_wfourcc(pb
, "SA3D");
979 avio_w8(pb
, 0); // version
980 avio_w8(pb
, (!!non_diegetic_channels
) << 7); // head_locked_stereo and ambisonic_type
981 avio_wb32(pb
, ambisonic_order
); // ambisonic_order
982 avio_w8(pb
, 0); // ambisonic_channel_ordering
983 avio_w8(pb
, 0); // ambisonic_normalization
984 avio_wb32(pb
, ch_layout
.nb_channels
); // num_channels
985 for (i
= 0; i
< ambi_channels
; i
++)
986 avio_wb32(pb
, av_channel_layout_channel_from_index(&ch_layout
, i
) - AV_CHAN_AMBISONIC_BASE
);
987 for (; i
< ch_layout
.nb_channels
; i
++)
988 avio_wb32(pb
, av_channel_layout_channel_from_index(&ch_layout
, i
) + ambi_channels
);
990 av_channel_layout_uninit(&ch_layout
);
992 return update_size(pb
, pos
);
995 static int mov_write_chan_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
997 uint32_t layout_tag
, bitmap
, *channel_desc
;
998 int64_t pos
= avio_tell(pb
);
1001 if (track
->multichannel_as_mono
)
1004 ret
= ff_mov_get_channel_layout_tag(track
->par
, &layout_tag
,
1005 &bitmap
, &channel_desc
);
1008 if (ret
== AVERROR(ENOSYS
)) {
1009 av_log(s
, AV_LOG_WARNING
, "not writing 'chan' tag due to "
1010 "lack of channel information\n");
1017 if (layout_tag
== MOV_CH_LAYOUT_MONO
&& track
->mono_as_fc
> 0) {
1018 av_assert0(!channel_desc
);
1019 channel_desc
= av_malloc(sizeof(*channel_desc
));
1021 return AVERROR(ENOMEM
);
1025 *channel_desc
= 3; // channel label "Center"
1028 num_desc
= layout_tag
? 0 : track
->par
->ch_layout
.nb_channels
;
1030 avio_wb32(pb
, 0); // Size
1031 ffio_wfourcc(pb
, "chan"); // Type
1032 avio_w8(pb
, 0); // Version
1033 avio_wb24(pb
, 0); // Flags
1034 avio_wb32(pb
, layout_tag
); // mChannelLayoutTag
1035 avio_wb32(pb
, bitmap
); // mChannelBitmap
1036 avio_wb32(pb
, num_desc
); // mNumberChannelDescriptions
1038 for (int i
= 0; i
< num_desc
; i
++) {
1039 avio_wb32(pb
, channel_desc
[i
]); // mChannelLabel
1040 avio_wb32(pb
, 0); // mChannelFlags
1041 avio_wl32(pb
, 0); // mCoordinates[0]
1042 avio_wl32(pb
, 0); // mCoordinates[1]
1043 avio_wl32(pb
, 0); // mCoordinates[2]
1046 av_free(channel_desc
);
1048 return update_size(pb
, pos
);
1051 static int mov_write_wave_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1053 int64_t pos
= avio_tell(pb
);
1055 avio_wb32(pb
, 0); /* size */
1056 ffio_wfourcc(pb
, "wave");
1058 if (track
->par
->codec_id
!= AV_CODEC_ID_QDM2
) {
1059 avio_wb32(pb
, 12); /* size */
1060 ffio_wfourcc(pb
, "frma");
1061 avio_wl32(pb
, track
->tag
);
1064 if (track
->par
->codec_id
== AV_CODEC_ID_AAC
) {
1065 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1066 avio_wb32(pb
, 12); /* size */
1067 ffio_wfourcc(pb
, "mp4a");
1069 mov_write_esds_tag(pb
, track
);
1070 } else if (mov_pcm_le_gt16(track
->par
->codec_id
)) {
1071 mov_write_enda_tag(pb
);
1072 } else if (mov_pcm_be_gt16(track
->par
->codec_id
)) {
1073 mov_write_enda_tag_be(pb
);
1074 } else if (track
->par
->codec_id
== AV_CODEC_ID_AMR_NB
) {
1075 mov_write_amr_tag(pb
, track
);
1076 } else if (track
->par
->codec_id
== AV_CODEC_ID_AC3
) {
1077 mov_write_ac3_tag(s
, pb
, track
);
1078 } else if (track
->par
->codec_id
== AV_CODEC_ID_EAC3
) {
1079 mov_write_eac3_tag(s
, pb
, track
);
1080 } else if (track
->par
->codec_id
== AV_CODEC_ID_ALAC
||
1081 track
->par
->codec_id
== AV_CODEC_ID_QDM2
) {
1082 mov_write_extradata_tag(pb
, track
);
1083 } else if (track
->par
->codec_id
== AV_CODEC_ID_ADPCM_MS
||
1084 track
->par
->codec_id
== AV_CODEC_ID_ADPCM_IMA_WAV
) {
1085 mov_write_ms_tag(s
, pb
, track
);
1088 avio_wb32(pb
, 8); /* size */
1089 avio_wb32(pb
, 0); /* null tag */
1091 return update_size(pb
, pos
);
1094 static int mov_write_dvc1_structs(MOVTrack
*track
, uint8_t *buf
)
1097 const uint8_t *start
, *next
, *end
= track
->extradata
[track
->last_stsd_index
] +
1098 track
->extradata_size
[track
->last_stsd_index
];
1099 int unescaped_size
, seq_found
= 0;
1100 int level
= 0, interlace
= 0;
1101 int packet_seq
= track
->vc1_info
.packet_seq
;
1102 int packet_entry
= track
->vc1_info
.packet_entry
;
1103 int slices
= track
->vc1_info
.slices
;
1106 if (track
->start_dts
== AV_NOPTS_VALUE
) {
1107 /* No packets written yet, vc1_info isn't authoritative yet. */
1108 /* Assume inline sequence and entry headers. */
1109 packet_seq
= packet_entry
= 1;
1110 av_log(NULL
, AV_LOG_WARNING
,
1111 "moov atom written before any packets, unable to write correct "
1112 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1115 unescaped
= av_mallocz(track
->extradata_size
[track
->last_stsd_index
] + AV_INPUT_BUFFER_PADDING_SIZE
);
1117 return AVERROR(ENOMEM
);
1118 start
= find_next_marker(track
->extradata
[track
->last_stsd_index
], end
);
1119 for (next
= start
; next
< end
; start
= next
) {
1122 next
= find_next_marker(start
+ 4, end
);
1123 size
= next
- start
- 4;
1126 unescaped_size
= vc1_unescape_buffer(start
+ 4, size
, unescaped
);
1127 init_get_bits(&gb
, unescaped
, 8 * unescaped_size
);
1128 if (AV_RB32(start
) == VC1_CODE_SEQHDR
) {
1129 int profile
= get_bits(&gb
, 2);
1130 if (profile
!= PROFILE_ADVANCED
) {
1132 return AVERROR(ENOSYS
);
1135 level
= get_bits(&gb
, 3);
1136 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1138 skip_bits_long(&gb
, 2 + 3 + 5 + 1 + 2*12);
1139 skip_bits(&gb
, 1); /* broadcast */
1140 interlace
= get_bits1(&gb
);
1141 skip_bits(&gb
, 4); /* tfcntrflag, finterpflag, reserved, psf */
1146 return AVERROR(ENOSYS
);
1149 init_put_bits(&pbc
, buf
, 7);
1150 /* VC1DecSpecStruc */
1151 put_bits(&pbc
, 4, 12); /* profile - advanced */
1152 put_bits(&pbc
, 3, level
);
1153 put_bits(&pbc
, 1, 0); /* reserved */
1154 /* VC1AdvDecSpecStruc */
1155 put_bits(&pbc
, 3, level
);
1156 put_bits(&pbc
, 1, 0); /* cbr */
1157 put_bits(&pbc
, 6, 0); /* reserved */
1158 put_bits(&pbc
, 1, !interlace
); /* no interlace */
1159 put_bits(&pbc
, 1, !packet_seq
); /* no multiple seq */
1160 put_bits(&pbc
, 1, !packet_entry
); /* no multiple entry */
1161 put_bits(&pbc
, 1, !slices
); /* no slice code */
1162 put_bits(&pbc
, 1, 0); /* no bframe */
1163 put_bits(&pbc
, 1, 0); /* reserved */
1166 if (track
->st
->avg_frame_rate
.num
> 0 && track
->st
->avg_frame_rate
.den
> 0)
1167 put_bits32(&pbc
, track
->st
->avg_frame_rate
.num
/ track
->st
->avg_frame_rate
.den
);
1169 put_bits32(&pbc
, 0xffffffff);
1171 flush_put_bits(&pbc
);
1178 static int mov_write_dvc1_tag(AVIOContext
*pb
, MOVTrack
*track
)
1180 uint8_t buf
[7] = { 0 };
1183 if ((ret
= mov_write_dvc1_structs(track
, buf
)) < 0)
1186 avio_wb32(pb
, track
->extradata_size
[track
->last_stsd_index
] + 8 + sizeof(buf
));
1187 ffio_wfourcc(pb
, "dvc1");
1188 avio_write(pb
, buf
, sizeof(buf
));
1189 avio_write(pb
, track
->extradata
[track
->last_stsd_index
],
1190 track
->extradata_size
[track
->last_stsd_index
]);
1195 static int mov_write_glbl_tag(AVIOContext
*pb
, MOVTrack
*track
)
1197 avio_wb32(pb
, track
->extradata_size
[track
->last_stsd_index
] + 8);
1198 ffio_wfourcc(pb
, "glbl");
1199 avio_write(pb
, track
->extradata
[track
->last_stsd_index
],
1200 track
->extradata_size
[track
->last_stsd_index
]);
1201 return 8 + track
->extradata_size
[track
->last_stsd_index
];
1205 * Compute flags for 'lpcm' tag.
1206 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1208 static int mov_get_lpcm_flags(enum AVCodecID codec_id
)
1211 case AV_CODEC_ID_PCM_F32BE
:
1212 case AV_CODEC_ID_PCM_F64BE
:
1214 case AV_CODEC_ID_PCM_F32LE
:
1215 case AV_CODEC_ID_PCM_F64LE
:
1217 case AV_CODEC_ID_PCM_U8
:
1219 case AV_CODEC_ID_PCM_S16BE
:
1220 case AV_CODEC_ID_PCM_S24BE
:
1221 case AV_CODEC_ID_PCM_S32BE
:
1223 case AV_CODEC_ID_PCM_S8
:
1224 case AV_CODEC_ID_PCM_S16LE
:
1225 case AV_CODEC_ID_PCM_S24LE
:
1226 case AV_CODEC_ID_PCM_S32LE
:
1233 static int get_cluster_duration(MOVTrack
*track
, int cluster_idx
)
1237 if (cluster_idx
>= track
->entry
)
1240 if (cluster_idx
+ 1 == track
->entry
)
1241 next_dts
= track
->track_duration
+ track
->start_dts
;
1243 next_dts
= track
->cluster
[cluster_idx
+ 1].dts
;
1245 next_dts
-= track
->cluster
[cluster_idx
].dts
;
1247 av_assert0(next_dts
>= 0);
1248 av_assert0(next_dts
<= INT_MAX
);
1253 static int get_samples_per_packet(MOVTrack
*track
)
1255 int i
, first_duration
;
1257 /* use 1 for raw PCM */
1258 if (!track
->audio_vbr
)
1261 /* check to see if duration is constant for all clusters */
1264 first_duration
= get_cluster_duration(track
, 0);
1265 for (i
= 1; i
< track
->entry
; i
++) {
1266 if (get_cluster_duration(track
, i
) != first_duration
)
1269 return first_duration
;
1272 static int mov_write_btrt_tag(AVIOContext
*pb
, MOVTrack
*track
)
1274 int64_t pos
= avio_tell(pb
);
1275 struct mpeg4_bit_rate_values bit_rates
= calculate_mpeg4_bit_rates(track
);
1276 if (!bit_rates
.max_bit_rate
&& !bit_rates
.avg_bit_rate
&&
1277 !bit_rates
.buffer_size
)
1278 // no useful data to be written, skip
1281 avio_wb32(pb
, 0); /* size */
1282 ffio_wfourcc(pb
, "btrt");
1284 avio_wb32(pb
, bit_rates
.buffer_size
);
1285 avio_wb32(pb
, bit_rates
.max_bit_rate
);
1286 avio_wb32(pb
, bit_rates
.avg_bit_rate
);
1288 return update_size(pb
, pos
);
1291 static int mov_write_chnl_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1293 int64_t pos
= avio_tell(pb
);
1296 uint8_t *speaker_pos
= NULL
;
1297 const AVChannelLayout
*layout
= &track
->par
->ch_layout
;
1299 ret
= ff_mov_get_channel_config_from_layout(layout
, &config
);
1300 if (ret
|| !config
) {
1302 speaker_pos
= av_malloc(layout
->nb_channels
);
1304 return AVERROR(ENOMEM
);
1305 ret
= ff_mov_get_channel_positions_from_layout(layout
,
1306 speaker_pos
, layout
->nb_channels
);
1308 char buf
[128] = {0};
1310 av_freep(&speaker_pos
);
1311 av_channel_layout_describe(layout
, buf
, sizeof(buf
));
1312 av_log(s
, AV_LOG_ERROR
, "unsupported channel layout %s\n", buf
);
1317 avio_wb32(pb
, 0); /* size */
1318 ffio_wfourcc(pb
, "chnl");
1319 avio_wb32(pb
, 0); /* version & flags */
1321 avio_w8(pb
, 1); /* stream_structure */
1322 avio_w8(pb
, config
);
1326 avio_write(pb
, speaker_pos
, layout
->nb_channels
);
1327 av_freep(&speaker_pos
);
1330 return update_size(pb
, pos
);
1333 static int mov_write_pcmc_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1335 int64_t pos
= avio_tell(pb
);
1339 avio_wb32(pb
, 0); /* size */
1340 ffio_wfourcc(pb
, "pcmC");
1341 avio_wb32(pb
, 0); /* version & flags */
1343 /* 0x01: indicates little-endian format */
1344 format_flags
= (track
->par
->codec_id
== AV_CODEC_ID_PCM_F32LE
||
1345 track
->par
->codec_id
== AV_CODEC_ID_PCM_F64LE
||
1346 track
->par
->codec_id
== AV_CODEC_ID_PCM_S16LE
||
1347 track
->par
->codec_id
== AV_CODEC_ID_PCM_S24LE
||
1348 track
->par
->codec_id
== AV_CODEC_ID_PCM_S32LE
);
1349 avio_w8(pb
, format_flags
);
1350 sample_size
= track
->par
->bits_per_raw_sample
;
1352 sample_size
= av_get_exact_bits_per_sample(track
->par
->codec_id
);
1353 av_assert0(sample_size
);
1354 avio_w8(pb
, sample_size
);
1356 return update_size(pb
, pos
);
1359 static int mov_write_srat_tag(AVIOContext
*pb
, MOVTrack
*track
)
1361 int64_t pos
= avio_tell(pb
);
1362 avio_wb32(pb
, 0); /* size */
1363 ffio_wfourcc(pb
, "srat");
1364 avio_wb32(pb
, 0); /* version & flags */
1366 avio_wb32(pb
, track
->par
->sample_rate
);
1368 return update_size(pb
, pos
);
1371 static int mov_write_audio_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVMuxContext
*mov
, MOVTrack
*track
)
1373 int64_t pos
= avio_tell(pb
);
1375 uint32_t tag
= track
->tag
;
1378 if (track
->mode
== MODE_MOV
) {
1379 if (track
->timescale
> UINT16_MAX
|| !track
->par
->ch_layout
.nb_channels
) {
1380 if (mov_get_lpcm_flags(track
->par
->codec_id
))
1381 tag
= AV_RL32("lpcm");
1383 } else if (track
->audio_vbr
|| mov_pcm_le_gt16(track
->par
->codec_id
) ||
1384 mov_pcm_be_gt16(track
->par
->codec_id
) ||
1385 track
->par
->codec_id
== AV_CODEC_ID_ADPCM_MS
||
1386 track
->par
->codec_id
== AV_CODEC_ID_ADPCM_IMA_WAV
||
1387 track
->par
->codec_id
== AV_CODEC_ID_QDM2
) {
1390 } else if (track
->mode
== MODE_MP4
) {
1391 if (track
->par
->sample_rate
> UINT16_MAX
&&
1392 (tag
== MOV_MP4_IPCM_TAG
|| tag
== MOV_MP4_FPCM_TAG
))
1396 avio_wb32(pb
, 0); /* size */
1397 if (mov
->encryption_scheme
!= MOV_ENC_NONE
) {
1398 ffio_wfourcc(pb
, "enca");
1400 avio_wl32(pb
, tag
); // store it byteswapped
1402 avio_wb32(pb
, 0); /* Reserved */
1403 avio_wb16(pb
, 0); /* Reserved */
1404 avio_wb16(pb
, 1); /* Data-reference index, XXX == 1 */
1406 /* SoundDescription */
1407 avio_wb16(pb
, version
); /* Version */
1408 avio_wb16(pb
, 0); /* Revision level */
1409 avio_wb32(pb
, 0); /* Reserved */
1414 avio_wb16(pb
, 0xfffe);
1416 avio_wb32(pb
, 0x00010000);
1418 avio_wb64(pb
, av_double2int(track
->par
->sample_rate
));
1419 avio_wb32(pb
, track
->par
->ch_layout
.nb_channels
);
1420 avio_wb32(pb
, 0x7F000000);
1421 avio_wb32(pb
, av_get_bits_per_sample(track
->par
->codec_id
));
1422 avio_wb32(pb
, mov_get_lpcm_flags(track
->par
->codec_id
));
1423 avio_wb32(pb
, track
->sample_size
);
1424 avio_wb32(pb
, get_samples_per_packet(track
));
1426 unsigned sample_rate
= track
->par
->sample_rate
;
1428 if (track
->mode
== MODE_MOV
) {
1429 avio_wb16(pb
, track
->par
->ch_layout
.nb_channels
);
1430 if (track
->par
->codec_id
== AV_CODEC_ID_PCM_U8
||
1431 track
->par
->codec_id
== AV_CODEC_ID_PCM_S8
)
1432 avio_wb16(pb
, 8); /* bits per sample */
1433 else if (track
->par
->codec_id
== AV_CODEC_ID_ADPCM_G726
)
1434 avio_wb16(pb
, track
->par
->bits_per_coded_sample
);
1437 avio_wb16(pb
, track
->audio_vbr
? -2 : 0); /* compression ID */
1438 } else { /* reserved for mp4/3gp */
1439 avio_wb16(pb
, track
->tag
== MKTAG('i', 'a', 'm', 'f') ?
1440 0 : track
->par
->ch_layout
.nb_channels
);
1441 if (track
->par
->codec_id
== AV_CODEC_ID_FLAC
||
1442 track
->par
->codec_id
== AV_CODEC_ID_ALAC
) {
1443 avio_wb16(pb
, track
->par
->bits_per_raw_sample
);
1449 while (sample_rate
> UINT16_MAX
)
1453 avio_wb16(pb
, 0); /* packet size (= 0) */
1454 if (track
->tag
== MKTAG('i','a','m','f'))
1455 avio_wb16(pb
, 0); /* samplerate must be 0 for IAMF */
1456 else if (track
->par
->codec_id
== AV_CODEC_ID_OPUS
)
1457 avio_wb16(pb
, 48000);
1458 else if (track
->par
->codec_id
== AV_CODEC_ID_TRUEHD
)
1459 avio_wb32(pb
, track
->par
->sample_rate
);
1461 avio_wb16(pb
, sample_rate
);
1463 if (track
->par
->codec_id
!= AV_CODEC_ID_TRUEHD
)
1464 avio_wb16(pb
, 0); /* Reserved */
1467 if (track
->mode
== MODE_MOV
&& version
== 1) { /* SoundDescription V1 extended info */
1468 if (mov_pcm_le_gt16(track
->par
->codec_id
) ||
1469 mov_pcm_be_gt16(track
->par
->codec_id
))
1470 avio_wb32(pb
, 1); /* must be 1 for uncompressed formats */
1472 avio_wb32(pb
, track
->par
->frame_size
); /* Samples per packet */
1473 avio_wb32(pb
, track
->sample_size
/ track
->par
->ch_layout
.nb_channels
); /* Bytes per packet */
1474 avio_wb32(pb
, track
->sample_size
); /* Bytes per frame */
1475 avio_wb32(pb
, 2); /* Bytes per sample */
1478 if (track
->mode
== MODE_MOV
&&
1479 (track
->par
->codec_id
== AV_CODEC_ID_AAC
||
1480 track
->par
->codec_id
== AV_CODEC_ID_AC3
||
1481 track
->par
->codec_id
== AV_CODEC_ID_EAC3
||
1482 track
->par
->codec_id
== AV_CODEC_ID_AMR_NB
||
1483 track
->par
->codec_id
== AV_CODEC_ID_ALAC
||
1484 track
->par
->codec_id
== AV_CODEC_ID_ADPCM_MS
||
1485 track
->par
->codec_id
== AV_CODEC_ID_ADPCM_IMA_WAV
||
1486 track
->par
->codec_id
== AV_CODEC_ID_QDM2
||
1487 (mov_pcm_le_gt16(track
->par
->codec_id
) && version
==1) ||
1488 (mov_pcm_be_gt16(track
->par
->codec_id
) && version
==1)))
1489 ret
= mov_write_wave_tag(s
, pb
, track
);
1490 else if (track
->tag
== MKTAG('m','p','4','a'))
1491 ret
= mov_write_esds_tag(pb
, track
);
1493 else if (track
->tag
== MKTAG('i','a','m','f'))
1494 ret
= mov_write_iacb_tag(mov
->fc
, pb
, track
);
1496 else if (track
->par
->codec_id
== AV_CODEC_ID_AMR_NB
)
1497 ret
= mov_write_amr_tag(pb
, track
);
1498 else if (track
->par
->codec_id
== AV_CODEC_ID_AC3
)
1499 ret
= mov_write_ac3_tag(s
, pb
, track
);
1500 else if (track
->par
->codec_id
== AV_CODEC_ID_EAC3
)
1501 ret
= mov_write_eac3_tag(s
, pb
, track
);
1502 else if (track
->par
->codec_id
== AV_CODEC_ID_ALAC
)
1503 ret
= mov_write_extradata_tag(pb
, track
);
1504 else if (track
->par
->codec_id
== AV_CODEC_ID_WMAPRO
)
1505 ret
= mov_write_wfex_tag(s
, pb
, track
);
1506 else if (track
->par
->codec_id
== AV_CODEC_ID_FLAC
)
1507 ret
= mov_write_dfla_tag(pb
, track
);
1508 else if (track
->par
->codec_id
== AV_CODEC_ID_OPUS
)
1509 ret
= mov_write_dops_tag(s
, pb
, track
);
1510 else if (track
->par
->codec_id
== AV_CODEC_ID_TRUEHD
)
1511 ret
= mov_write_dmlp_tag(s
, pb
, track
);
1512 else if (tag
== MOV_MP4_IPCM_TAG
|| tag
== MOV_MP4_FPCM_TAG
) {
1513 if (track
->par
->sample_rate
> UINT16_MAX
)
1514 mov_write_srat_tag(pb
, track
);
1515 if (track
->par
->ch_layout
.nb_channels
> 1)
1516 ret
= mov_write_chnl_tag(s
, pb
, track
);
1519 ret
= mov_write_pcmc_tag(s
, pb
, track
);
1520 } else if (track
->extradata_size
[track
->last_stsd_index
] > 0)
1521 ret
= mov_write_glbl_tag(pb
, track
);
1526 if (track
->mode
== MODE_MP4
&& track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
1527 && ((ret
= mov_write_SA3D_tag(s
, pb
, track
)) < 0)) {
1531 if (track
->mode
== MODE_MOV
&& track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
1532 && ((ret
= mov_write_chan_tag(s
, pb
, track
)) < 0)) {
1536 if (mov
->encryption_scheme
!= MOV_ENC_NONE
1537 && ((ret
= ff_mov_cenc_write_sinf_tag(track
, pb
, mov
->encryption_kid
)) < 0)) {
1541 if (mov
->write_btrt
&&
1542 ((ret
= mov_write_btrt_tag(pb
, track
)) < 0))
1545 if (track
->mode
== MODE_MP4
)
1546 track
->entry_version
= version
;
1548 ret
= update_size(pb
, pos
);
1552 static int mov_write_d263_tag(AVIOContext
*pb
)
1554 avio_wb32(pb
, 0xf); /* size */
1555 ffio_wfourcc(pb
, "d263");
1556 ffio_wfourcc(pb
, "FFMP");
1557 avio_w8(pb
, 0); /* decoder version */
1558 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1559 avio_w8(pb
, 0xa); /* level */
1560 avio_w8(pb
, 0); /* profile */
1564 static int mov_write_av1c_tag(AVIOContext
*pb
, MOVTrack
*track
)
1566 int64_t pos
= avio_tell(pb
);
1569 ffio_wfourcc(pb
, "av1C");
1570 ff_isom_write_av1c(pb
, track
->extradata
[track
->last_stsd_index
],
1571 track
->extradata_size
[track
->last_stsd_index
], track
->mode
!= MODE_AVIF
);
1572 return update_size(pb
, pos
);
1575 static int mov_write_avcc_tag(AVIOContext
*pb
, MOVTrack
*track
)
1577 int64_t pos
= avio_tell(pb
);
1580 ffio_wfourcc(pb
, "avcC");
1581 ff_isom_write_avcc(pb
, track
->extradata
[track
->last_stsd_index
],
1582 track
->extradata_size
[track
->last_stsd_index
]);
1583 return update_size(pb
, pos
);
1586 /* AVS3 Intelligent Media Coding
1587 * Information Technology - Intelligent Media Coding
1588 * Part 6: Intelligent Media Format
1590 static int mov_write_av3c(AVIOContext
*pb
, const uint8_t *data
, int len
)
1593 return AVERROR_INVALIDDATA
;
1596 // In Avs3DecoderConfigurationRecord format
1597 avio_write(pb
, data
, len
);
1601 avio_w8(pb
, 1); // version
1602 avio_wb16(pb
, len
); // sequence_header_length
1603 avio_write(pb
, data
, len
); // sequence_header
1604 avio_w8(pb
, 0xFC); // Only support library_dependency_idc = 0
1609 static int mov_write_av3c_tag(AVIOContext
*pb
, MOVTrack
*track
)
1611 int64_t pos
= avio_tell(pb
);
1613 ffio_wfourcc(pb
, "av3c");
1614 mov_write_av3c(pb
, track
->extradata
[track
->last_stsd_index
],
1615 track
->extradata_size
[track
->last_stsd_index
]);
1616 return update_size(pb
, pos
);
1619 static int mov_write_vpcc_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1621 int64_t pos
= avio_tell(pb
);
1624 ffio_wfourcc(pb
, "vpcC");
1625 ff_isom_write_vpcc(s
, pb
, track
->extradata
[track
->last_stsd_index
],
1626 track
->extradata_size
[track
->last_stsd_index
], track
->par
);
1627 return update_size(pb
, pos
);
1630 static int mov_write_hvcc_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1632 int64_t pos
= avio_tell(pb
);
1635 ffio_wfourcc(pb
, "hvcC");
1636 if (track
->tag
== MKTAG('h','v','c','1'))
1637 ff_isom_write_hvcc(pb
, track
->extradata
[track
->last_stsd_index
],
1638 track
->extradata_size
[track
->last_stsd_index
], 1, s
);
1640 ff_isom_write_hvcc(pb
, track
->extradata
[track
->last_stsd_index
],
1641 track
->extradata_size
[track
->last_stsd_index
], 0, s
);
1642 return update_size(pb
, pos
);
1645 static int mov_write_lhvc_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1647 int64_t pos
= avio_tell(pb
);
1651 ffio_wfourcc(pb
, "lhvC");
1652 if (track
->tag
== MKTAG('h','v','c','1'))
1653 ret
= ff_isom_write_lhvc(pb
, track
->extradata
[track
->last_stsd_index
],
1654 track
->extradata_size
[track
->last_stsd_index
], 1, s
);
1656 ret
= ff_isom_write_lhvc(pb
, track
->extradata
[track
->last_stsd_index
],
1657 track
->extradata_size
[track
->last_stsd_index
], 0, s
);
1660 avio_seek(pb
, pos
, SEEK_SET
);
1664 return update_size(pb
, pos
);
1667 static int mov_write_evcc_tag(AVIOContext
*pb
, MOVTrack
*track
)
1669 int64_t pos
= avio_tell(pb
);
1672 ffio_wfourcc(pb
, "evcC");
1674 if (track
->tag
== MKTAG('e','v','c','1'))
1675 ff_isom_write_evcc(pb
, track
->extradata
[track
->last_stsd_index
],
1676 track
->extradata_size
[track
->last_stsd_index
], 1);
1678 ff_isom_write_evcc(pb
, track
->extradata
[track
->last_stsd_index
],
1679 track
->extradata_size
[track
->last_stsd_index
], 0);
1681 return update_size(pb
, pos
);
1684 static int mov_write_vvcc_tag(AVIOContext
*pb
, MOVTrack
*track
)
1686 int64_t pos
= avio_tell(pb
);
1689 ffio_wfourcc(pb
, "vvcC");
1691 avio_w8 (pb
, 0); /* version */
1692 avio_wb24(pb
, 0); /* flags */
1694 if (track
->tag
== MKTAG('v','v','c','1'))
1695 ff_isom_write_vvcc(pb
, track
->extradata
[track
->last_stsd_index
],
1696 track
->extradata_size
[track
->last_stsd_index
], 1);
1698 ff_isom_write_vvcc(pb
, track
->extradata
[track
->last_stsd_index
],
1699 track
->extradata_size
[track
->last_stsd_index
], 0);
1700 return update_size(pb
, pos
);
1703 static int mov_write_apvc_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
1705 int64_t pos
= avio_tell(pb
);
1708 ffio_wfourcc(pb
, "apvC");
1710 avio_w8 (pb
, 0); /* version */
1711 avio_wb24(pb
, 0); /* flags */
1713 ff_isom_write_apvc(pb
, track
->apv
, s
);
1715 return update_size(pb
, pos
);
1718 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1719 /* https://community.avid.com/forums/t/136517.aspx */
1720 static int mov_write_avid_tag(AVIOContext
*pb
, MOVTrack
*track
)
1724 int display_width
= track
->par
->width
;
1725 const uint8_t *extradata
;
1727 if (track
->extradata
[track
->last_stsd_index
] && track
->extradata_size
[track
->last_stsd_index
] > 0x29) {
1728 if (ff_dnxhd_parse_header_prefix(track
->extradata
[track
->last_stsd_index
]) != 0) {
1729 /* looks like a DNxHD bit stream */
1730 extradata
= track
->extradata
[track
->last_stsd_index
];
1732 av_log(NULL
, AV_LOG_WARNING
, "Could not locate DNxHD bit stream in vos_data\n");
1736 av_log(NULL
, AV_LOG_WARNING
, "Could not locate DNxHD bit stream, vos_data too small\n");
1740 cid
= AV_RB32(extradata
+ 0x28);
1742 avio_wb32(pb
, 24); /* size */
1743 ffio_wfourcc(pb
, "ACLR");
1744 ffio_wfourcc(pb
, "ACLR");
1745 ffio_wfourcc(pb
, "0001");
1746 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1747 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1748 if (track
->par
->color_range
== AVCOL_RANGE_MPEG
|| /* Legal range (16-235) */
1749 track
->par
->color_range
== AVCOL_RANGE_UNSPECIFIED
) {
1754 avio_wb32(pb
, 0); /* reserved */
1756 if (track
->tag
== MKTAG('A','V','d','h')) {
1757 int alp
= extradata
[0x07] & 1;
1758 int pma
= (extradata
[0x07] >> 2) & 1;
1759 int sbd
= (extradata
[0x21] >> 5) & 3;
1760 int ssc
= (extradata
[0x2C] >> 5) & 3;
1761 int clv
= (extradata
[0x2C] >> 1) & 3;
1762 int clf
= extradata
[0x2C] & 1;
1765 ffio_wfourcc(pb
, "ADHR");
1766 ffio_wfourcc(pb
, "0001");
1767 avio_wb32(pb
, cid
); // Compression ID
1768 // 0: 4:2:2 Sub Sampling
1769 // 1: 4:2:0 Sub Sampling
1770 // 2: 4:4:4 Sub Sampling
1771 avio_wb32(pb
, ssc
); // Sub Sampling Control
1772 // 1: 8-bits per sample
1773 // 2: 10-bits per sample
1774 // 3: 12-bits per sample
1775 avio_wb32(pb
, sbd
); // Sample Bit Depth
1776 // 0: Bitstream is encoded using the YCBCR format rules and tables
1777 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1778 avio_wb16(pb
, clf
); // Color Format
1781 // 2: ITU-R BT.2020 C
1783 avio_wb16(pb
, clv
); // Color Volume
1784 // 0: Alpha channel not present
1785 // 1: Alpha channel present
1786 avio_wb16(pb
, alp
); // Alpha Present
1787 // 0: Alpha has not been applied to video channels
1788 // 1: Alpha has been applied to the video channels prior to encoding
1789 avio_wb16(pb
, pma
); // Pre-Multiplied Alpha
1793 interlaced
= extradata
[5] & 2;
1795 avio_wb32(pb
, 24); /* size */
1796 ffio_wfourcc(pb
, "APRG");
1797 ffio_wfourcc(pb
, "APRG");
1798 ffio_wfourcc(pb
, "0001");
1799 // 1 for progressive or 2 for interlaced
1804 avio_wb32(pb
, 0); /* reserved */
1806 avio_wb32(pb
, 120); /* size */
1807 ffio_wfourcc(pb
, "ARES");
1808 ffio_wfourcc(pb
, "ARES");
1809 ffio_wfourcc(pb
, "0001");
1810 avio_wb32(pb
, cid
); /* cid */
1811 if ( track
->par
->sample_aspect_ratio
.num
> 0
1812 && track
->par
->sample_aspect_ratio
.den
> 0)
1813 display_width
= display_width
* track
->par
->sample_aspect_ratio
.num
/ track
->par
->sample_aspect_ratio
.den
;
1814 avio_wb32(pb
, display_width
); // field width
1816 avio_wb32(pb
, track
->par
->height
/ 2); // field height
1817 avio_wb32(pb
, 2); // num fields
1818 avio_wb32(pb
, 0); // num black lines (must be 0)
1822 avio_wb32(pb
, 4); // video format
1824 avio_wb32(pb
, track
->par
->height
);
1825 avio_wb32(pb
, 1); // num fields
1827 if (track
->par
->height
== 1080)
1833 ffio_fill(pb
, 0, 10 * 8);
1838 static int mov_write_dpxe_tag(AVIOContext
*pb
, MOVTrack
*track
)
1841 ffio_wfourcc(pb
, "DpxE");
1842 if (track
->extradata_size
[track
->last_stsd_index
] >= 12 &&
1843 !memcmp(&track
->extradata
[track
->last_stsd_index
][4], "DpxE", 4)) {
1844 avio_wb32(pb
, track
->extradata
[track
->last_stsd_index
][11]);
1851 static int mov_get_dv_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
1855 if (track
->par
->width
== 720) { /* SD */
1856 if (track
->par
->height
== 480) { /* NTSC */
1857 if (track
->par
->format
== AV_PIX_FMT_YUV422P
) tag
= MKTAG('d','v','5','n');
1858 else tag
= MKTAG('d','v','c',' ');
1859 }else if (track
->par
->format
== AV_PIX_FMT_YUV422P
) tag
= MKTAG('d','v','5','p');
1860 else if (track
->par
->format
== AV_PIX_FMT_YUV420P
) tag
= MKTAG('d','v','c','p');
1861 else tag
= MKTAG('d','v','p','p');
1862 } else if (track
->par
->height
== 720) { /* HD 720 line */
1863 if (track
->st
->time_base
.den
== 50) tag
= MKTAG('d','v','h','q');
1864 else tag
= MKTAG('d','v','h','p');
1865 } else if (track
->par
->height
== 1080) { /* HD 1080 line */
1866 if (track
->st
->time_base
.den
== 25) tag
= MKTAG('d','v','h','5');
1867 else tag
= MKTAG('d','v','h','6');
1869 av_log(s
, AV_LOG_ERROR
, "unsupported height for dv codec\n");
1876 static int defined_frame_rate(AVFormatContext
*s
, AVStream
*st
)
1878 AVRational rational_framerate
= st
->avg_frame_rate
;
1880 if (rational_framerate
.den
!= 0)
1881 rate
= av_q2d(rational_framerate
);
1885 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
1887 int tag
= track
->par
->codec_tag
;
1888 int interlaced
= track
->par
->field_order
> AV_FIELD_PROGRESSIVE
;
1889 AVStream
*st
= track
->st
;
1890 int rate
= defined_frame_rate(s
, st
);
1893 tag
= MKTAG('m', '2', 'v', '1'); //fallback tag
1895 if (track
->par
->format
== AV_PIX_FMT_YUV420P
) {
1896 if (track
->par
->width
== 1280 && track
->par
->height
== 720) {
1898 if (rate
== 24) tag
= MKTAG('x','d','v','4');
1899 else if (rate
== 25) tag
= MKTAG('x','d','v','5');
1900 else if (rate
== 30) tag
= MKTAG('x','d','v','1');
1901 else if (rate
== 50) tag
= MKTAG('x','d','v','a');
1902 else if (rate
== 60) tag
= MKTAG('x','d','v','9');
1904 } else if (track
->par
->width
== 1440 && track
->par
->height
== 1080) {
1906 if (rate
== 24) tag
= MKTAG('x','d','v','6');
1907 else if (rate
== 25) tag
= MKTAG('x','d','v','7');
1908 else if (rate
== 30) tag
= MKTAG('x','d','v','8');
1910 if (rate
== 25) tag
= MKTAG('x','d','v','3');
1911 else if (rate
== 30) tag
= MKTAG('x','d','v','2');
1913 } else if (track
->par
->width
== 1920 && track
->par
->height
== 1080) {
1915 if (rate
== 24) tag
= MKTAG('x','d','v','d');
1916 else if (rate
== 25) tag
= MKTAG('x','d','v','e');
1917 else if (rate
== 30) tag
= MKTAG('x','d','v','f');
1919 if (rate
== 25) tag
= MKTAG('x','d','v','c');
1920 else if (rate
== 30) tag
= MKTAG('x','d','v','b');
1923 } else if (track
->par
->format
== AV_PIX_FMT_YUV422P
) {
1924 if (track
->par
->width
== 1280 && track
->par
->height
== 720) {
1926 if (rate
== 24) tag
= MKTAG('x','d','5','4');
1927 else if (rate
== 25) tag
= MKTAG('x','d','5','5');
1928 else if (rate
== 30) tag
= MKTAG('x','d','5','1');
1929 else if (rate
== 50) tag
= MKTAG('x','d','5','a');
1930 else if (rate
== 60) tag
= MKTAG('x','d','5','9');
1932 } else if (track
->par
->width
== 1920 && track
->par
->height
== 1080) {
1934 if (rate
== 24) tag
= MKTAG('x','d','5','d');
1935 else if (rate
== 25) tag
= MKTAG('x','d','5','e');
1936 else if (rate
== 30) tag
= MKTAG('x','d','5','f');
1938 if (rate
== 25) tag
= MKTAG('x','d','5','c');
1939 else if (rate
== 30) tag
= MKTAG('x','d','5','b');
1947 static int mov_get_h264_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
1949 int tag
= track
->par
->codec_tag
;
1950 int interlaced
= track
->par
->field_order
> AV_FIELD_PROGRESSIVE
;
1951 AVStream
*st
= track
->st
;
1952 int rate
= defined_frame_rate(s
, st
);
1955 tag
= MKTAG('a', 'v', 'c', 'i'); //fallback tag
1957 if (track
->par
->profile
== AV_PROFILE_UNKNOWN
||
1958 !(track
->par
->profile
& AV_PROFILE_H264_INTRA
))
1961 if (track
->par
->format
== AV_PIX_FMT_YUV420P10
) {
1962 if (track
->par
->width
== 960 && track
->par
->height
== 720) {
1964 if (rate
== 24) tag
= MKTAG('a','i','5','p');
1965 else if (rate
== 25) tag
= MKTAG('a','i','5','q');
1966 else if (rate
== 30) tag
= MKTAG('a','i','5','p');
1967 else if (rate
== 50) tag
= MKTAG('a','i','5','q');
1968 else if (rate
== 60) tag
= MKTAG('a','i','5','p');
1970 } else if (track
->par
->width
== 1440 && track
->par
->height
== 1080) {
1972 if (rate
== 24) tag
= MKTAG('a','i','5','3');
1973 else if (rate
== 25) tag
= MKTAG('a','i','5','2');
1974 else if (rate
== 30) tag
= MKTAG('a','i','5','3');
1976 if (rate
== 50) tag
= MKTAG('a','i','5','5');
1977 else if (rate
== 60) tag
= MKTAG('a','i','5','6');
1980 } else if (track
->par
->format
== AV_PIX_FMT_YUV422P10
) {
1981 if (track
->par
->width
== 1280 && track
->par
->height
== 720) {
1983 if (rate
== 24) tag
= MKTAG('a','i','1','p');
1984 else if (rate
== 25) tag
= MKTAG('a','i','1','q');
1985 else if (rate
== 30) tag
= MKTAG('a','i','1','p');
1986 else if (rate
== 50) tag
= MKTAG('a','i','1','q');
1987 else if (rate
== 60) tag
= MKTAG('a','i','1','p');
1989 } else if (track
->par
->width
== 1920 && track
->par
->height
== 1080) {
1991 if (rate
== 24) tag
= MKTAG('a','i','1','3');
1992 else if (rate
== 25) tag
= MKTAG('a','i','1','2');
1993 else if (rate
== 30) tag
= MKTAG('a','i','1','3');
1995 if (rate
== 25) tag
= MKTAG('a','i','1','5');
1996 else if (rate
== 50) tag
= MKTAG('a','i','1','5');
1997 else if (rate
== 60) tag
= MKTAG('a','i','1','6');
1999 } else if ( track
->par
->width
== 4096 && track
->par
->height
== 2160
2000 || track
->par
->width
== 3840 && track
->par
->height
== 2160
2001 || track
->par
->width
== 2048 && track
->par
->height
== 1080) {
2002 tag
= MKTAG('a','i','v','x');
2009 static int mov_get_evc_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
2011 int tag
= track
->par
->codec_tag
;
2014 tag
= MKTAG('e', 'v', 'c', '1');
2019 static int mov_get_apv_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
2021 int tag
= track
->par
->codec_tag
;
2024 tag
= MKTAG('a', 'p', 'v', '1');
2030 static const struct {
2031 enum AVPixelFormat pix_fmt
;
2034 } mov_pix_fmt_tags
[] = {
2035 { AV_PIX_FMT_YUYV422
, MKTAG('y','u','v','2'), 0 },
2036 { AV_PIX_FMT_YUYV422
, MKTAG('y','u','v','s'), 0 },
2037 { AV_PIX_FMT_UYVY422
, MKTAG('2','v','u','y'), 0 },
2038 { AV_PIX_FMT_VYU444
, MKTAG('v','3','0','8'), 0 },
2039 { AV_PIX_FMT_UYVA
, MKTAG('v','4','0','8'), 0 },
2040 { AV_PIX_FMT_V30XLE
, MKTAG('v','4','1','0'), 0 },
2041 { AV_PIX_FMT_RGB555BE
,MKTAG('r','a','w',' '), 16 },
2042 { AV_PIX_FMT_RGB555LE
,MKTAG('L','5','5','5'), 16 },
2043 { AV_PIX_FMT_RGB565LE
,MKTAG('L','5','6','5'), 16 },
2044 { AV_PIX_FMT_RGB565BE
,MKTAG('B','5','6','5'), 16 },
2045 { AV_PIX_FMT_GRAY16BE
,MKTAG('b','1','6','g'), 16 },
2046 { AV_PIX_FMT_RGB24
, MKTAG('r','a','w',' '), 24 },
2047 { AV_PIX_FMT_BGR24
, MKTAG('2','4','B','G'), 24 },
2048 { AV_PIX_FMT_ARGB
, MKTAG('r','a','w',' '), 32 },
2049 { AV_PIX_FMT_BGRA
, MKTAG('B','G','R','A'), 32 },
2050 { AV_PIX_FMT_RGBA
, MKTAG('R','G','B','A'), 32 },
2051 { AV_PIX_FMT_ABGR
, MKTAG('A','B','G','R'), 32 },
2052 { AV_PIX_FMT_RGB48BE
, MKTAG('b','4','8','r'), 48 },
2055 static int mov_get_dnxhd_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
2057 int tag
= MKTAG('A','V','d','n');
2058 if (track
->par
->profile
!= AV_PROFILE_UNKNOWN
&&
2059 track
->par
->profile
!= AV_PROFILE_DNXHD
)
2060 tag
= MKTAG('A','V','d','h');
2064 static int mov_get_rawvideo_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
2066 int tag
= track
->par
->codec_tag
;
2068 enum AVPixelFormat pix_fmt
;
2070 for (i
= 0; i
< FF_ARRAY_ELEMS(mov_pix_fmt_tags
); i
++) {
2071 if (track
->par
->format
== mov_pix_fmt_tags
[i
].pix_fmt
) {
2072 tag
= mov_pix_fmt_tags
[i
].tag
;
2073 track
->par
->bits_per_coded_sample
= mov_pix_fmt_tags
[i
].bps
;
2074 if (track
->par
->codec_tag
== mov_pix_fmt_tags
[i
].tag
)
2079 pix_fmt
= avpriv_pix_fmt_find(PIX_FMT_LIST_MOV
,
2080 track
->par
->bits_per_coded_sample
);
2081 if (tag
== MKTAG('r','a','w',' ') &&
2082 track
->par
->format
!= pix_fmt
&&
2083 track
->par
->format
!= AV_PIX_FMT_GRAY8
&&
2084 track
->par
->format
!= AV_PIX_FMT_NONE
)
2085 av_log(s
, AV_LOG_ERROR
, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2086 av_get_pix_fmt_name(track
->par
->format
));
2090 static unsigned int mov_get_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
2092 unsigned int tag
= track
->par
->codec_tag
;
2094 // "rtp " is used to distinguish internally created RTP-hint tracks
2095 // (with rtp_ctx) from other tracks.
2096 if (tag
== MKTAG('r','t','p',' '))
2098 if (!tag
|| (s
->strict_std_compliance
>= FF_COMPLIANCE_NORMAL
&&
2099 (track
->par
->codec_id
== AV_CODEC_ID_DVVIDEO
||
2100 track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
||
2101 track
->par
->codec_id
== AV_CODEC_ID_H263
||
2102 track
->par
->codec_id
== AV_CODEC_ID_H264
||
2103 track
->par
->codec_id
== AV_CODEC_ID_DNXHD
||
2104 track
->par
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
||
2105 av_get_bits_per_sample(track
->par
->codec_id
)))) { // pcm audio
2106 if (track
->par
->codec_id
== AV_CODEC_ID_DVVIDEO
)
2107 tag
= mov_get_dv_codec_tag(s
, track
);
2108 else if (track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
)
2109 tag
= mov_get_rawvideo_codec_tag(s
, track
);
2110 else if (track
->par
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
)
2111 tag
= mov_get_mpeg2_xdcam_codec_tag(s
, track
);
2112 else if (track
->par
->codec_id
== AV_CODEC_ID_H264
)
2113 tag
= mov_get_h264_codec_tag(s
, track
);
2114 else if (track
->par
->codec_id
== AV_CODEC_ID_EVC
)
2115 tag
= mov_get_evc_codec_tag(s
, track
);
2116 else if (track
->par
->codec_id
== AV_CODEC_ID_APV
)
2117 tag
= mov_get_apv_codec_tag(s
, track
);
2118 else if (track
->par
->codec_id
== AV_CODEC_ID_DNXHD
)
2119 tag
= mov_get_dnxhd_codec_tag(s
, track
);
2120 else if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
2121 tag
= ff_codec_get_tag(ff_codec_movvideo_tags
, track
->par
->codec_id
);
2122 if (!tag
) { // if no mac fcc found, try with Microsoft tags
2123 tag
= ff_codec_get_tag(ff_codec_bmp_tags
, track
->par
->codec_id
);
2125 av_log(s
, AV_LOG_WARNING
, "Using MS style video codec tag, "
2126 "the file may be unplayable!\n");
2128 } else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
2129 tag
= ff_codec_get_tag(ff_codec_movaudio_tags
, track
->par
->codec_id
);
2130 if (!tag
) { // if no mac fcc found, try with Microsoft tags
2131 int ms_tag
= ff_codec_get_tag(ff_codec_wav_tags
, track
->par
->codec_id
);
2133 tag
= MKTAG('m', 's', ((ms_tag
>> 8) & 0xff), (ms_tag
& 0xff));
2134 av_log(s
, AV_LOG_WARNING
, "Using MS style audio codec tag, "
2135 "the file may be unplayable!\n");
2138 } else if (track
->par
->codec_type
== AVMEDIA_TYPE_SUBTITLE
)
2139 tag
= ff_codec_get_tag(ff_codec_movsubtitle_tags
, track
->par
->codec_id
);
2145 static const AVCodecTag codec_cover_image_tags
[] = {
2146 { AV_CODEC_ID_MJPEG
, 0xD },
2147 { AV_CODEC_ID_PNG
, 0xE },
2148 { AV_CODEC_ID_BMP
, 0x1B },
2149 { AV_CODEC_ID_NONE
, 0 },
2152 static unsigned int validate_codec_tag(const AVCodecTag
*const *tags
,
2153 unsigned int tag
, int codec_id
)
2158 * Check that tag + id is in the table
2160 for (i
= 0; tags
&& tags
[i
]; i
++) {
2161 const AVCodecTag
*codec_tags
= tags
[i
];
2162 while (codec_tags
->id
!= AV_CODEC_ID_NONE
) {
2163 if (ff_toupper4(codec_tags
->tag
) == ff_toupper4(tag
) &&
2164 codec_tags
->id
== codec_id
)
2165 return codec_tags
->tag
;
2172 static unsigned int mov_find_codec_tag(AVFormatContext
*s
, MOVTrack
*track
)
2174 if (is_cover_image(track
->st
))
2175 return ff_codec_get_tag(codec_cover_image_tags
, track
->par
->codec_id
);
2177 if (track
->mode
== MODE_IPOD
)
2178 if (!av_match_ext(s
->url
, "m4a") &&
2179 !av_match_ext(s
->url
, "m4v") &&
2180 !av_match_ext(s
->url
, "m4b"))
2181 av_log(s
, AV_LOG_WARNING
, "Warning, extension is not .m4a nor .m4v "
2182 "Quicktime/Ipod might not play the file\n");
2184 if (track
->mode
== MODE_MOV
) {
2185 return mov_get_codec_tag(s
, track
);
2187 return validate_codec_tag(s
->oformat
->codec_tag
, track
->par
->codec_tag
,
2188 track
->par
->codec_id
);
2191 /** Write uuid atom.
2192 * Needed to make file play in iPods running newest firmware
2193 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2195 static int mov_write_uuid_tag_ipod(AVIOContext
*pb
)
2198 ffio_wfourcc(pb
, "uuid");
2199 avio_wb32(pb
, 0x6b6840f2);
2200 avio_wb32(pb
, 0x5f244fc5);
2201 avio_wb32(pb
, 0xba39a51b);
2202 avio_wb32(pb
, 0xcf0323f3);
2207 static const uint16_t fiel_data
[] = {
2208 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2211 static int mov_write_fiel_tag(AVIOContext
*pb
, MOVTrack
*track
, int field_order
)
2213 unsigned mov_field_order
= 0;
2214 if (field_order
< FF_ARRAY_ELEMS(fiel_data
))
2215 mov_field_order
= fiel_data
[field_order
];
2219 ffio_wfourcc(pb
, "fiel");
2220 avio_wb16(pb
, mov_field_order
);
2224 static int mov_write_subtitle_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
2226 MOVMuxContext
*mov
= s
->priv_data
;
2227 int ret
= AVERROR_BUG
;
2228 int64_t pos
= avio_tell(pb
);
2229 avio_wb32(pb
, 0); /* size */
2230 avio_wl32(pb
, track
->tag
); // store it byteswapped
2231 avio_wb32(pb
, 0); /* Reserved */
2232 avio_wb16(pb
, 0); /* Reserved */
2233 avio_wb16(pb
, 1); /* Data-reference index */
2235 if (track
->par
->codec_id
== AV_CODEC_ID_DVD_SUBTITLE
)
2236 mov_write_esds_tag(pb
, track
);
2237 else if (track
->par
->codec_id
== AV_CODEC_ID_TTML
) {
2238 switch (track
->par
->codec_tag
) {
2239 case MOV_ISMV_TTML_TAG
:
2240 // ISMV dfxp requires no extradata.
2242 case MOV_MP4_TTML_TAG
:
2243 // As specified in 14496-30, XMLSubtitleSampleEntry
2245 avio_put_str(pb
, "http://www.w3.org/ns/ttml");
2246 // Empty schema_location
2248 // Empty auxiliary_mime_types
2252 av_log(NULL
, AV_LOG_ERROR
,
2253 "Unknown codec tag '%s' utilized for TTML stream with "
2254 "index %d (track id %d)!\n",
2255 av_fourcc2str(track
->par
->codec_tag
), track
->st
->index
,
2257 return AVERROR(EINVAL
);
2259 } else if (track
->extradata_size
[track
->last_stsd_index
])
2260 avio_write(pb
, track
->extradata
[track
->last_stsd_index
], track
->extradata_size
[track
->last_stsd_index
]);
2262 if (mov
->write_btrt
&&
2263 ((ret
= mov_write_btrt_tag(pb
, track
)) < 0))
2266 return update_size(pb
, pos
);
2269 static int mov_write_st3d_tag(AVFormatContext
*s
, AVIOContext
*pb
, AVStereo3D
*stereo_3d
)
2273 if (stereo_3d
->flags
!= 0) {
2274 av_log(s
, AV_LOG_WARNING
, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d
->flags
);
2278 switch (stereo_3d
->type
) {
2279 case AV_STEREO3D_2D
:
2282 case AV_STEREO3D_TOPBOTTOM
:
2285 case AV_STEREO3D_SIDEBYSIDE
:
2289 av_log(s
, AV_LOG_WARNING
, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d
->type
));
2292 avio_wb32(pb
, 13); /* size */
2293 ffio_wfourcc(pb
, "st3d");
2294 avio_wb32(pb
, 0); /* version = 0 & flags = 0 */
2295 avio_w8(pb
, stereo_mode
);
2299 static int mov_write_sv3d_tag(AVFormatContext
*s
, AVIOContext
*pb
, AVSphericalMapping
*spherical_mapping
)
2301 int64_t sv3d_pos
, svhd_pos
, proj_pos
;
2302 const char* metadata_source
= s
->flags
& AVFMT_FLAG_BITEXACT
? "Lavf" : LIBAVFORMAT_IDENT
;
2304 if (spherical_mapping
->projection
!= AV_SPHERICAL_EQUIRECTANGULAR
&&
2305 spherical_mapping
->projection
!= AV_SPHERICAL_EQUIRECTANGULAR_TILE
&&
2306 spherical_mapping
->projection
!= AV_SPHERICAL_CUBEMAP
) {
2307 av_log(s
, AV_LOG_WARNING
, "Unsupported projection %d. sv3d not written.\n", spherical_mapping
->projection
);
2311 sv3d_pos
= avio_tell(pb
);
2312 avio_wb32(pb
, 0); /* size */
2313 ffio_wfourcc(pb
, "sv3d");
2315 svhd_pos
= avio_tell(pb
);
2316 avio_wb32(pb
, 0); /* size */
2317 ffio_wfourcc(pb
, "svhd");
2318 avio_wb32(pb
, 0); /* version = 0 & flags = 0 */
2319 avio_put_str(pb
, metadata_source
);
2320 update_size(pb
, svhd_pos
);
2322 proj_pos
= avio_tell(pb
);
2323 avio_wb32(pb
, 0); /* size */
2324 ffio_wfourcc(pb
, "proj");
2326 avio_wb32(pb
, 24); /* size */
2327 ffio_wfourcc(pb
, "prhd");
2328 avio_wb32(pb
, 0); /* version = 0 & flags = 0 */
2329 avio_wb32(pb
, spherical_mapping
->yaw
);
2330 avio_wb32(pb
, spherical_mapping
->pitch
);
2331 avio_wb32(pb
, spherical_mapping
->roll
);
2333 switch (spherical_mapping
->projection
) {
2334 case AV_SPHERICAL_EQUIRECTANGULAR
:
2335 case AV_SPHERICAL_EQUIRECTANGULAR_TILE
:
2336 avio_wb32(pb
, 28); /* size */
2337 ffio_wfourcc(pb
, "equi");
2338 avio_wb32(pb
, 0); /* version = 0 & flags = 0 */
2339 avio_wb32(pb
, spherical_mapping
->bound_top
);
2340 avio_wb32(pb
, spherical_mapping
->bound_bottom
);
2341 avio_wb32(pb
, spherical_mapping
->bound_left
);
2342 avio_wb32(pb
, spherical_mapping
->bound_right
);
2344 case AV_SPHERICAL_CUBEMAP
:
2345 avio_wb32(pb
, 20); /* size */
2346 ffio_wfourcc(pb
, "cbmp");
2347 avio_wb32(pb
, 0); /* version = 0 & flags = 0 */
2348 avio_wb32(pb
, 0); /* layout */
2349 avio_wb32(pb
, spherical_mapping
->padding
); /* padding */
2352 update_size(pb
, proj_pos
);
2354 return update_size(pb
, sv3d_pos
);
2357 static inline int64_t rescale_rational(AVRational q
, int b
)
2359 return av_rescale(q
.num
, b
, q
.den
);
2362 static void mov_write_hfov_tag(AVFormatContext
*s
, AVIOContext
*pb
,
2363 const AVStereo3D
*stereo3d
)
2365 if (!stereo3d
->horizontal_field_of_view
.num
)
2368 avio_wb32(pb
, 12); /* size */
2369 ffio_wfourcc(pb
, "hfov");
2370 avio_wb32(pb
, rescale_rational(stereo3d
->horizontal_field_of_view
, 1000));
2373 static void mov_write_vexu_proj_tag(AVFormatContext
*s
, AVIOContext
*pb
,
2374 const AVSphericalMapping
*spherical_mapping
)
2376 avio_wb32(pb
, 24); /* size */
2377 ffio_wfourcc(pb
, "proj");
2378 avio_wb32(pb
, 16); /* size */
2379 ffio_wfourcc(pb
, "prji");
2380 avio_wb32(pb
, 0); /* version + flags */
2382 switch (spherical_mapping
->projection
) {
2383 case AV_SPHERICAL_RECTILINEAR
:
2384 ffio_wfourcc(pb
, "rect");
2386 case AV_SPHERICAL_EQUIRECTANGULAR
:
2387 ffio_wfourcc(pb
, "equi");
2389 case AV_SPHERICAL_HALF_EQUIRECTANGULAR
:
2390 ffio_wfourcc(pb
, "hequ");
2392 case AV_SPHERICAL_FISHEYE
:
2393 ffio_wfourcc(pb
, "fish");
2400 static int mov_write_eyes_tag(AVFormatContext
*s
, AVIOContext
*pb
,
2401 const AVStereo3D
*stereo3d
)
2403 int64_t pos
= avio_tell(pb
);
2406 avio_wb32(pb
, 0); /* size */
2407 ffio_wfourcc(pb
, "eyes");
2409 // stri is mandatory
2410 avio_wb32(pb
, 13); /* size */
2411 ffio_wfourcc(pb
, "stri");
2412 avio_wb32(pb
, 0); /* version + flags */
2413 switch (stereo3d
->view
) {
2414 case AV_STEREO3D_VIEW_LEFT
:
2417 case AV_STEREO3D_VIEW_RIGHT
:
2420 case AV_STEREO3D_VIEW_PACKED
:
2421 view
|= (1 << 0) | (1 << 1);
2424 view
|= !!(stereo3d
->flags
& AV_STEREO3D_FLAG_INVERT
) << 3;
2428 if (stereo3d
->primary_eye
!= AV_PRIMARY_EYE_NONE
) {
2429 avio_wb32(pb
, 13); /* size */
2430 ffio_wfourcc(pb
, "hero");
2431 avio_wb32(pb
, 0); /* version + flags */
2432 avio_w8(pb
, stereo3d
->primary_eye
);
2435 // it's not clear if cams is mandatory or optional
2436 if (stereo3d
->baseline
) {
2437 avio_wb32(pb
, 24); /* size */
2438 ffio_wfourcc(pb
, "cams");
2439 avio_wb32(pb
, 16); /* size */
2440 ffio_wfourcc(pb
, "blin");
2441 avio_wb32(pb
, 0); /* version + flags */
2442 avio_wb32(pb
, stereo3d
->baseline
);
2445 // it's not clear if cmfy is mandatory or optional
2446 if (stereo3d
->horizontal_disparity_adjustment
.num
) {
2447 avio_wb32(pb
, 24); /* size */
2448 ffio_wfourcc(pb
, "cmfy");
2449 avio_wb32(pb
, 16); /* size */
2450 ffio_wfourcc(pb
, "dadj");
2451 avio_wb32(pb
, 0); /* version + flags */
2452 avio_wb32(pb
, rescale_rational(stereo3d
->horizontal_disparity_adjustment
, 10000));
2455 return update_size(pb
, pos
);
2458 static int mov_write_vexu_tag(AVFormatContext
*s
, AVIOContext
*pb
,
2459 const AVStereo3D
*stereo3d
,
2460 const AVSphericalMapping
*spherical_mapping
)
2464 if (spherical_mapping
&&
2465 spherical_mapping
->projection
!= AV_SPHERICAL_RECTILINEAR
&&
2466 spherical_mapping
->projection
!= AV_SPHERICAL_EQUIRECTANGULAR
&&
2467 spherical_mapping
->projection
!= AV_SPHERICAL_HALF_EQUIRECTANGULAR
&&
2468 spherical_mapping
->projection
!= AV_SPHERICAL_FISHEYE
) {
2469 av_log(s
, AV_LOG_WARNING
, "Unsupported projection %d. proj not written.\n",
2470 spherical_mapping
->projection
);
2471 spherical_mapping
= NULL
;
2474 if (stereo3d
&& (stereo3d
->type
== AV_STEREO3D_2D
||
2475 (!(stereo3d
->flags
& AV_STEREO3D_FLAG_INVERT
) &&
2476 stereo3d
->view
== AV_STEREO3D_VIEW_UNSPEC
&&
2477 stereo3d
->primary_eye
== AV_PRIMARY_EYE_NONE
&&
2478 !stereo3d
->baseline
&&
2479 !stereo3d
->horizontal_disparity_adjustment
.num
))) {
2480 av_log(s
, AV_LOG_WARNING
, "Unsupported stereo 3d metadata. eyes not written.\n");
2484 if (!spherical_mapping
&& !stereo3d
)
2487 pos
= avio_tell(pb
);
2488 avio_wb32(pb
, 0); /* size */
2489 ffio_wfourcc(pb
, "vexu");
2491 if (spherical_mapping
)
2492 mov_write_vexu_proj_tag(s
, pb
, spherical_mapping
);
2495 mov_write_eyes_tag(s
, pb
, stereo3d
);
2497 return update_size(pb
, pos
);
2500 static int mov_write_dvcc_dvvc_tag(AVFormatContext
*s
, AVIOContext
*pb
, AVDOVIDecoderConfigurationRecord
*dovi
)
2502 uint8_t buf
[ISOM_DVCC_DVVC_SIZE
];
2504 avio_wb32(pb
, 32); /* size = 8 + 24 */
2505 if (dovi
->dv_profile
> 10)
2506 ffio_wfourcc(pb
, "dvwC");
2507 else if (dovi
->dv_profile
> 7)
2508 ffio_wfourcc(pb
, "dvvC");
2510 ffio_wfourcc(pb
, "dvcC");
2512 ff_isom_put_dvcc_dvvc(s
, buf
, dovi
);
2513 avio_write(pb
, buf
, sizeof(buf
));
2515 return 32; /* 8 + 24 */
2518 static int mov_write_clap_tag(AVIOContext
*pb
, MOVTrack
*track
,
2519 uint32_t top
, uint32_t bottom
,
2520 uint32_t left
, uint32_t right
)
2522 uint32_t cropped_width
= track
->par
->width
- left
- right
;
2523 uint32_t cropped_height
= track
->height
- top
- bottom
;
2524 AVRational horizOff
=
2525 av_sub_q((AVRational
) { track
->par
->width
- cropped_width
, 2 },
2526 (AVRational
) { left
, 1 });
2527 AVRational vertOff
=
2528 av_sub_q((AVRational
) { track
->height
- cropped_height
, 2 },
2529 (AVRational
) { top
, 1 });
2532 ffio_wfourcc(pb
, "clap");
2533 avio_wb32(pb
, cropped_width
); /* apertureWidthN */
2534 avio_wb32(pb
, 1); /* apertureWidthD */
2535 avio_wb32(pb
, cropped_height
); /* apertureHeightN */
2536 avio_wb32(pb
, 1); /* apertureHeightD */
2538 avio_wb32(pb
, -horizOff
.num
);
2539 avio_wb32(pb
, horizOff
.den
);
2540 avio_wb32(pb
, -vertOff
.num
);
2541 avio_wb32(pb
, vertOff
.den
);
2546 static int mov_write_pasp_tag(AVIOContext
*pb
, MOVTrack
*track
)
2549 av_reduce(&sar
.num
, &sar
.den
, track
->par
->sample_aspect_ratio
.num
,
2550 track
->par
->sample_aspect_ratio
.den
, INT_MAX
);
2553 ffio_wfourcc(pb
, "pasp");
2554 avio_wb32(pb
, sar
.num
);
2555 avio_wb32(pb
, sar
.den
);
2559 static int mov_write_gama_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
, double gamma
)
2563 gamma
= av_csp_approximate_eotf_gamma(track
->par
->color_trc
);
2564 av_log(s
, AV_LOG_DEBUG
, "gamma value %g\n", gamma
);
2567 gama
= (uint32_t)lrint((double)(1<<16) * gamma
);
2568 av_log(s
, AV_LOG_DEBUG
, "writing gama value %"PRId32
"\n", gama
);
2570 av_assert0(track
->mode
== MODE_MOV
);
2572 ffio_wfourcc(pb
, "gama");
2573 avio_wb32(pb
, gama
);
2576 av_log(s
, AV_LOG_WARNING
, "gamma value unknown, unable to write gama atom\n");
2581 static int mov_write_colr_tag(AVIOContext
*pb
, MOVTrack
*track
, int prefer_icc
)
2583 int64_t pos
= avio_tell(pb
);
2585 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2586 // Ref (MP4): ISO/IEC 14496-12:2012
2589 const AVPacketSideData
*sd
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2590 track
->st
->codecpar
->nb_coded_side_data
,
2591 AV_PKT_DATA_ICC_PROFILE
);
2594 avio_wb32(pb
, 12 + sd
->size
);
2595 ffio_wfourcc(pb
, "colr");
2596 ffio_wfourcc(pb
, "prof");
2597 avio_write(pb
, sd
->data
, sd
->size
);
2598 return 12 + sd
->size
;
2601 av_log(NULL
, AV_LOG_INFO
, "no ICC profile found, will write nclx/nclc colour info instead\n");
2605 /* We should only ever be called for MOV, MP4 and AVIF. */
2606 av_assert0(track
->mode
== MODE_MOV
|| track
->mode
== MODE_MP4
||
2607 track
->mode
== MODE_AVIF
);
2609 avio_wb32(pb
, 0); /* size */
2610 ffio_wfourcc(pb
, "colr");
2611 if (track
->mode
== MODE_MP4
|| track
->mode
== MODE_AVIF
)
2612 ffio_wfourcc(pb
, "nclx");
2614 ffio_wfourcc(pb
, "nclc");
2615 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2616 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2617 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2618 avio_wb16(pb
, track
->par
->color_primaries
);
2619 avio_wb16(pb
, track
->par
->color_trc
);
2620 avio_wb16(pb
, track
->par
->color_space
);
2621 if (track
->mode
== MODE_MP4
|| track
->mode
== MODE_AVIF
) {
2622 int full_range
= track
->par
->color_range
== AVCOL_RANGE_JPEG
;
2623 avio_w8(pb
, full_range
<< 7);
2626 return update_size(pb
, pos
);
2629 static int mov_write_clli_tag(AVIOContext
*pb
, MOVTrack
*track
)
2631 const AVPacketSideData
*side_data
;
2632 const AVContentLightMetadata
*content_light_metadata
;
2634 side_data
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2635 track
->st
->codecpar
->nb_coded_side_data
,
2636 AV_PKT_DATA_CONTENT_LIGHT_LEVEL
);
2640 content_light_metadata
= (const AVContentLightMetadata
*)side_data
->data
;
2642 avio_wb32(pb
, 12); // size
2643 ffio_wfourcc(pb
, "clli");
2644 avio_wb16(pb
, content_light_metadata
->MaxCLL
);
2645 avio_wb16(pb
, content_light_metadata
->MaxFALL
);
2649 static int mov_write_mdcv_tag(AVIOContext
*pb
, MOVTrack
*track
)
2651 const int chroma_den
= 50000;
2652 const int luma_den
= 10000;
2653 const AVPacketSideData
*side_data
;
2654 const AVMasteringDisplayMetadata
*metadata
= NULL
;
2656 side_data
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2657 track
->st
->codecpar
->nb_coded_side_data
,
2658 AV_PKT_DATA_MASTERING_DISPLAY_METADATA
);
2660 metadata
= (const AVMasteringDisplayMetadata
*)side_data
->data
;
2661 if (!metadata
|| !metadata
->has_primaries
|| !metadata
->has_luminance
) {
2665 avio_wb32(pb
, 32); // size
2666 ffio_wfourcc(pb
, "mdcv");
2667 avio_wb16(pb
, rescale_rational(metadata
->display_primaries
[1][0], chroma_den
));
2668 avio_wb16(pb
, rescale_rational(metadata
->display_primaries
[1][1], chroma_den
));
2669 avio_wb16(pb
, rescale_rational(metadata
->display_primaries
[2][0], chroma_den
));
2670 avio_wb16(pb
, rescale_rational(metadata
->display_primaries
[2][1], chroma_den
));
2671 avio_wb16(pb
, rescale_rational(metadata
->display_primaries
[0][0], chroma_den
));
2672 avio_wb16(pb
, rescale_rational(metadata
->display_primaries
[0][1], chroma_den
));
2673 avio_wb16(pb
, rescale_rational(metadata
->white_point
[0], chroma_den
));
2674 avio_wb16(pb
, rescale_rational(metadata
->white_point
[1], chroma_den
));
2675 avio_wb32(pb
, rescale_rational(metadata
->max_luminance
, luma_den
));
2676 avio_wb32(pb
, rescale_rational(metadata
->min_luminance
, luma_den
));
2680 static int mov_write_amve_tag(AVIOContext
*pb
, MOVTrack
*track
)
2682 const int illuminance_den
= 10000;
2683 const int ambient_den
= 50000;
2684 const AVPacketSideData
*side_data
;
2685 const AVAmbientViewingEnvironment
*ambient
;
2688 side_data
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2689 track
->st
->codecpar
->nb_coded_side_data
,
2690 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT
);
2695 ambient
= (const AVAmbientViewingEnvironment
*)side_data
->data
;
2696 if (!ambient
|| !ambient
->ambient_illuminance
.num
)
2699 avio_wb32(pb
, 16); // size
2700 ffio_wfourcc(pb
, "amve");
2701 avio_wb32(pb
, rescale_rational(ambient
->ambient_illuminance
, illuminance_den
));
2702 avio_wb16(pb
, rescale_rational(ambient
->ambient_light_x
, ambient_den
));
2703 avio_wb16(pb
, rescale_rational(ambient
->ambient_light_y
, ambient_den
));
2707 static void find_compressor(char * compressor_name
, int len
, MOVTrack
*track
)
2709 AVDictionaryEntry
*encoder
;
2710 int xdcam_res
= (track
->par
->width
== 1280 && track
->par
->height
== 720)
2711 || (track
->par
->width
== 1440 && track
->par
->height
== 1080)
2712 || (track
->par
->width
== 1920 && track
->par
->height
== 1080);
2714 if ((track
->mode
== MODE_AVIF
||
2715 track
->mode
== MODE_MOV
||
2716 track
->mode
== MODE_MP4
) &&
2717 (encoder
= av_dict_get(track
->st
->metadata
, "encoder", NULL
, 0))) {
2718 av_strlcpy(compressor_name
, encoder
->value
, 32);
2719 } else if (track
->par
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
&& xdcam_res
) {
2720 int interlaced
= track
->par
->field_order
> AV_FIELD_PROGRESSIVE
;
2721 AVStream
*st
= track
->st
;
2722 int rate
= defined_frame_rate(NULL
, st
);
2723 av_strlcatf(compressor_name
, len
, "XDCAM");
2724 if (track
->par
->format
== AV_PIX_FMT_YUV422P
) {
2725 av_strlcatf(compressor_name
, len
, " HD422");
2726 } else if(track
->par
->width
== 1440) {
2727 av_strlcatf(compressor_name
, len
, " HD");
2729 av_strlcatf(compressor_name
, len
, " EX");
2731 av_strlcatf(compressor_name
, len
, " %d%c", track
->par
->height
, interlaced
? 'i' : 'p');
2733 av_strlcatf(compressor_name
, len
, "%d", rate
* (interlaced
+ 1));
2737 static int mov_write_ccst_tag(AVIOContext
*pb
)
2739 int64_t pos
= avio_tell(pb
);
2740 // Write sane defaults:
2741 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2742 // intra_pred_used = 1 : intra prediction may or may not be used.
2743 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2744 // reference images can be used.
2745 uint8_t ccstValue
= (0 << 7) | /* all_ref_pics_intra */
2746 (1 << 6) | /* intra_pred_used */
2747 (15 << 2); /* max_ref_per_pic */
2748 avio_wb32(pb
, 0); /* size */
2749 ffio_wfourcc(pb
, "ccst");
2750 avio_wb32(pb
, 0); /* Version & flags */
2751 avio_w8(pb
, ccstValue
);
2752 avio_wb24(pb
, 0); /* reserved */
2753 return update_size(pb
, pos
);
2756 static int mov_write_aux_tag(AVIOContext
*pb
, const char *aux_type
)
2758 int64_t pos
= avio_tell(pb
);
2759 avio_wb32(pb
, 0); /* size */
2760 ffio_wfourcc(pb
, aux_type
);
2761 avio_wb32(pb
, 0); /* Version & flags */
2762 avio_write(pb
, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2763 return update_size(pb
, pos
);
2766 static int mov_write_video_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVMuxContext
*mov
, MOVTrack
*track
)
2768 int ret
= AVERROR_BUG
;
2769 int64_t pos
= avio_tell(pb
);
2770 const AVPacketSideData
*sd
;
2771 char compressor_name
[32] = { 0 };
2774 int uncompressed_ycbcr
= ((track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&& track
->par
->format
== AV_PIX_FMT_UYVY422
)
2775 || (track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&& track
->par
->format
== AV_PIX_FMT_YUYV422
)
2776 || (track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&& track
->par
->format
== AV_PIX_FMT_VYU444
)
2777 || (track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&& track
->par
->format
== AV_PIX_FMT_UYVA
)
2778 || (track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&& track
->par
->format
== AV_PIX_FMT_V30XLE
)
2779 #if FF_API_V408_CODECID
2780 || track
->par
->codec_id
== AV_CODEC_ID_V308
2781 || track
->par
->codec_id
== AV_CODEC_ID_V408
2782 || track
->par
->codec_id
== AV_CODEC_ID_V410
2784 || track
->par
->codec_id
== AV_CODEC_ID_V210
);
2786 avio_wb32(pb
, 0); /* size */
2787 if (mov
->encryption_scheme
!= MOV_ENC_NONE
) {
2788 ffio_wfourcc(pb
, "encv");
2790 avio_wl32(pb
, track
->tag
); // store it byteswapped
2792 avio_wb32(pb
, 0); /* Reserved */
2793 avio_wb16(pb
, 0); /* Reserved */
2794 avio_wb16(pb
, 1); /* Data-reference index */
2796 if (uncompressed_ycbcr
) {
2797 avio_wb16(pb
, 2); /* Codec stream version */
2799 avio_wb16(pb
, 0); /* Codec stream version */
2801 avio_wb16(pb
, 0); /* Codec stream revision (=0) */
2802 if (track
->mode
== MODE_MOV
) {
2803 ffio_wfourcc(pb
, "FFMP"); /* Vendor */
2804 if (track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
|| uncompressed_ycbcr
) {
2805 avio_wb32(pb
, 0); /* Temporal Quality */
2806 avio_wb32(pb
, 0x400); /* Spatial Quality = lossless*/
2808 avio_wb32(pb
, 0x200); /* Temporal Quality = normal */
2809 avio_wb32(pb
, 0x200); /* Spatial Quality = normal */
2812 ffio_fill(pb
, 0, 3 * 4); /* Reserved */
2814 avio_wb16(pb
, track
->par
->width
); /* Video width */
2815 avio_wb16(pb
, track
->height
); /* Video height */
2816 avio_wb32(pb
, 0x00480000); /* Horizontal resolution 72dpi */
2817 avio_wb32(pb
, 0x00480000); /* Vertical resolution 72dpi */
2818 avio_wb32(pb
, 0); /* Data size (= 0) */
2819 avio_wb16(pb
, 1); /* Frame count (= 1) */
2821 find_compressor(compressor_name
, 32, track
);
2822 avio_w8(pb
, strlen(compressor_name
));
2823 avio_write(pb
, compressor_name
, 31);
2825 if (track
->mode
== MODE_MOV
&&
2826 (track
->par
->codec_id
== AV_CODEC_ID_V410
|| track
->par
->codec_id
== AV_CODEC_ID_V210
))
2827 avio_wb16(pb
, 0x18);
2828 else if (track
->mode
== MODE_MOV
&& track
->par
->bits_per_coded_sample
)
2829 avio_wb16(pb
, track
->par
->bits_per_coded_sample
|
2830 (track
->par
->format
== AV_PIX_FMT_GRAY8
? 0x20 : 0));
2832 avio_wb16(pb
, 0x18); /* Reserved */
2834 if (track
->mode
== MODE_MOV
&& track
->par
->format
== AV_PIX_FMT_PAL8
) {
2836 avio_wb16(pb
, 0); /* Color table ID */
2837 avio_wb32(pb
, 0); /* Color table seed */
2838 avio_wb16(pb
, 0x8000); /* Color table flags */
2839 if (track
->par
->bits_per_coded_sample
< 0 || track
->par
->bits_per_coded_sample
> 8)
2840 return AVERROR(EINVAL
);
2841 pal_size
= 1 << track
->par
->bits_per_coded_sample
;
2842 avio_wb16(pb
, pal_size
- 1); /* Color table size (zero-relative) */
2843 for (i
= 0; i
< pal_size
; i
++) {
2844 uint32_t rgb
= track
->palette
[i
];
2845 uint16_t r
= (rgb
>> 16) & 0xff;
2846 uint16_t g
= (rgb
>> 8) & 0xff;
2847 uint16_t b
= rgb
& 0xff;
2849 avio_wb16(pb
, (r
<< 8) | r
);
2850 avio_wb16(pb
, (g
<< 8) | g
);
2851 avio_wb16(pb
, (b
<< 8) | b
);
2854 avio_wb16(pb
, 0xffff); /* Reserved */
2856 if (track
->tag
== MKTAG('m','p','4','v'))
2857 mov_write_esds_tag(pb
, track
);
2858 else if (track
->par
->codec_id
== AV_CODEC_ID_H263
)
2859 mov_write_d263_tag(pb
);
2860 else if (track
->par
->codec_id
== AV_CODEC_ID_AVUI
||
2861 track
->par
->codec_id
== AV_CODEC_ID_SVQ3
) {
2862 mov_write_extradata_tag(pb
, track
);
2864 } else if (track
->par
->codec_id
== AV_CODEC_ID_DNXHD
) {
2865 mov_write_avid_tag(pb
, track
);
2867 } else if (track
->par
->codec_id
== AV_CODEC_ID_HEVC
) {
2868 mov_write_hvcc_tag(mov
->fc
, pb
, track
);
2869 if (track
->st
->disposition
& AV_DISPOSITION_MULTILAYER
) {
2870 ret
= mov_write_lhvc_tag(mov
->fc
, pb
, track
);
2872 av_log(mov
->fc
, AV_LOG_WARNING
, "Not writing 'lhvC' atom for multilayer stream.\n");
2874 } else if (track
->par
->codec_id
== AV_CODEC_ID_VVC
)
2875 mov_write_vvcc_tag(pb
, track
);
2876 else if (track
->par
->codec_id
== AV_CODEC_ID_H264
&& !TAG_IS_AVCI(track
->tag
)) {
2877 mov_write_avcc_tag(pb
, track
);
2878 if (track
->mode
== MODE_IPOD
)
2879 mov_write_uuid_tag_ipod(pb
);
2881 else if (track
->par
->codec_id
==AV_CODEC_ID_EVC
) {
2882 mov_write_evcc_tag(pb
, track
);
2883 } else if (track
->par
->codec_id
==AV_CODEC_ID_APV
) {
2884 mov_write_apvc_tag(mov
->fc
, pb
, track
);
2885 } else if (track
->par
->codec_id
== AV_CODEC_ID_VP9
) {
2886 mov_write_vpcc_tag(mov
->fc
, pb
, track
);
2887 } else if (track
->par
->codec_id
== AV_CODEC_ID_AV1
) {
2888 mov_write_av1c_tag(pb
, track
);
2889 } else if (track
->par
->codec_id
== AV_CODEC_ID_VC1
&& track
->extradata_size
[track
->last_stsd_index
] > 0)
2890 mov_write_dvc1_tag(pb
, track
);
2891 else if (track
->par
->codec_id
== AV_CODEC_ID_VP6F
||
2892 track
->par
->codec_id
== AV_CODEC_ID_VP6A
) {
2893 /* Don't write any potential extradata here - the cropping
2894 * is signalled via the normal width/height fields. */
2895 } else if (track
->par
->codec_id
== AV_CODEC_ID_R10K
) {
2896 if (track
->par
->codec_tag
== MKTAG('R','1','0','k'))
2897 mov_write_dpxe_tag(pb
, track
);
2898 } else if (track
->par
->codec_id
== AV_CODEC_ID_AVS3
) {
2899 mov_write_av3c_tag(pb
, track
);
2900 } else if (track
->extradata_size
[track
->last_stsd_index
] > 0)
2901 mov_write_glbl_tag(pb
, track
);
2903 if (track
->par
->codec_id
!= AV_CODEC_ID_H264
&&
2904 track
->par
->codec_id
!= AV_CODEC_ID_MPEG4
&&
2905 track
->par
->codec_id
!= AV_CODEC_ID_DNXHD
) {
2906 int field_order
= track
->par
->field_order
;
2908 if (field_order
!= AV_FIELD_UNKNOWN
)
2909 mov_write_fiel_tag(pb
, track
, field_order
);
2912 if (mov
->flags
& FF_MOV_FLAG_WRITE_GAMA
) {
2913 if (track
->mode
== MODE_MOV
)
2914 mov_write_gama_tag(s
, pb
, track
, mov
->gamma
);
2916 av_log(mov
->fc
, AV_LOG_WARNING
, "Not writing 'gama' atom. Format is not MOV.\n");
2918 if (track
->mode
== MODE_MOV
|| track
->mode
== MODE_MP4
|| track
->mode
== MODE_AVIF
) {
2919 int has_color_info
= track
->par
->color_primaries
!= AVCOL_PRI_UNSPECIFIED
&&
2920 track
->par
->color_trc
!= AVCOL_TRC_UNSPECIFIED
&&
2921 track
->par
->color_space
!= AVCOL_SPC_UNSPECIFIED
;
2922 if (has_color_info
|| mov
->flags
& FF_MOV_FLAG_WRITE_COLR
||
2923 av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
, track
->st
->codecpar
->nb_coded_side_data
,
2924 AV_PKT_DATA_ICC_PROFILE
)) {
2925 int prefer_icc
= mov
->flags
& FF_MOV_FLAG_PREFER_ICC
|| !has_color_info
;
2926 mov_write_colr_tag(pb
, track
, prefer_icc
);
2928 } else if (mov
->flags
& FF_MOV_FLAG_WRITE_COLR
) {
2929 av_log(mov
->fc
, AV_LOG_WARNING
, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2932 if (track
->mode
== MODE_MOV
|| track
->mode
== MODE_MP4
) {
2933 mov_write_clli_tag(pb
, track
);
2934 mov_write_mdcv_tag(pb
, track
);
2935 mov_write_amve_tag(pb
, track
);
2938 if (track
->mode
== MODE_MP4
&& mov
->fc
->strict_std_compliance
<= FF_COMPLIANCE_UNOFFICIAL
) {
2939 const AVPacketSideData
*stereo_3d
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2940 track
->st
->codecpar
->nb_coded_side_data
,
2941 AV_PKT_DATA_STEREO3D
);
2942 const AVPacketSideData
*spherical_mapping
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2943 track
->st
->codecpar
->nb_coded_side_data
,
2944 AV_PKT_DATA_SPHERICAL
);
2946 mov_write_st3d_tag(s
, pb
, (AVStereo3D
*)stereo_3d
->data
);
2947 if (spherical_mapping
)
2948 mov_write_sv3d_tag(mov
->fc
, pb
, (AVSphericalMapping
*)spherical_mapping
->data
);
2951 if (track
->mode
== MODE_MOV
|| (track
->mode
== MODE_MP4
&&
2952 mov
->fc
->strict_std_compliance
<= FF_COMPLIANCE_UNOFFICIAL
)) {
2953 const AVStereo3D
*stereo3d
= NULL
;
2954 const AVSphericalMapping
*spherical_mapping
= NULL
;
2956 sd
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2957 track
->st
->codecpar
->nb_coded_side_data
,
2958 AV_PKT_DATA_STEREO3D
);
2960 stereo3d
= (AVStereo3D
*)sd
->data
;
2962 sd
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2963 track
->st
->codecpar
->nb_coded_side_data
,
2964 AV_PKT_DATA_SPHERICAL
);
2966 spherical_mapping
= (AVSphericalMapping
*)sd
->data
;
2968 if (stereo3d
|| spherical_mapping
)
2969 mov_write_vexu_tag(s
, pb
, stereo3d
, spherical_mapping
);
2971 mov_write_hfov_tag(s
, pb
, stereo3d
);
2974 if (track
->mode
== MODE_MP4
) {
2975 const AVPacketSideData
*dovi
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2976 track
->st
->codecpar
->nb_coded_side_data
,
2977 AV_PKT_DATA_DOVI_CONF
);
2978 if (dovi
&& mov
->fc
->strict_std_compliance
<= FF_COMPLIANCE_UNOFFICIAL
) {
2979 mov_write_dvcc_dvvc_tag(s
, pb
, (AVDOVIDecoderConfigurationRecord
*)dovi
->data
);
2981 av_log(mov
->fc
, AV_LOG_WARNING
, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2985 if (track
->par
->sample_aspect_ratio
.den
&& track
->par
->sample_aspect_ratio
.num
) {
2986 mov_write_pasp_tag(pb
, track
);
2989 sd
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
2990 track
->st
->codecpar
->nb_coded_side_data
,
2991 AV_PKT_DATA_FRAME_CROPPING
);
2992 if (sd
&& sd
->size
>= sizeof(uint32_t) * 4) {
2993 uint64_t top
= AV_RL32(sd
->data
+ 0);
2994 uint64_t bottom
= AV_RL32(sd
->data
+ 4);
2995 uint64_t left
= AV_RL32(sd
->data
+ 8);
2996 uint64_t right
= AV_RL32(sd
->data
+ 12);
2998 if ((left
+ right
) >= track
->par
->width
||
2999 (top
+ bottom
) >= track
->height
) {
3000 av_log(s
, AV_LOG_ERROR
, "Invalid cropping dimensions in stream side data\n");
3001 return AVERROR(EINVAL
);
3003 if (top
|| bottom
|| left
|| right
)
3004 mov_write_clap_tag(pb
, track
, top
, bottom
, left
, right
);
3005 } else if (uncompressed_ycbcr
)
3006 mov_write_clap_tag(pb
, track
, 0, 0, 0, 0);
3008 if (mov
->encryption_scheme
!= MOV_ENC_NONE
) {
3009 ff_mov_cenc_write_sinf_tag(track
, pb
, mov
->encryption_kid
);
3012 if (mov
->write_btrt
&&
3013 ((ret
= mov_write_btrt_tag(pb
, track
)) < 0))
3016 /* extra padding for avid stsd */
3017 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3021 if (track
->mode
== MODE_AVIF
) {
3022 mov_write_ccst_tag(pb
);
3023 if (mov
->nb_streams
> 0 && track
== &mov
->tracks
[1])
3024 mov_write_aux_tag(pb
, "auxi");
3027 return update_size(pb
, pos
);
3030 static int mov_write_rtp_tag(AVIOContext
*pb
, MOVTrack
*track
)
3032 int64_t pos
= avio_tell(pb
);
3033 avio_wb32(pb
, 0); /* size */
3034 ffio_wfourcc(pb
, "rtp ");
3035 avio_wb32(pb
, 0); /* Reserved */
3036 avio_wb16(pb
, 0); /* Reserved */
3037 avio_wb16(pb
, 1); /* Data-reference index */
3039 avio_wb16(pb
, 1); /* Hint track version */
3040 avio_wb16(pb
, 1); /* Highest compatible version */
3041 avio_wb32(pb
, track
->max_packet_size
); /* Max packet size */
3043 avio_wb32(pb
, 12); /* size */
3044 ffio_wfourcc(pb
, "tims");
3045 avio_wb32(pb
, track
->timescale
);
3047 return update_size(pb
, pos
);
3050 static int mov_write_source_reference_tag(AVIOContext
*pb
, MOVTrack
*track
, const char *reel_name
)
3052 uint64_t str_size
=strlen(reel_name
);
3053 int64_t pos
= avio_tell(pb
);
3055 if (str_size
>= UINT16_MAX
){
3056 av_log(NULL
, AV_LOG_ERROR
, "reel_name length %"PRIu64
" is too large\n", str_size
);
3058 return AVERROR(EINVAL
);
3061 avio_wb32(pb
, 0); /* size */
3062 ffio_wfourcc(pb
, "name"); /* Data format */
3063 avio_wb16(pb
, str_size
); /* string size */
3064 avio_wb16(pb
, track
->language
); /* langcode */
3065 avio_write(pb
, reel_name
, str_size
); /* reel name */
3066 return update_size(pb
,pos
);
3069 static int mov_write_tmcd_tag(AVIOContext
*pb
, MOVTrack
*track
)
3071 int64_t pos
= avio_tell(pb
);
3075 AVDictionaryEntry
*t
= NULL
;
3077 if (!track
->st
->avg_frame_rate
.num
|| !track
->st
->avg_frame_rate
.den
) {
3078 av_log(NULL
, AV_LOG_ERROR
, "avg_frame_rate not set for tmcd track.\n");
3079 return AVERROR(EINVAL
);
3081 frame_duration
= av_rescale(track
->timescale
, track
->st
->avg_frame_rate
.den
, track
->st
->avg_frame_rate
.num
);
3082 nb_frames
= ROUNDED_DIV(track
->st
->avg_frame_rate
.num
, track
->st
->avg_frame_rate
.den
);
3085 if (nb_frames
> 255) {
3086 av_log(NULL
, AV_LOG_ERROR
, "fps %d is too large\n", nb_frames
);
3087 return AVERROR(EINVAL
);
3090 avio_wb32(pb
, 0); /* size */
3091 ffio_wfourcc(pb
, "tmcd"); /* Data format */
3092 avio_wb32(pb
, 0); /* Reserved */
3093 avio_wb32(pb
, 1); /* Data reference index */
3094 avio_wb32(pb
, 0); /* Flags */
3095 avio_wb32(pb
, track
->timecode_flags
); /* Flags (timecode) */
3096 avio_wb32(pb
, track
->timescale
); /* Timescale */
3097 avio_wb32(pb
, frame_duration
); /* Frame duration */
3098 avio_w8(pb
, nb_frames
); /* Number of frames */
3099 avio_w8(pb
, 0); /* Reserved */
3101 t
= av_dict_get(track
->st
->metadata
, "reel_name", NULL
, 0);
3102 if (t
&& utf8len(t
->value
) && track
->mode
!= MODE_MP4
)
3103 mov_write_source_reference_tag(pb
, track
, t
->value
);
3105 avio_wb16(pb
, 0); /* zero size */
3108 avio_wb32(pb
, 0); /* size */
3109 ffio_wfourcc(pb
, "tmcd"); /* Data format */
3110 avio_wb32(pb
, 0); /* Reserved */
3111 avio_wb32(pb
, 1); /* Data reference index */
3112 if (track
->par
->extradata_size
)
3113 avio_write(pb
, track
->par
->extradata
, track
->par
->extradata_size
);
3115 return update_size(pb
, pos
);
3118 static int mov_write_gpmd_tag(AVIOContext
*pb
, const MOVTrack
*track
)
3120 int64_t pos
= avio_tell(pb
);
3121 avio_wb32(pb
, 0); /* size */
3122 ffio_wfourcc(pb
, "gpmd");
3123 avio_wb32(pb
, 0); /* Reserved */
3124 avio_wb16(pb
, 0); /* Reserved */
3125 avio_wb16(pb
, 1); /* Data-reference index */
3126 avio_wb32(pb
, 0); /* Reserved */
3127 return update_size(pb
, pos
);
3130 static int mov_write_stsd_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVMuxContext
*mov
, MOVTrack
*track
)
3132 int64_t pos
= avio_tell(pb
);
3134 avio_wb32(pb
, 0); /* size */
3135 ffio_wfourcc(pb
, "stsd");
3136 avio_wb32(pb
, 0); /* version & flags */
3137 avio_wb32(pb
, track
->stsd_count
);
3139 int stsd_index_back
= track
->last_stsd_index
;
3140 for (track
->last_stsd_index
= 0;
3141 track
->last_stsd_index
< track
->stsd_count
;
3142 track
->last_stsd_index
++) {
3143 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
)
3144 ret
= mov_write_video_tag(s
, pb
, mov
, track
);
3145 else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
)
3146 ret
= mov_write_audio_tag(s
, pb
, mov
, track
);
3147 else if (track
->par
->codec_type
== AVMEDIA_TYPE_SUBTITLE
)
3148 ret
= mov_write_subtitle_tag(s
, pb
, track
);
3149 else if (track
->par
->codec_tag
== MKTAG('r','t','p',' '))
3150 ret
= mov_write_rtp_tag(pb
, track
);
3151 else if (track
->par
->codec_tag
== MKTAG('t','m','c','d'))
3152 ret
= mov_write_tmcd_tag(pb
, track
);
3153 else if (track
->par
->codec_tag
== MKTAG('g','p','m','d'))
3154 ret
= mov_write_gpmd_tag(pb
, track
);
3160 track
->last_stsd_index
= stsd_index_back
;
3162 return update_size_and_version(pb
, pos
, track
->entry_version
);
3165 static int mov_write_ctts_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
3167 MOVMuxContext
*mov
= s
->priv_data
;
3168 MOVCtts
*ctts_entries
;
3169 uint32_t entries
= 0;
3173 ctts_entries
= av_malloc_array((track
->entry
+ 1), sizeof(*ctts_entries
)); /* worst case */
3175 return AVERROR(ENOMEM
);
3176 ctts_entries
[0].count
= 1;
3177 ctts_entries
[0].offset
= track
->cluster
[0].cts
;
3178 for (i
= 1; i
< track
->entry
; i
++) {
3179 if (track
->cluster
[i
].cts
== ctts_entries
[entries
].offset
) {
3180 ctts_entries
[entries
].count
++; /* compress */
3183 ctts_entries
[entries
].offset
= track
->cluster
[i
].cts
;
3184 ctts_entries
[entries
].count
= 1;
3187 entries
++; /* last one */
3188 atom_size
= 16 + (entries
* 8);
3189 avio_wb32(pb
, atom_size
); /* size */
3190 ffio_wfourcc(pb
, "ctts");
3191 if (mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
)
3192 avio_w8(pb
, 1); /* version */
3194 avio_w8(pb
, 0); /* version */
3195 avio_wb24(pb
, 0); /* flags */
3196 avio_wb32(pb
, entries
); /* entry count */
3197 for (i
= 0; i
< entries
; i
++) {
3198 avio_wb32(pb
, ctts_entries
[i
].count
);
3199 avio_wb32(pb
, ctts_entries
[i
].offset
);
3201 av_free(ctts_entries
);
3205 /* Time to sample atom */
3206 static int mov_write_stts_tag(AVIOContext
*pb
, MOVTrack
*track
)
3208 MOVStts
*stts_entries
= NULL
;
3209 uint32_t entries
= -1;
3213 if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
&& !track
->audio_vbr
) {
3214 stts_entries
= av_malloc(sizeof(*stts_entries
)); /* one entry */
3216 return AVERROR(ENOMEM
);
3217 stts_entries
[0].count
= track
->sample_count
;
3218 stts_entries
[0].duration
= 1;
3222 stts_entries
= av_malloc_array(track
->entry
, sizeof(*stts_entries
)); /* worst case */
3224 return AVERROR(ENOMEM
);
3226 for (i
= 0; i
< track
->entry
; i
++) {
3227 int duration
= get_cluster_duration(track
, i
);
3229 if (track
->iamf
&& track
->par
->codec_id
== AV_CODEC_ID_OPUS
)
3230 duration
= av_rescale(duration
, 48000, track
->par
->sample_rate
);
3232 if (i
&& duration
== stts_entries
[entries
].duration
) {
3233 stts_entries
[entries
].count
++; /* compress */
3236 stts_entries
[entries
].duration
= duration
;
3237 stts_entries
[entries
].count
= 1;
3240 entries
++; /* last one */
3242 atom_size
= 16 + (entries
* 8);
3243 avio_wb32(pb
, atom_size
); /* size */
3244 ffio_wfourcc(pb
, "stts");
3245 avio_wb32(pb
, 0); /* version & flags */
3246 avio_wb32(pb
, entries
); /* entry count */
3247 for (i
= 0; i
< entries
; i
++) {
3248 avio_wb32(pb
, stts_entries
[i
].count
);
3249 avio_wb32(pb
, stts_entries
[i
].duration
);
3251 av_free(stts_entries
);
3255 static int mov_write_dref_tag(AVIOContext
*pb
)
3257 avio_wb32(pb
, 28); /* size */
3258 ffio_wfourcc(pb
, "dref");
3259 avio_wb32(pb
, 0); /* version & flags */
3260 avio_wb32(pb
, 1); /* entry count */
3262 avio_wb32(pb
, 0xc); /* size */
3263 //FIXME add the alis and rsrc atom
3264 ffio_wfourcc(pb
, "url ");
3265 avio_wb32(pb
, 1); /* version & flags */
3270 static int mov_preroll_write_stbl_atoms(AVIOContext
*pb
, MOVTrack
*track
)
3274 int16_t roll_distance
;
3275 int group_description_index
;
3278 struct sgpd_entry
*sgpd_entries
= NULL
;
3283 const int OPUS_SEEK_PREROLL_MS
= 80;
3284 int roll_samples
= av_rescale_q(OPUS_SEEK_PREROLL_MS
,
3285 (AVRational
){1, 1000},
3286 (AVRational
){1, 48000});
3291 sgpd_entries
= av_malloc_array(track
->entry
, sizeof(*sgpd_entries
));
3293 return AVERROR(ENOMEM
);
3295 av_assert0(track
->par
->codec_id
== AV_CODEC_ID_OPUS
|| track
->par
->codec_id
== AV_CODEC_ID_AAC
);
3297 if (track
->par
->codec_id
== AV_CODEC_ID_OPUS
) {
3298 for (i
= 0; i
< track
->entry
; i
++) {
3299 int roll_samples_remaining
= roll_samples
;
3301 for (j
= i
- 1; j
>= 0; j
--) {
3302 roll_samples_remaining
-= get_cluster_duration(track
, j
);
3304 if (roll_samples_remaining
<= 0)
3307 /* We don't have enough preceding samples to compute a valid
3308 roll_distance here, so this sample can't be independently
3310 if (roll_samples_remaining
> 0)
3312 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3314 return AVERROR_INVALIDDATA
;
3315 if (i
&& distance
== sgpd_entries
[entries
].roll_distance
) {
3316 sgpd_entries
[entries
].count
++;
3319 sgpd_entries
[entries
].count
= 1;
3320 sgpd_entries
[entries
].roll_distance
= distance
;
3321 sgpd_entries
[entries
].group_description_index
= distance
? ++group
: 0;
3326 sgpd_entries
[entries
].count
= track
->sample_count
;
3327 sgpd_entries
[entries
].roll_distance
= 1;
3328 sgpd_entries
[entries
].group_description_index
= ++group
;
3333 av_free(sgpd_entries
);
3337 /* Write sgpd tag */
3338 avio_wb32(pb
, 24 + (group
* 2)); /* size */
3339 ffio_wfourcc(pb
, "sgpd");
3340 avio_wb32(pb
, 1 << 24); /* fullbox */
3341 ffio_wfourcc(pb
, "roll");
3342 avio_wb32(pb
, 2); /* default_length */
3343 avio_wb32(pb
, group
); /* entry_count */
3344 for (i
= 0; i
< entries
; i
++) {
3345 if (sgpd_entries
[i
].group_description_index
) {
3346 avio_wb16(pb
, -sgpd_entries
[i
].roll_distance
); /* roll_distance */
3350 /* Write sbgp tag */
3351 avio_wb32(pb
, 20 + (entries
* 8)); /* size */
3352 ffio_wfourcc(pb
, "sbgp");
3353 avio_wb32(pb
, 0); /* fullbox */
3354 ffio_wfourcc(pb
, "roll");
3355 avio_wb32(pb
, entries
); /* entry_count */
3356 for (i
= 0; i
< entries
; i
++) {
3357 avio_wb32(pb
, sgpd_entries
[i
].count
); /* sample_count */
3358 avio_wb32(pb
, sgpd_entries
[i
].group_description_index
); /* group_description_index */
3361 av_free(sgpd_entries
);
3365 static int mov_write_stbl_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVMuxContext
*mov
, MOVTrack
*track
)
3367 int64_t pos
= avio_tell(pb
);
3370 avio_wb32(pb
, 0); /* size */
3371 ffio_wfourcc(pb
, "stbl");
3372 if ((ret
= mov_write_stsd_tag(s
, pb
, mov
, track
)) < 0)
3374 mov_write_stts_tag(pb
, track
);
3375 if ((track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
||
3376 track
->par
->codec_id
== AV_CODEC_ID_TRUEHD
||
3377 track
->par
->codec_id
== AV_CODEC_ID_MPEGH_3D_AUDIO
||
3378 (track
->par
->codec_id
== AV_CODEC_ID_AAC
&& track
->par
->profile
== AV_PROFILE_AAC_USAC
) ||
3379 track
->par
->codec_tag
== MKTAG('r','t','p',' ')) &&
3380 track
->has_keyframes
&& track
->has_keyframes
< track
->entry
)
3381 mov_write_stss_tag(pb
, track
, MOV_SYNC_SAMPLE
);
3382 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
&& track
->has_disposable
&& track
->entry
)
3383 mov_write_sdtp_tag(pb
, track
);
3384 if (track
->mode
== MODE_MOV
&& track
->flags
& MOV_TRACK_STPS
)
3385 mov_write_stss_tag(pb
, track
, MOV_PARTIAL_SYNC_SAMPLE
);
3386 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
&&
3387 track
->flags
& MOV_TRACK_CTTS
&& track
->entry
) {
3389 if ((ret
= mov_write_ctts_tag(s
, pb
, track
)) < 0)
3392 mov_write_stsc_tag(pb
, track
);
3393 mov_write_stsz_tag(pb
, track
);
3394 mov_write_stco_tag(pb
, track
);
3395 if (track
->cenc
.aes_ctr
&& !(mov
->flags
& FF_MOV_FLAG_FRAGMENT
)) {
3396 ff_mov_cenc_write_stbl_atoms(&track
->cenc
, pb
, 0);
3398 if (track
->par
->codec_id
== AV_CODEC_ID_OPUS
|| track
->par
->codec_id
== AV_CODEC_ID_AAC
) {
3399 mov_preroll_write_stbl_atoms(pb
, track
);
3401 return update_size(pb
, pos
);
3404 static int mov_write_dinf_tag(AVIOContext
*pb
)
3406 int64_t pos
= avio_tell(pb
);
3407 avio_wb32(pb
, 0); /* size */
3408 ffio_wfourcc(pb
, "dinf");
3409 mov_write_dref_tag(pb
);
3410 return update_size(pb
, pos
);
3413 static int mov_write_nmhd_tag(AVIOContext
*pb
)
3416 ffio_wfourcc(pb
, "nmhd");
3421 static int mov_write_sthd_tag(AVIOContext
*pb
)
3424 ffio_wfourcc(pb
, "sthd");
3429 static int mov_write_tcmi_tag(AVIOContext
*pb
, MOVTrack
*track
)
3431 int64_t pos
= avio_tell(pb
);
3432 const char *font
= "Lucida Grande";
3433 avio_wb32(pb
, 0); /* size */
3434 ffio_wfourcc(pb
, "tcmi"); /* timecode media information atom */
3435 avio_wb32(pb
, 0); /* version & flags */
3436 avio_wb16(pb
, 0); /* text font */
3437 avio_wb16(pb
, 0); /* text face */
3438 avio_wb16(pb
, 12); /* text size */
3439 avio_wb16(pb
, 0); /* (unknown, not in the QT specs...) */
3440 avio_wb16(pb
, 0x0000); /* text color (red) */
3441 avio_wb16(pb
, 0x0000); /* text color (green) */
3442 avio_wb16(pb
, 0x0000); /* text color (blue) */
3443 avio_wb16(pb
, 0xffff); /* background color (red) */
3444 avio_wb16(pb
, 0xffff); /* background color (green) */
3445 avio_wb16(pb
, 0xffff); /* background color (blue) */
3446 avio_w8(pb
, strlen(font
)); /* font len (part of the pascal string) */
3447 avio_write(pb
, font
, strlen(font
)); /* font name */
3448 return update_size(pb
, pos
);
3451 static int mov_write_gmhd_tag(AVIOContext
*pb
, MOVTrack
*track
)
3453 int64_t pos
= avio_tell(pb
);
3454 avio_wb32(pb
, 0); /* size */
3455 ffio_wfourcc(pb
, "gmhd");
3456 avio_wb32(pb
, 0x18); /* gmin size */
3457 ffio_wfourcc(pb
, "gmin");/* generic media info */
3458 avio_wb32(pb
, 0); /* version & flags */
3459 avio_wb16(pb
, 0x40); /* graphics mode = */
3460 avio_wb16(pb
, 0x8000); /* opColor (r?) */
3461 avio_wb16(pb
, 0x8000); /* opColor (g?) */
3462 avio_wb16(pb
, 0x8000); /* opColor (b?) */
3463 avio_wb16(pb
, 0); /* balance */
3464 avio_wb16(pb
, 0); /* reserved */
3467 * This special text atom is required for
3468 * Apple Quicktime chapters. The contents
3469 * don't appear to be documented, so the
3470 * bytes are copied verbatim.
3472 if (track
->tag
!= MKTAG('c','6','0','8')) {
3473 avio_wb32(pb
, 0x2C); /* size */
3474 ffio_wfourcc(pb
, "text");
3475 avio_wb16(pb
, 0x01);
3476 avio_wb32(pb
, 0x00);
3477 avio_wb32(pb
, 0x00);
3478 avio_wb32(pb
, 0x00);
3479 avio_wb32(pb
, 0x01);
3480 avio_wb32(pb
, 0x00);
3481 avio_wb32(pb
, 0x00);
3482 avio_wb32(pb
, 0x00);
3483 avio_wb32(pb
, 0x00004000);
3484 avio_wb16(pb
, 0x0000);
3487 if (track
->par
->codec_tag
== MKTAG('t','m','c','d')) {
3488 int64_t tmcd_pos
= avio_tell(pb
);
3489 avio_wb32(pb
, 0); /* size */
3490 ffio_wfourcc(pb
, "tmcd");
3491 mov_write_tcmi_tag(pb
, track
);
3492 update_size(pb
, tmcd_pos
);
3493 } else if (track
->par
->codec_tag
== MKTAG('g','p','m','d')) {
3494 int64_t gpmd_pos
= avio_tell(pb
);
3495 avio_wb32(pb
, 0); /* size */
3496 ffio_wfourcc(pb
, "gpmd");
3497 avio_wb32(pb
, 0); /* version */
3498 update_size(pb
, gpmd_pos
);
3500 return update_size(pb
, pos
);
3503 static int mov_write_smhd_tag(AVIOContext
*pb
)
3505 avio_wb32(pb
, 16); /* size */
3506 ffio_wfourcc(pb
, "smhd");
3507 avio_wb32(pb
, 0); /* version & flags */
3508 avio_wb16(pb
, 0); /* reserved (balance, normally = 0) */
3509 avio_wb16(pb
, 0); /* reserved */
3513 static int mov_write_vmhd_tag(AVIOContext
*pb
)
3515 avio_wb32(pb
, 0x14); /* size (always 0x14) */
3516 ffio_wfourcc(pb
, "vmhd");
3517 avio_wb32(pb
, 0x01); /* version & flags */
3518 avio_wb64(pb
, 0); /* reserved (graphics mode = copy) */
3522 static int is_clcp_track(MOVTrack
*track
)
3524 return track
->tag
== MKTAG('c','7','0','8') ||
3525 track
->tag
== MKTAG('c','6','0','8');
3528 static int mov_write_hdlr_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVTrack
*track
)
3530 MOVMuxContext
*mov
= s
->priv_data
;
3531 const char *hdlr
, *descr
= NULL
, *hdlr_type
= NULL
;
3532 int64_t pos
= avio_tell(pb
);
3537 descr
= "DataHandler";
3540 hdlr
= (track
->mode
== MODE_MOV
) ? "mhlr" : "\0\0\0\0";
3541 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
3542 if (track
->mode
== MODE_AVIF
) {
3543 hdlr_type
= (track
== &mov
->tracks
[0]) ? "pict" : "auxv";
3544 descr
= "PictureHandler";
3547 descr
= "VideoHandler";
3549 } else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
3551 descr
= "SoundHandler";
3552 } else if (track
->par
->codec_type
== AVMEDIA_TYPE_SUBTITLE
) {
3553 if (is_clcp_track(track
)) {
3555 descr
= "ClosedCaptionHandler";
3557 if (track
->tag
== MKTAG('t','x','3','g')) {
3559 } else if (track
->tag
== MKTAG('m','p','4','s')) {
3561 } else if (track
->tag
== MOV_MP4_TTML_TAG
) {
3566 descr
= "SubtitleHandler";
3568 } else if (track
->par
->codec_tag
== MKTAG('r','t','p',' ')) {
3570 descr
= "HintHandler";
3571 } else if (track
->par
->codec_tag
== MKTAG('t','m','c','d')) {
3573 descr
= "TimeCodeHandler";
3574 } else if (track
->par
->codec_tag
== MKTAG('g','p','m','d')) {
3576 descr
= "GoPro MET"; // GoPro Metadata
3578 av_log(s
, AV_LOG_WARNING
,
3579 "Unknown hdlr_type for %s, writing dummy values\n",
3580 av_fourcc2str(track
->par
->codec_tag
));
3583 // hdlr.name is used by some players to identify the content title
3584 // of the track. So if an alternate handler description is
3585 // specified, use it.
3586 AVDictionaryEntry
*t
;
3587 t
= av_dict_get(track
->st
->metadata
, "handler_name", NULL
, 0);
3588 if (t
&& utf8len(t
->value
))
3593 if (mov
->empty_hdlr_name
) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3596 avio_wb32(pb
, 0); /* size */
3597 ffio_wfourcc(pb
, "hdlr");
3598 avio_wb32(pb
, 0); /* Version & flags */
3599 avio_write(pb
, hdlr
, 4); /* handler */
3600 ffio_wfourcc(pb
, hdlr_type
); /* handler type */
3601 avio_wb32(pb
, 0); /* reserved */
3602 avio_wb32(pb
, 0); /* reserved */
3603 avio_wb32(pb
, 0); /* reserved */
3604 descr_len
= strlen(descr
);
3605 if (!track
|| track
->mode
== MODE_MOV
)
3606 avio_w8(pb
, descr_len
); /* pascal string */
3607 avio_write(pb
, descr
, descr_len
); /* handler description */
3608 if (track
&& track
->mode
!= MODE_MOV
)
3609 avio_w8(pb
, 0); /* c string */
3610 return update_size(pb
, pos
);
3613 static int mov_write_pitm_tag(AVIOContext
*pb
, int item_id
)
3615 int64_t pos
= avio_tell(pb
);
3616 avio_wb32(pb
, 0); /* size */
3617 ffio_wfourcc(pb
, "pitm");
3618 avio_wb32(pb
, 0); /* Version & flags */
3619 avio_wb16(pb
, item_id
); /* item_id */
3620 return update_size(pb
, pos
);
3623 static int mov_write_iloc_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
3625 int64_t pos
= avio_tell(pb
);
3626 avio_wb32(pb
, 0); /* size */
3627 ffio_wfourcc(pb
, "iloc");
3628 avio_wb32(pb
, 0); /* Version & flags */
3629 avio_w8(pb
, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3630 avio_w8(pb
, 0); /* base_offset_size(4) and reserved(4) */
3631 avio_wb16(pb
, mov
->nb_streams
); /* item_count */
3633 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
3634 avio_wb16(pb
, i
+ 1); /* item_id */
3635 avio_wb16(pb
, 0); /* data_reference_index */
3636 avio_wb16(pb
, 1); /* extent_count */
3637 mov
->avif_extent_pos
[i
] = avio_tell(pb
);
3638 avio_wb32(pb
, 0); /* extent_offset (written later) */
3639 // For animated AVIF, we simply write the first packet's size.
3640 avio_wb32(pb
, mov
->avif_extent_length
[i
]); /* extent_length */
3643 return update_size(pb
, pos
);
3646 static int mov_write_iinf_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
3648 int64_t iinf_pos
= avio_tell(pb
);
3649 avio_wb32(pb
, 0); /* size */
3650 ffio_wfourcc(pb
, "iinf");
3651 avio_wb32(pb
, 0); /* Version & flags */
3652 avio_wb16(pb
, mov
->nb_streams
); /* entry_count */
3654 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
3655 int64_t infe_pos
= avio_tell(pb
);
3656 avio_wb32(pb
, 0); /* size */
3657 ffio_wfourcc(pb
, "infe");
3658 avio_w8(pb
, 0x2); /* Version */
3659 avio_wb24(pb
, 0); /* flags */
3660 avio_wb16(pb
, i
+ 1); /* item_id */
3661 avio_wb16(pb
, 0); /* item_protection_index */
3662 avio_write(pb
, "av01", 4); /* item_type */
3663 avio_write(pb
, !i
? "Color\0" : "Alpha\0", 6); /* item_name */
3664 update_size(pb
, infe_pos
);
3667 return update_size(pb
, iinf_pos
);
3671 static int mov_write_iref_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
3674 int64_t iref_pos
= avio_tell(pb
);
3675 avio_wb32(pb
, 0); /* size */
3676 ffio_wfourcc(pb
, "iref");
3677 avio_wb32(pb
, 0); /* Version & flags */
3679 auxl_pos
= avio_tell(pb
);
3680 avio_wb32(pb
, 0); /* size */
3681 ffio_wfourcc(pb
, "auxl");
3682 avio_wb16(pb
, 2); /* from_item_ID */
3683 avio_wb16(pb
, 1); /* reference_count */
3684 avio_wb16(pb
, 1); /* to_item_ID */
3685 update_size(pb
, auxl_pos
);
3687 return update_size(pb
, iref_pos
);
3690 static int mov_write_ispe_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
,
3693 int64_t pos
= avio_tell(pb
);
3694 avio_wb32(pb
, 0); /* size */
3695 ffio_wfourcc(pb
, "ispe");
3696 avio_wb32(pb
, 0); /* Version & flags */
3697 avio_wb32(pb
, s
->streams
[stream_index
]->codecpar
->width
); /* image_width */
3698 avio_wb32(pb
, s
->streams
[stream_index
]->codecpar
->height
); /* image_height */
3699 return update_size(pb
, pos
);
3702 static int mov_write_pixi_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
,
3705 int64_t pos
= avio_tell(pb
);
3706 const AVPixFmtDescriptor
*pixdesc
=
3707 av_pix_fmt_desc_get(s
->streams
[stream_index
]->codecpar
->format
);
3708 avio_wb32(pb
, 0); /* size */
3709 ffio_wfourcc(pb
, "pixi");
3710 avio_wb32(pb
, 0); /* Version & flags */
3711 avio_w8(pb
, pixdesc
->nb_components
); /* num_channels */
3712 for (int i
= 0; i
< pixdesc
->nb_components
; ++i
) {
3713 avio_w8(pb
, pixdesc
->comp
[i
].depth
); /* bits_per_channel */
3715 return update_size(pb
, pos
);
3718 static int mov_write_ipco_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
3720 int64_t pos
= avio_tell(pb
);
3721 avio_wb32(pb
, 0); /* size */
3722 ffio_wfourcc(pb
, "ipco");
3723 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
3724 mov_write_ispe_tag(pb
, mov
, s
, i
);
3725 mov_write_pixi_tag(pb
, mov
, s
, i
);
3726 mov_write_av1c_tag(pb
, &mov
->tracks
[i
]);
3728 mov_write_colr_tag(pb
, &mov
->tracks
[0], 0);
3730 mov_write_aux_tag(pb
, "auxC");
3732 return update_size(pb
, pos
);
3735 static int mov_write_ipma_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
3737 int64_t pos
= avio_tell(pb
);
3738 avio_wb32(pb
, 0); /* size */
3739 ffio_wfourcc(pb
, "ipma");
3740 avio_wb32(pb
, 0); /* Version & flags */
3741 avio_wb32(pb
, mov
->nb_streams
); /* entry_count */
3743 for (int i
= 0, index
= 1; i
< mov
->nb_streams
; i
++) {
3744 avio_wb16(pb
, i
+ 1); /* item_ID */
3745 avio_w8(pb
, 4); /* association_count */
3747 // ispe association.
3748 avio_w8(pb
, index
++); /* essential and property_index */
3749 // pixi association.
3750 avio_w8(pb
, index
++); /* essential and property_index */
3751 // av1C association.
3752 avio_w8(pb
, 0x80 | index
++); /* essential and property_index */
3753 // colr/auxC association.
3754 avio_w8(pb
, index
++); /* essential and property_index */
3756 return update_size(pb
, pos
);
3759 static int mov_write_iprp_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
3761 int64_t pos
= avio_tell(pb
);
3762 avio_wb32(pb
, 0); /* size */
3763 ffio_wfourcc(pb
, "iprp");
3764 mov_write_ipco_tag(pb
, mov
, s
);
3765 mov_write_ipma_tag(pb
, mov
, s
);
3766 return update_size(pb
, pos
);
3769 static int mov_write_hmhd_tag(AVIOContext
*pb
)
3771 /* This atom must be present, but leaving the values at zero
3772 * seems harmless. */
3773 avio_wb32(pb
, 28); /* size */
3774 ffio_wfourcc(pb
, "hmhd");
3775 avio_wb32(pb
, 0); /* version, flags */
3776 avio_wb16(pb
, 0); /* maxPDUsize */
3777 avio_wb16(pb
, 0); /* avgPDUsize */
3778 avio_wb32(pb
, 0); /* maxbitrate */
3779 avio_wb32(pb
, 0); /* avgbitrate */
3780 avio_wb32(pb
, 0); /* reserved */
3784 static int mov_write_minf_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVMuxContext
*mov
, MOVTrack
*track
)
3786 int64_t pos
= avio_tell(pb
);
3789 avio_wb32(pb
, 0); /* size */
3790 ffio_wfourcc(pb
, "minf");
3791 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
)
3792 mov_write_vmhd_tag(pb
);
3793 else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
)
3794 mov_write_smhd_tag(pb
);
3795 else if (track
->par
->codec_type
== AVMEDIA_TYPE_SUBTITLE
) {
3796 if (track
->tag
== MKTAG('t','e','x','t') || is_clcp_track(track
)) {
3797 mov_write_gmhd_tag(pb
, track
);
3798 } else if (track
->tag
== MOV_MP4_TTML_TAG
) {
3799 mov_write_sthd_tag(pb
);
3801 mov_write_nmhd_tag(pb
);
3803 } else if (track
->tag
== MKTAG('r','t','p',' ')) {
3804 mov_write_hmhd_tag(pb
);
3805 } else if (track
->tag
== MKTAG('t','m','c','d')) {
3806 if (track
->mode
!= MODE_MOV
)
3807 mov_write_nmhd_tag(pb
);
3809 mov_write_gmhd_tag(pb
, track
);
3810 } else if (track
->tag
== MKTAG('g','p','m','d')) {
3811 mov_write_gmhd_tag(pb
, track
);
3813 if (track
->mode
== MODE_MOV
) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3814 mov_write_hdlr_tag(s
, pb
, NULL
);
3815 mov_write_dinf_tag(pb
);
3816 if ((ret
= mov_write_stbl_tag(s
, pb
, mov
, track
)) < 0)
3818 return update_size(pb
, pos
);
3821 static void get_pts_range(MOVMuxContext
*mov
, MOVTrack
*track
,
3822 int64_t *start
, int64_t *end
)
3824 if (track
->tag
== MKTAG('t','m','c','d') && mov
->nb_meta_tmcd
) {
3825 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3826 // another track's duration, while the end_pts may be left at zero.
3827 // Calculate the pts duration for that track instead.
3828 get_pts_range(mov
, &mov
->tracks
[track
->src_track
], start
, end
);
3829 *start
= av_rescale(*start
, track
->timescale
,
3830 mov
->tracks
[track
->src_track
].timescale
);
3831 *end
= av_rescale(*end
, track
->timescale
,
3832 mov
->tracks
[track
->src_track
].timescale
);
3835 if (track
->end_pts
!= AV_NOPTS_VALUE
&&
3836 track
->start_dts
!= AV_NOPTS_VALUE
&&
3837 track
->start_cts
!= AV_NOPTS_VALUE
) {
3838 *start
= track
->start_dts
+ track
->start_cts
;
3839 *end
= track
->end_pts
;
3843 *end
= track
->track_duration
;
3846 static int64_t calc_samples_pts_duration(MOVMuxContext
*mov
, MOVTrack
*track
)
3849 get_pts_range(mov
, track
, &start
, &end
);
3853 // Calculate the actual duration of the track, after edits.
3854 // If it starts with a pts < 0, that is removed by the edit list.
3855 // If it starts with a pts > 0, the edit list adds a delay before that.
3856 // Thus, with edit lists enabled, the post-edit output of the file is
3857 // starting with pts=0.
3858 static int64_t calc_pts_duration(MOVMuxContext
*mov
, MOVTrack
*track
)
3861 get_pts_range(mov
, track
, &start
, &end
);
3862 if (mov
->use_editlist
!= 0)
3867 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext
*mov
, MOVTrack
*track
, int64_t duration
)
3869 if (track
&& track
->mode
== MODE_ISM
)
3871 if (duration
< INT32_MAX
)
3876 static int mov_write_mdhd_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
3879 int64_t duration
= calc_samples_pts_duration(mov
, track
);
3880 int version
= mov_mdhd_mvhd_tkhd_version(mov
, track
, duration
);
3882 (version
== 1) ? avio_wb32(pb
, 44) : avio_wb32(pb
, 32); /* size */
3883 ffio_wfourcc(pb
, "mdhd");
3884 avio_w8(pb
, version
);
3885 avio_wb24(pb
, 0); /* flags */
3887 avio_wb64(pb
, track
->time
);
3888 avio_wb64(pb
, track
->time
);
3890 avio_wb32(pb
, track
->time
); /* creation time */
3891 avio_wb32(pb
, track
->time
); /* modification time */
3893 avio_wb32(pb
, track
->timescale
); /* time scale (sample rate for audio) */
3894 if (!track
->entry
&& mov
->mode
== MODE_ISM
)
3895 (version
== 1) ? avio_wb64(pb
, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb
, 0xffffffff);
3896 else if (!track
->entry
)
3897 (version
== 1) ? avio_wb64(pb
, 0) : avio_wb32(pb
, 0);
3899 (version
== 1) ? avio_wb64(pb
, duration
) : avio_wb32(pb
, duration
); /* duration */
3900 avio_wb16(pb
, track
->language
); /* language */
3901 avio_wb16(pb
, 0); /* reserved (quality) */
3903 if (version
!= 0 && track
->mode
== MODE_MOV
) {
3904 av_log(NULL
, AV_LOG_ERROR
,
3905 "FATAL error, file duration too long for timebase, this file will not be\n"
3906 "playable with QuickTime. Choose a different timebase with "
3907 "-video_track_timescale or a different container format\n");
3913 static int mov_write_mdia_tag(AVFormatContext
*s
, AVIOContext
*pb
,
3914 MOVMuxContext
*mov
, MOVTrack
*track
)
3916 int64_t pos
= avio_tell(pb
);
3919 avio_wb32(pb
, 0); /* size */
3920 ffio_wfourcc(pb
, "mdia");
3921 mov_write_mdhd_tag(pb
, mov
, track
);
3922 mov_write_hdlr_tag(s
, pb
, track
);
3923 if ((ret
= mov_write_minf_tag(s
, pb
, mov
, track
)) < 0)
3925 return update_size(pb
, pos
);
3928 /* transformation matrix
3932 static void write_matrix(AVIOContext
*pb
, int16_t a
, int16_t b
, int16_t c
,
3933 int16_t d
, int16_t tx
, int16_t ty
)
3935 avio_wb32(pb
, a
<< 16); /* 16.16 format */
3936 avio_wb32(pb
, b
<< 16); /* 16.16 format */
3937 avio_wb32(pb
, 0); /* u in 2.30 format */
3938 avio_wb32(pb
, c
<< 16); /* 16.16 format */
3939 avio_wb32(pb
, d
<< 16); /* 16.16 format */
3940 avio_wb32(pb
, 0); /* v in 2.30 format */
3941 avio_wb32(pb
, tx
<< 16); /* 16.16 format */
3942 avio_wb32(pb
, ty
<< 16); /* 16.16 format */
3943 avio_wb32(pb
, 1 << 30); /* w in 2.30 format */
3946 static int mov_write_tkhd_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
3947 MOVTrack
*track
, AVStream
*st
)
3949 int64_t duration
= av_rescale_rnd(calc_pts_duration(mov
, track
),
3950 mov
->movie_timescale
, track
->timescale
,
3953 int flags
= MOV_TKHD_FLAG_IN_MOVIE
;
3956 uint32_t *display_matrix
= NULL
;
3959 if (mov
->mode
== MODE_AVIF
)
3960 if (!mov
->avif_loop_count
)
3961 duration
= INT64_MAX
;
3963 duration
*= mov
->avif_loop_count
;
3966 const AVPacketSideData
*sd
;
3967 if (mov
->per_stream_grouping
)
3970 group
= st
->codecpar
->codec_type
;
3972 sd
= av_packet_side_data_get(st
->codecpar
->coded_side_data
,
3973 st
->codecpar
->nb_coded_side_data
,
3974 AV_PKT_DATA_DISPLAYMATRIX
);
3975 if (sd
&& sd
->size
== 9 * sizeof(*display_matrix
))
3976 display_matrix
= (uint32_t *)sd
->data
;
3979 if (track
->flags
& MOV_TRACK_ENABLED
)
3980 flags
|= MOV_TKHD_FLAG_ENABLED
;
3982 version
= mov_mdhd_mvhd_tkhd_version(mov
, track
, duration
);
3984 (version
== 1) ? avio_wb32(pb
, 104) : avio_wb32(pb
, 92); /* size */
3985 ffio_wfourcc(pb
, "tkhd");
3986 avio_w8(pb
, version
);
3987 avio_wb24(pb
, flags
);
3989 avio_wb64(pb
, track
->time
);
3990 avio_wb64(pb
, track
->time
);
3992 avio_wb32(pb
, track
->time
); /* creation time */
3993 avio_wb32(pb
, track
->time
); /* modification time */
3995 avio_wb32(pb
, track
->track_id
); /* track-id */
3996 avio_wb32(pb
, 0); /* reserved */
3997 if (!track
->entry
&& mov
->mode
== MODE_ISM
)
3998 (version
== 1) ? avio_wb64(pb
, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb
, 0xffffffff);
3999 else if (!track
->entry
)
4000 (version
== 1) ? avio_wb64(pb
, 0) : avio_wb32(pb
, 0);
4002 (version
== 1) ? avio_wb64(pb
, duration
) : avio_wb32(pb
, duration
);
4004 avio_wb32(pb
, 0); /* reserved */
4005 avio_wb32(pb
, 0); /* reserved */
4006 avio_wb16(pb
, 0); /* layer */
4007 avio_wb16(pb
, group
); /* alternate group) */
4008 /* Volume, only for audio */
4009 if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
)
4010 avio_wb16(pb
, 0x0100);
4013 avio_wb16(pb
, 0); /* reserved */
4015 /* Matrix structure */
4016 if (display_matrix
) {
4017 for (i
= 0; i
< 9; i
++)
4018 avio_wb32(pb
, display_matrix
[i
]);
4020 write_matrix(pb
, 1, 0, 0, 1, 0, 0);
4022 /* Track width and height, for visual only */
4023 if (st
&& (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
||
4024 track
->par
->codec_type
== AVMEDIA_TYPE_SUBTITLE
)) {
4025 int64_t track_width_1616
;
4026 if (track
->mode
== MODE_MOV
|| track
->mode
== MODE_AVIF
) {
4027 track_width_1616
= track
->par
->width
* 0x10000ULL
;
4029 track_width_1616
= av_rescale(st
->sample_aspect_ratio
.num
,
4030 track
->par
->width
* 0x10000LL
,
4031 st
->sample_aspect_ratio
.den
);
4032 if (!track_width_1616
||
4033 track
->height
!= track
->par
->height
||
4034 track_width_1616
> UINT32_MAX
)
4035 track_width_1616
= track
->par
->width
* 0x10000ULL
;
4037 if (track_width_1616
> UINT32_MAX
) {
4038 av_log(mov
->fc
, AV_LOG_WARNING
, "track width is too large\n");
4039 track_width_1616
= 0;
4041 avio_wb32(pb
, track_width_1616
);
4042 if (track
->height
> 0xFFFF) {
4043 av_log(mov
->fc
, AV_LOG_WARNING
, "track height is too large\n");
4046 avio_wb32(pb
, track
->height
* 0x10000U
);
4054 static int mov_write_tapt_tag(AVIOContext
*pb
, MOVTrack
*track
)
4056 int32_t width
= av_rescale(track
->par
->sample_aspect_ratio
.num
, track
->par
->width
,
4057 track
->par
->sample_aspect_ratio
.den
);
4059 int64_t pos
= avio_tell(pb
);
4061 avio_wb32(pb
, 0); /* size */
4062 ffio_wfourcc(pb
, "tapt");
4065 ffio_wfourcc(pb
, "clef");
4067 avio_wb32(pb
, width
<< 16);
4068 avio_wb32(pb
, track
->par
->height
<< 16);
4071 ffio_wfourcc(pb
, "prof");
4073 avio_wb32(pb
, width
<< 16);
4074 avio_wb32(pb
, track
->par
->height
<< 16);
4077 ffio_wfourcc(pb
, "enof");
4079 avio_wb32(pb
, track
->par
->width
<< 16);
4080 avio_wb32(pb
, track
->par
->height
<< 16);
4082 return update_size(pb
, pos
);
4085 // This box is written in the following cases:
4086 // * Seems important for the psp playback. Without it the movie seems to hang.
4087 // * Used for specifying the looping behavior of animated AVIF (as specified
4088 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4089 static int mov_write_edts_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4092 int64_t duration
= av_rescale_rnd(calc_samples_pts_duration(mov
, track
),
4093 mov
->movie_timescale
, track
->timescale
,
4095 int version
= duration
< INT32_MAX
? 0 : 1;
4096 int entry_size
, entry_count
, size
;
4097 int64_t delay
, start_ct
= track
->start_cts
;
4098 int64_t start_dts
= track
->start_dts
;
4102 if (start_dts
!= track
->cluster
[0].dts
|| (start_ct
!= track
->cluster
[0].cts
&& track
->cluster
[0].dts
>= 0)) {
4104 av_log(mov
->fc
, AV_LOG_DEBUG
,
4105 "EDTS using dts:%"PRId64
" cts:%d instead of dts:%"PRId64
" cts:%"PRId64
" tid:%d\n",
4106 track
->cluster
[0].dts
, track
->cluster
[0].cts
,
4107 start_dts
, start_ct
, track
->track_id
);
4108 start_dts
= track
->cluster
[0].dts
;
4109 start_ct
= track
->cluster
[0].cts
;
4113 delay
= av_rescale_rnd(start_dts
+ start_ct
, mov
->movie_timescale
,
4114 track
->timescale
, AV_ROUND_DOWN
);
4116 if (mov
->mode
== MODE_AVIF
) {
4118 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4119 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4120 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4121 // edit list is repeated.
4122 flags
= mov
->avif_loop_count
!= 1;
4126 version
|= delay
< INT32_MAX
? 0 : 1;
4128 entry_size
= (version
== 1) ? 20 : 12;
4129 entry_count
= 1 + (delay
> 0);
4130 size
= 24 + entry_count
* entry_size
;
4132 /* write the atom data */
4133 avio_wb32(pb
, size
);
4134 ffio_wfourcc(pb
, "edts");
4135 avio_wb32(pb
, size
- 8);
4136 ffio_wfourcc(pb
, "elst");
4137 avio_w8(pb
, version
);
4138 avio_wb24(pb
, flags
); /* flags */
4140 avio_wb32(pb
, entry_count
);
4141 if (delay
> 0) { /* add an empty edit to delay presentation */
4142 /* In the positive delay case, the delay includes the cts
4143 * offset, and the second edit list entry below trims out
4144 * the same amount from the actual content. This makes sure
4145 * that the offset last sample is included in the edit
4146 * list duration as well. */
4148 avio_wb64(pb
, delay
);
4151 avio_wb32(pb
, delay
);
4154 avio_wb32(pb
, 0x00010000);
4155 } else if (mov
->mode
!= MODE_AVIF
) {
4156 /* Avoid accidentally ending up with start_ct = -1 which has got a
4157 * special meaning. Normally start_ct should end up positive or zero
4158 * here, but use FFMIN in case dts is a small positive integer
4159 * rounded to 0 when represented in movie timescale units. */
4160 av_assert0(av_rescale_rnd(start_dts
, mov
->movie_timescale
, track
->timescale
, AV_ROUND_DOWN
) <= 0);
4161 start_ct
= -FFMIN(start_dts
, 0);
4164 if (track
->iamf
&& track
->par
->codec_id
== AV_CODEC_ID_OPUS
)
4165 start_ct
= av_rescale(start_ct
, 48000, track
->par
->sample_rate
);
4167 /* Note, this delay is calculated from the pts of the first sample,
4168 * ensuring that we don't reduce the duration for cases with
4173 /* For fragmented files, we don't know the full length yet. Setting
4174 * duration to 0 allows us to only specify the offset, including
4175 * the rest of the content (from all future fragments) without specifying
4176 * an explicit duration.
4178 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4179 * don't reset duration to zero.
4181 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
&&
4182 !(mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
&& mov
->moov_written
))
4187 avio_wb64(pb
, duration
);
4188 avio_wb64(pb
, start_ct
);
4190 avio_wb32(pb
, duration
);
4191 avio_wb32(pb
, start_ct
);
4193 avio_wb32(pb
, 0x00010000);
4197 static int mov_write_tref_tag(AVIOContext
*pb
, MOVTrack
*track
)
4199 avio_wb32(pb
, 20); // size
4200 ffio_wfourcc(pb
, "tref");
4201 avio_wb32(pb
, 12); // size (subatom)
4202 avio_wl32(pb
, track
->tref_tag
);
4203 avio_wb32(pb
, track
->tref_id
);
4207 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4208 static int mov_write_uuid_tag_psp(AVIOContext
*pb
, MOVTrack
*mov
)
4210 avio_wb32(pb
, 0x34); /* size ... reports as 28 in mp4box! */
4211 ffio_wfourcc(pb
, "uuid");
4212 ffio_wfourcc(pb
, "USMT");
4213 avio_wb32(pb
, 0x21d24fce);
4214 avio_wb32(pb
, 0xbb88695c);
4215 avio_wb32(pb
, 0xfac9c740);
4216 avio_wb32(pb
, 0x1c); // another size here!
4217 ffio_wfourcc(pb
, "MTDT");
4218 avio_wb32(pb
, 0x00010012);
4219 avio_wb32(pb
, 0x0a);
4220 avio_wb32(pb
, 0x55c40000);
4226 static int mov_write_udta_sdp(AVIOContext
*pb
, MOVTrack
*track
)
4228 AVFormatContext
*ctx
= track
->rtp_ctx
;
4229 char buf
[1000] = "";
4232 ff_sdp_write_media(buf
, sizeof(buf
), ctx
->streams
[0], track
->src_track
,
4233 NULL
, NULL
, 0, 0, ctx
);
4234 av_strlcatf(buf
, sizeof(buf
), "a=control:streamid=%d\r\n", track
->track_id
);
4237 avio_wb32(pb
, len
+ 24);
4238 ffio_wfourcc(pb
, "udta");
4239 avio_wb32(pb
, len
+ 16);
4240 ffio_wfourcc(pb
, "hnti");
4241 avio_wb32(pb
, len
+ 8);
4242 ffio_wfourcc(pb
, "sdp ");
4243 avio_write(pb
, buf
, len
);
4247 static int mov_write_track_metadata(AVIOContext
*pb
, AVStream
*st
,
4248 const char *tag
, const char *str
)
4250 int64_t pos
= avio_tell(pb
);
4251 AVDictionaryEntry
*t
= av_dict_get(st
->metadata
, str
, NULL
, 0);
4252 if (!t
|| !utf8len(t
->value
))
4255 avio_wb32(pb
, 0); /* size */
4256 ffio_wfourcc(pb
, tag
); /* type */
4257 avio_write(pb
, t
->value
, strlen(t
->value
)); /* UTF8 string value */
4258 return update_size(pb
, pos
);
4261 static int mov_write_track_kind(AVIOContext
*pb
, const char *scheme_uri
,
4264 int64_t pos
= avio_tell(pb
);
4266 /* Box|FullBox basics */
4267 avio_wb32(pb
, 0); /* size placeholder */
4268 ffio_wfourcc(pb
, (const unsigned char *)"kind");
4269 avio_w8(pb
, 0); /* version = 0 */
4270 avio_wb24(pb
, 0); /* flags = 0 */
4272 /* Required null-terminated scheme URI */
4273 avio_write(pb
, (const unsigned char *)scheme_uri
,
4274 strlen(scheme_uri
));
4277 /* Optional value string */
4278 if (value
&& value
[0])
4279 avio_write(pb
, (const unsigned char *)value
,
4284 return update_size(pb
, pos
);
4287 static int mov_write_track_kinds(AVIOContext
*pb
, AVStream
*st
)
4289 int ret
= AVERROR_BUG
;
4291 for (int i
= 0; ff_mov_track_kind_table
[i
].scheme_uri
; i
++) {
4292 const struct MP4TrackKindMapping map
= ff_mov_track_kind_table
[i
];
4294 for (int j
= 0; map
.value_maps
[j
].disposition
; j
++) {
4295 const struct MP4TrackKindValueMapping value_map
= map
.value_maps
[j
];
4296 if (!(st
->disposition
& value_map
.disposition
))
4299 if ((ret
= mov_write_track_kind(pb
, map
.scheme_uri
, value_map
.value
)) < 0)
4307 static int mov_write_track_udta_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4310 AVIOContext
*pb_buf
;
4317 ret
= avio_open_dyn_buf(&pb_buf
);
4321 if (mov
->mode
& (MODE_MP4
|MODE_MOV
))
4322 mov_write_track_metadata(pb_buf
, st
, "name", "title");
4324 if (mov
->mode
& MODE_MP4
) {
4325 if ((ret
= mov_write_track_kinds(pb_buf
, st
)) < 0)
4329 if ((size
= avio_get_dyn_buf(pb_buf
, &buf
)) > 0) {
4330 avio_wb32(pb
, size
+ 8);
4331 ffio_wfourcc(pb
, "udta");
4332 avio_write(pb
, buf
, size
);
4334 ffio_free_dyn_buf(&pb_buf
);
4339 static int mov_write_trak_tag(AVFormatContext
*s
, AVIOContext
*pb
, MOVMuxContext
*mov
,
4340 MOVTrack
*track
, AVStream
*st
)
4342 int64_t pos
= avio_tell(pb
);
4343 int entry_backup
= track
->entry
;
4344 int chunk_backup
= track
->chunkCount
;
4347 /* If we want to have an empty moov, but some samples already have been
4348 * buffered (delay_moov), pretend that no samples have been written yet. */
4349 if (mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
)
4350 track
->chunkCount
= track
->entry
= 0;
4352 avio_wb32(pb
, 0); /* size */
4353 ffio_wfourcc(pb
, "trak");
4354 mov_write_tkhd_tag(pb
, mov
, track
, st
);
4356 av_assert2(mov
->use_editlist
>= 0);
4358 if (track
->start_dts
!= AV_NOPTS_VALUE
) {
4359 if (mov
->use_editlist
)
4360 mov_write_edts_tag(pb
, mov
, track
); // PSP Movies and several other cases require edts box
4361 else if ((track
->entry
&& track
->cluster
[0].dts
) || track
->mode
== MODE_PSP
|| is_clcp_track(track
))
4362 av_log(mov
->fc
, AV_LOG_WARNING
,
4363 "Not writing any edit list even though one would have been required\n");
4366 if (mov
->is_animated_avif
)
4367 mov_write_edts_tag(pb
, mov
, track
);
4369 if (track
->tref_tag
)
4370 mov_write_tref_tag(pb
, track
);
4372 if ((ret
= mov_write_mdia_tag(s
, pb
, mov
, track
)) < 0)
4374 if (track
->mode
== MODE_PSP
)
4375 mov_write_uuid_tag_psp(pb
, track
); // PSP Movies require this uuid box
4376 if (track
->tag
== MKTAG('r','t','p',' '))
4377 mov_write_udta_sdp(pb
, track
);
4378 if (track
->mode
== MODE_MOV
) {
4379 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
4380 double sample_aspect_ratio
= av_q2d(st
->sample_aspect_ratio
);
4381 if (st
->sample_aspect_ratio
.num
&& 1.0 != sample_aspect_ratio
) {
4382 mov_write_tapt_tag(pb
, track
);
4385 if (is_clcp_track(track
) && st
->sample_aspect_ratio
.num
) {
4386 mov_write_tapt_tag(pb
, track
);
4389 mov_write_track_udta_tag(pb
, mov
, st
);
4390 track
->entry
= entry_backup
;
4391 track
->chunkCount
= chunk_backup
;
4392 return update_size(pb
, pos
);
4395 static int mov_write_iods_tag(AVIOContext
*pb
, MOVMuxContext
*mov
)
4397 int i
, has_audio
= 0, has_video
= 0;
4398 int64_t pos
= avio_tell(pb
);
4399 int audio_profile
= mov
->iods_audio_profile
;
4400 int video_profile
= mov
->iods_video_profile
;
4401 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
4402 if (mov
->tracks
[i
].entry
> 0 || mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
) {
4403 has_audio
|= mov
->tracks
[i
].par
->codec_type
== AVMEDIA_TYPE_AUDIO
;
4404 has_video
|= mov
->tracks
[i
].par
->codec_type
== AVMEDIA_TYPE_VIDEO
;
4407 if (audio_profile
< 0)
4408 audio_profile
= 0xFF - has_audio
;
4409 if (video_profile
< 0)
4410 video_profile
= 0xFF - has_video
;
4411 avio_wb32(pb
, 0x0); /* size */
4412 ffio_wfourcc(pb
, "iods");
4413 avio_wb32(pb
, 0); /* version & flags */
4414 put_descr(pb
, 0x10, 7);
4415 avio_wb16(pb
, 0x004f);
4418 avio_w8(pb
, audio_profile
);
4419 avio_w8(pb
, video_profile
);
4421 return update_size(pb
, pos
);
4424 static int mov_write_trex_tag(AVIOContext
*pb
, MOVTrack
*track
)
4426 avio_wb32(pb
, 0x20); /* size */
4427 ffio_wfourcc(pb
, "trex");
4428 avio_wb32(pb
, 0); /* version & flags */
4429 avio_wb32(pb
, track
->track_id
); /* track ID */
4430 avio_wb32(pb
, 1); /* default sample description index */
4431 avio_wb32(pb
, 0); /* default sample duration */
4432 avio_wb32(pb
, 0); /* default sample size */
4433 avio_wb32(pb
, 0); /* default sample flags */
4437 static int mov_write_mvex_tag(AVIOContext
*pb
, MOVMuxContext
*mov
)
4439 int64_t pos
= avio_tell(pb
);
4441 avio_wb32(pb
, 0x0); /* size */
4442 ffio_wfourcc(pb
, "mvex");
4443 for (i
= 0; i
< mov
->nb_tracks
; i
++)
4444 mov_write_trex_tag(pb
, &mov
->tracks
[i
]);
4445 return update_size(pb
, pos
);
4448 static int mov_write_mvhd_tag(AVIOContext
*pb
, MOVMuxContext
*mov
)
4450 int max_track_id
= 1, i
;
4451 int64_t max_track_len
= 0;
4455 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
4456 if (mov
->tracks
[i
].entry
> 0 && mov
->tracks
[i
].timescale
) {
4457 int64_t max_track_len_temp
= av_rescale_rnd(
4458 calc_pts_duration(mov
, &mov
->tracks
[i
]),
4459 mov
->movie_timescale
,
4460 mov
->tracks
[i
].timescale
,
4462 if (max_track_len
< max_track_len_temp
)
4463 max_track_len
= max_track_len_temp
;
4464 if (max_track_id
< mov
->tracks
[i
].track_id
)
4465 max_track_id
= mov
->tracks
[i
].track_id
;
4468 /* If using delay_moov, make sure the output is the same as if no
4469 * samples had been written yet. */
4470 if (mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
) {
4475 version
= mov_mdhd_mvhd_tkhd_version(mov
, NULL
, max_track_len
);
4476 avio_wb32(pb
, version
== 1 ? 120 : 108); /* size */
4478 ffio_wfourcc(pb
, "mvhd");
4479 avio_w8(pb
, version
);
4480 avio_wb24(pb
, 0); /* flags */
4482 avio_wb64(pb
, mov
->time
);
4483 avio_wb64(pb
, mov
->time
);
4485 avio_wb32(pb
, mov
->time
); /* creation time */
4486 avio_wb32(pb
, mov
->time
); /* modification time */
4489 timescale
= mov
->movie_timescale
;
4490 if (mov
->mode
== MODE_AVIF
&& !timescale
)
4491 timescale
= mov
->tracks
[0].timescale
;
4493 avio_wb32(pb
, timescale
);
4494 (version
== 1) ? avio_wb64(pb
, max_track_len
) : avio_wb32(pb
, max_track_len
); /* duration of longest track */
4496 avio_wb32(pb
, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4497 avio_wb16(pb
, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4498 ffio_fill(pb
, 0, 2 + 2 * 4); /* reserved */
4500 /* Matrix structure */
4501 write_matrix(pb
, 1, 0, 0, 1, 0, 0);
4503 avio_wb32(pb
, 0); /* reserved (preview time) */
4504 avio_wb32(pb
, 0); /* reserved (preview duration) */
4505 avio_wb32(pb
, 0); /* reserved (poster time) */
4506 avio_wb32(pb
, 0); /* reserved (selection time) */
4507 avio_wb32(pb
, 0); /* reserved (selection duration) */
4508 avio_wb32(pb
, 0); /* reserved (current time) */
4509 avio_wb32(pb
, max_track_id
+ 1); /* Next track id */
4513 static int mov_write_itunes_hdlr_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4516 avio_wb32(pb
, 33); /* size */
4517 ffio_wfourcc(pb
, "hdlr");
4520 ffio_wfourcc(pb
, "mdir");
4521 ffio_wfourcc(pb
, "appl");
4528 /* helper function to write a data tag with the specified string as data */
4529 static int mov_write_string_data_tag(AVIOContext
*pb
, const char *data
, int lang
, int long_style
)
4531 size_t data_len
= strlen(data
);
4533 int size
= 16 + data_len
;
4534 avio_wb32(pb
, size
); /* size */
4535 ffio_wfourcc(pb
, "data");
4538 avio_write(pb
, data
, data_len
);
4541 avio_wb16(pb
, data_len
); /* string length */
4543 lang
= ff_mov_iso639_to_lang("und", 1);
4544 avio_wb16(pb
, lang
);
4545 avio_write(pb
, data
, data_len
);
4546 return data_len
+ 4;
4550 static int mov_write_string_tag(AVIOContext
*pb
, const char *name
,
4551 const char *value
, int lang
, int long_style
)
4554 if (value
&& value
[0]) {
4555 int64_t pos
= avio_tell(pb
);
4556 avio_wb32(pb
, 0); /* size */
4557 ffio_wfourcc(pb
, name
);
4558 mov_write_string_data_tag(pb
, value
, lang
, long_style
);
4559 size
= update_size(pb
, pos
);
4564 static AVDictionaryEntry
*get_metadata_lang(AVFormatContext
*s
,
4565 const char *tag
, int *lang
)
4568 AVDictionaryEntry
*t
, *t2
= NULL
;
4573 if (!(t
= av_dict_get(s
->metadata
, tag
, NULL
, 0)))
4576 len
= strlen(t
->key
);
4577 snprintf(tag2
, sizeof(tag2
), "%s-", tag
);
4578 while ((t2
= av_dict_get(s
->metadata
, tag2
, t2
, AV_DICT_IGNORE_SUFFIX
))) {
4579 len2
= strlen(t2
->key
);
4580 if (len2
== len
+ 4 && !strcmp(t
->value
, t2
->value
)
4581 && (l
= ff_mov_iso639_to_lang(&t2
->key
[len2
- 3], 1)) >= 0) {
4589 static int mov_write_string_metadata(AVFormatContext
*s
, AVIOContext
*pb
,
4590 const char *name
, const char *tag
,
4594 AVDictionaryEntry
*t
= get_metadata_lang(s
, tag
, &lang
);
4597 return mov_write_string_tag(pb
, name
, t
->value
, lang
, long_style
);
4600 /* iTunes bpm number */
4601 static int mov_write_tmpo_tag(AVIOContext
*pb
, AVFormatContext
*s
)
4603 AVDictionaryEntry
*t
= av_dict_get(s
->metadata
, "tmpo", NULL
, 0);
4604 int size
= 0, tmpo
= t
? atoi(t
->value
) : 0;
4607 avio_wb32(pb
, size
);
4608 ffio_wfourcc(pb
, "tmpo");
4609 avio_wb32(pb
, size
-8); /* size */
4610 ffio_wfourcc(pb
, "data");
4611 avio_wb32(pb
, 0x15); //type specifier
4613 avio_wb16(pb
, tmpo
); // data
4618 /* 3GPP TS 26.244 */
4619 static int mov_write_loci_tag(AVFormatContext
*s
, AVIOContext
*pb
)
4622 int64_t pos
= avio_tell(pb
);
4623 double latitude
, longitude
, altitude
;
4624 int32_t latitude_fix
, longitude_fix
, altitude_fix
;
4625 AVDictionaryEntry
*t
= get_metadata_lang(s
, "location", &lang
);
4626 const char *ptr
, *place
= "";
4628 static const char *astronomical_body
= "earth";
4633 latitude
= strtod(ptr
, &end
);
4635 av_log(s
, AV_LOG_WARNING
, "malformed location metadata\n");
4639 longitude
= strtod(ptr
, &end
);
4641 av_log(s
, AV_LOG_WARNING
, "malformed location metadata\n");
4645 altitude
= strtod(ptr
, &end
);
4646 /* If no altitude was present, the default 0 should be fine */
4650 latitude_fix
= (int32_t) ((1 << 16) * latitude
);
4651 longitude_fix
= (int32_t) ((1 << 16) * longitude
);
4652 altitude_fix
= (int32_t) ((1 << 16) * altitude
);
4654 avio_wb32(pb
, 0); /* size */
4655 ffio_wfourcc(pb
, "loci"); /* type */
4656 avio_wb32(pb
, 0); /* version + flags */
4657 avio_wb16(pb
, lang
);
4658 avio_write(pb
, place
, strlen(place
) + 1);
4659 avio_w8(pb
, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4660 avio_wb32(pb
, longitude_fix
);
4661 avio_wb32(pb
, latitude_fix
);
4662 avio_wb32(pb
, altitude_fix
);
4663 avio_write(pb
, astronomical_body
, strlen(astronomical_body
) + 1);
4664 avio_w8(pb
, 0); /* additional notes, null terminated string */
4666 return update_size(pb
, pos
);
4669 /* iTunes track or disc number */
4670 static int mov_write_trkn_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4671 AVFormatContext
*s
, int disc
)
4673 AVDictionaryEntry
*t
= av_dict_get(s
->metadata
,
4674 disc
? "disc" : "track",
4676 int size
= 0, track
= t
? atoi(t
->value
) : 0;
4679 char *slash
= strchr(t
->value
, '/');
4681 tracks
= atoi(slash
+ 1);
4682 avio_wb32(pb
, 32); /* size */
4683 ffio_wfourcc(pb
, disc
? "disk" : "trkn");
4684 avio_wb32(pb
, 24); /* size */
4685 ffio_wfourcc(pb
, "data");
4686 avio_wb32(pb
, 0); // 8 bytes empty
4688 avio_wb16(pb
, 0); // empty
4689 avio_wb16(pb
, track
); // track / disc number
4690 avio_wb16(pb
, tracks
); // total track / disc number
4691 avio_wb16(pb
, 0); // empty
4697 static int mov_write_int8_metadata(AVFormatContext
*s
, AVIOContext
*pb
,
4698 const char *name
, const char *tag
,
4701 AVDictionaryEntry
*t
= NULL
;
4703 int size
= 24 + len
;
4705 if (len
!= 1 && len
!= 4)
4708 if (!(t
= av_dict_get(s
->metadata
, tag
, NULL
, 0)))
4710 num
= atoi(t
->value
);
4712 avio_wb32(pb
, size
);
4713 ffio_wfourcc(pb
, name
);
4714 avio_wb32(pb
, size
- 8);
4715 ffio_wfourcc(pb
, "data");
4716 avio_wb32(pb
, 0x15);
4718 if (len
==4) avio_wb32(pb
, num
);
4719 else avio_w8 (pb
, num
);
4724 static int mov_write_covr(AVIOContext
*pb
, AVFormatContext
*s
)
4726 MOVMuxContext
*mov
= s
->priv_data
;
4729 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
4730 MOVTrack
*trk
= &mov
->tracks
[i
];
4732 if (!is_cover_image(trk
->st
) || trk
->cover_image
->size
<= 0)
4736 pos
= avio_tell(pb
);
4738 ffio_wfourcc(pb
, "covr");
4740 avio_wb32(pb
, 16 + trk
->cover_image
->size
);
4741 ffio_wfourcc(pb
, "data");
4742 avio_wb32(pb
, trk
->tag
);
4744 avio_write(pb
, trk
->cover_image
->data
, trk
->cover_image
->size
);
4747 return pos
? update_size(pb
, pos
) : 0;
4750 /* iTunes meta data list */
4751 static int mov_write_ilst_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4754 int64_t pos
= avio_tell(pb
);
4755 avio_wb32(pb
, 0); /* size */
4756 ffio_wfourcc(pb
, "ilst");
4757 mov_write_string_metadata(s
, pb
, "\251nam", "title" , 1);
4758 mov_write_string_metadata(s
, pb
, "\251ART", "artist" , 1);
4759 mov_write_string_metadata(s
, pb
, "aART", "album_artist", 1);
4760 mov_write_string_metadata(s
, pb
, "\251wrt", "composer" , 1);
4761 mov_write_string_metadata(s
, pb
, "\251alb", "album" , 1);
4762 mov_write_string_metadata(s
, pb
, "\251day", "date" , 1);
4763 if (!mov_write_string_metadata(s
, pb
, "\251too", "encoding_tool", 1)) {
4764 if (!(s
->flags
& AVFMT_FLAG_BITEXACT
))
4765 mov_write_string_tag(pb
, "\251too", LIBAVFORMAT_IDENT
, 0, 1);
4767 mov_write_string_metadata(s
, pb
, "\251cmt", "comment" , 1);
4768 mov_write_string_metadata(s
, pb
, "\251gen", "genre" , 1);
4769 mov_write_string_metadata(s
, pb
, "cprt", "copyright", 1);
4770 mov_write_string_metadata(s
, pb
, "\251grp", "grouping" , 1);
4771 mov_write_string_metadata(s
, pb
, "\251lyr", "lyrics" , 1);
4772 mov_write_string_metadata(s
, pb
, "desc", "description",1);
4773 mov_write_string_metadata(s
, pb
, "ldes", "synopsis" , 1);
4774 mov_write_string_metadata(s
, pb
, "tvsh", "show" , 1);
4775 mov_write_string_metadata(s
, pb
, "tven", "episode_id",1);
4776 mov_write_string_metadata(s
, pb
, "tvnn", "network" , 1);
4777 mov_write_string_metadata(s
, pb
, "keyw", "keywords" , 1);
4778 mov_write_int8_metadata (s
, pb
, "tves", "episode_sort",4);
4779 mov_write_int8_metadata (s
, pb
, "tvsn", "season_number",4);
4780 mov_write_int8_metadata (s
, pb
, "stik", "media_type",1);
4781 mov_write_int8_metadata (s
, pb
, "hdvd", "hd_video", 1);
4782 mov_write_int8_metadata (s
, pb
, "pgap", "gapless_playback",1);
4783 mov_write_int8_metadata (s
, pb
, "cpil", "compilation", 1);
4784 mov_write_covr(pb
, s
);
4785 mov_write_trkn_tag(pb
, mov
, s
, 0); // track number
4786 mov_write_trkn_tag(pb
, mov
, s
, 1); // disc number
4787 mov_write_tmpo_tag(pb
, s
);
4788 return update_size(pb
, pos
);
4791 static int mov_write_mdta_hdlr_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4794 avio_wb32(pb
, 33); /* size */
4795 ffio_wfourcc(pb
, "hdlr");
4798 ffio_wfourcc(pb
, "mdta");
4806 static int mov_write_mdta_keys_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4809 const AVDictionaryEntry
*t
= NULL
;
4810 int64_t pos
= avio_tell(pb
);
4811 int64_t curpos
, entry_pos
;
4814 avio_wb32(pb
, 0); /* size */
4815 ffio_wfourcc(pb
, "keys");
4817 entry_pos
= avio_tell(pb
);
4818 avio_wb32(pb
, 0); /* entry count */
4820 while (t
= av_dict_iterate(s
->metadata
, t
)) {
4821 size_t key_len
= strlen(t
->key
);
4822 avio_wb32(pb
, key_len
+ 8);
4823 ffio_wfourcc(pb
, "mdta");
4824 avio_write(pb
, t
->key
, key_len
);
4827 curpos
= avio_tell(pb
);
4828 avio_seek(pb
, entry_pos
, SEEK_SET
);
4829 avio_wb32(pb
, count
); // rewrite entry count
4830 avio_seek(pb
, curpos
, SEEK_SET
);
4832 return update_size(pb
, pos
);
4835 static int mov_write_mdta_ilst_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4838 const AVDictionaryEntry
*t
= NULL
;
4839 int64_t pos
= avio_tell(pb
);
4840 int count
= 1; /* keys are 1-index based */
4842 avio_wb32(pb
, 0); /* size */
4843 ffio_wfourcc(pb
, "ilst");
4845 while (t
= av_dict_iterate(s
->metadata
, t
)) {
4846 int64_t entry_pos
= avio_tell(pb
);
4847 avio_wb32(pb
, 0); /* size */
4848 avio_wb32(pb
, count
); /* key */
4849 mov_write_string_data_tag(pb
, t
->value
, 0, 1);
4850 update_size(pb
, entry_pos
);
4853 return update_size(pb
, pos
);
4856 /* meta data tags */
4857 static int mov_write_meta_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4861 int64_t pos
= avio_tell(pb
);
4862 avio_wb32(pb
, 0); /* size */
4863 ffio_wfourcc(pb
, "meta");
4865 if (mov
->flags
& FF_MOV_FLAG_USE_MDTA
) {
4866 mov_write_mdta_hdlr_tag(pb
, mov
, s
);
4867 mov_write_mdta_keys_tag(pb
, mov
, s
);
4868 mov_write_mdta_ilst_tag(pb
, mov
, s
);
4869 } else if (mov
->mode
== MODE_AVIF
) {
4870 mov_write_hdlr_tag(s
, pb
, &mov
->tracks
[0]);
4871 // We always write the primary item id as 1 since only one track is
4872 // supported for AVIF.
4873 mov_write_pitm_tag(pb
, 1);
4874 mov_write_iloc_tag(pb
, mov
, s
);
4875 mov_write_iinf_tag(pb
, mov
, s
);
4876 if (mov
->nb_streams
> 1)
4877 mov_write_iref_tag(pb
, mov
, s
);
4878 mov_write_iprp_tag(pb
, mov
, s
);
4880 /* iTunes metadata tag */
4881 mov_write_itunes_hdlr_tag(pb
, mov
, s
);
4882 mov_write_ilst_tag(pb
, mov
, s
);
4884 size
= update_size(pb
, pos
);
4888 static int mov_write_raw_metadata_tag(AVFormatContext
*s
, AVIOContext
*pb
,
4889 const char *name
, const char *key
)
4892 AVDictionaryEntry
*t
;
4894 if (!(t
= av_dict_get(s
->metadata
, key
, NULL
, 0)))
4897 len
= strlen(t
->value
);
4900 avio_wb32(pb
, size
);
4901 ffio_wfourcc(pb
, name
);
4902 avio_write(pb
, t
->value
, len
);
4908 static int ascii_to_wc(AVIOContext
*pb
, const uint8_t *b
)
4912 GET_UTF8(val
, *b
++, return -1;)
4915 avio_wb16(pb
, 0x00);
4919 static uint16_t language_code(const char *str
)
4921 return (((str
[0] - 0x60) & 0x1F) << 10) +
4922 (((str
[1] - 0x60) & 0x1F) << 5) +
4923 (( str
[2] - 0x60) & 0x1F);
4926 static int mov_write_3gp_udta_tag(AVIOContext
*pb
, AVFormatContext
*s
,
4927 const char *tag
, const char *str
)
4929 int64_t pos
= avio_tell(pb
);
4930 AVDictionaryEntry
*t
= av_dict_get(s
->metadata
, str
, NULL
, 0);
4931 if (!t
|| !utf8len(t
->value
))
4933 avio_wb32(pb
, 0); /* size */
4934 ffio_wfourcc(pb
, tag
); /* type */
4935 avio_wb32(pb
, 0); /* version + flags */
4936 if (!strcmp(tag
, "yrrc"))
4937 avio_wb16(pb
, atoi(t
->value
));
4939 avio_wb16(pb
, language_code("eng")); /* language */
4940 avio_write(pb
, t
->value
, strlen(t
->value
) + 1); /* UTF8 string value */
4941 if (!strcmp(tag
, "albm") &&
4942 (t
= av_dict_get(s
->metadata
, "track", NULL
, 0)))
4943 avio_w8(pb
, atoi(t
->value
));
4945 return update_size(pb
, pos
);
4948 static int mov_write_chpl_tag(AVIOContext
*pb
, AVFormatContext
*s
)
4950 int64_t pos
= avio_tell(pb
);
4951 int i
, nb_chapters
= FFMIN(s
->nb_chapters
, 255);
4953 avio_wb32(pb
, 0); // size
4954 ffio_wfourcc(pb
, "chpl");
4955 avio_wb32(pb
, 0x01000000); // version + flags
4956 avio_wb32(pb
, 0); // unknown
4957 avio_w8(pb
, nb_chapters
);
4959 for (i
= 0; i
< nb_chapters
; i
++) {
4960 AVChapter
*c
= s
->chapters
[i
];
4961 AVDictionaryEntry
*t
;
4962 avio_wb64(pb
, av_rescale_q(c
->start
, c
->time_base
, (AVRational
){1,10000000}));
4964 if ((t
= av_dict_get(c
->metadata
, "title", NULL
, 0))) {
4965 int len
= FFMIN(strlen(t
->value
), 255);
4967 avio_write(pb
, t
->value
, len
);
4971 return update_size(pb
, pos
);
4974 static int mov_write_udta_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
4977 AVIOContext
*pb_buf
;
4981 ret
= avio_open_dyn_buf(&pb_buf
);
4985 if (mov
->mode
& MODE_3GP
) {
4986 mov_write_3gp_udta_tag(pb_buf
, s
, "perf", "artist");
4987 mov_write_3gp_udta_tag(pb_buf
, s
, "titl", "title");
4988 mov_write_3gp_udta_tag(pb_buf
, s
, "auth", "author");
4989 mov_write_3gp_udta_tag(pb_buf
, s
, "gnre", "genre");
4990 mov_write_3gp_udta_tag(pb_buf
, s
, "dscp", "comment");
4991 mov_write_3gp_udta_tag(pb_buf
, s
, "albm", "album");
4992 mov_write_3gp_udta_tag(pb_buf
, s
, "cprt", "copyright");
4993 mov_write_3gp_udta_tag(pb_buf
, s
, "yrrc", "date");
4994 mov_write_loci_tag(s
, pb_buf
);
4995 } else if (mov
->mode
== MODE_MOV
&& !(mov
->flags
& FF_MOV_FLAG_USE_MDTA
)) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
4996 mov_write_string_metadata(s
, pb_buf
, "\251ART", "artist", 0);
4997 mov_write_string_metadata(s
, pb_buf
, "\251nam", "title", 0);
4998 mov_write_string_metadata(s
, pb_buf
, "\251aut", "author", 0);
4999 mov_write_string_metadata(s
, pb_buf
, "\251alb", "album", 0);
5000 mov_write_string_metadata(s
, pb_buf
, "\251day", "date", 0);
5001 mov_write_string_metadata(s
, pb_buf
, "\251swr", "encoder", 0);
5002 // currently ignored by mov.c
5003 mov_write_string_metadata(s
, pb_buf
, "\251des", "comment", 0);
5004 // add support for libquicktime, this atom is also actually read by mov.c
5005 mov_write_string_metadata(s
, pb_buf
, "\251cmt", "comment", 0);
5006 mov_write_string_metadata(s
, pb_buf
, "\251gen", "genre", 0);
5007 mov_write_string_metadata(s
, pb_buf
, "\251cpy", "copyright", 0);
5008 mov_write_string_metadata(s
, pb_buf
, "\251mak", "make", 0);
5009 mov_write_string_metadata(s
, pb_buf
, "\251mod", "model", 0);
5010 mov_write_string_metadata(s
, pb_buf
, "\251xyz", "location", 0);
5011 mov_write_string_metadata(s
, pb_buf
, "\251key", "keywords", 0);
5012 mov_write_raw_metadata_tag(s
, pb_buf
, "XMP_", "xmp");
5014 /* iTunes meta data */
5015 mov_write_meta_tag(pb_buf
, mov
, s
);
5016 mov_write_loci_tag(s
, pb_buf
);
5019 if (s
->nb_chapters
&& !(mov
->flags
& FF_MOV_FLAG_DISABLE_CHPL
))
5020 mov_write_chpl_tag(pb_buf
, s
);
5022 if ((size
= avio_get_dyn_buf(pb_buf
, &buf
)) > 0) {
5023 avio_wb32(pb
, size
+ 8);
5024 ffio_wfourcc(pb
, "udta");
5025 avio_write(pb
, buf
, size
);
5027 ffio_free_dyn_buf(&pb_buf
);
5032 static void mov_write_psp_udta_tag(AVIOContext
*pb
,
5033 const char *str
, const char *lang
, int type
)
5035 int len
= utf8len(str
) + 1;
5038 avio_wb16(pb
, len
* 2 + 10); /* size */
5039 avio_wb32(pb
, type
); /* type */
5040 avio_wb16(pb
, language_code(lang
)); /* language */
5041 avio_wb16(pb
, 0x01); /* ? */
5042 ascii_to_wc(pb
, str
);
5045 static int mov_write_uuidusmt_tag(AVIOContext
*pb
, AVFormatContext
*s
)
5047 AVDictionaryEntry
*title
= av_dict_get(s
->metadata
, "title", NULL
, 0);
5051 pos
= avio_tell(pb
);
5052 avio_wb32(pb
, 0); /* size placeholder*/
5053 ffio_wfourcc(pb
, "uuid");
5054 ffio_wfourcc(pb
, "USMT");
5055 avio_wb32(pb
, 0x21d24fce); /* 96 bit UUID */
5056 avio_wb32(pb
, 0xbb88695c);
5057 avio_wb32(pb
, 0xfac9c740);
5059 pos2
= avio_tell(pb
);
5060 avio_wb32(pb
, 0); /* size placeholder*/
5061 ffio_wfourcc(pb
, "MTDT");
5065 avio_wb16(pb
, 0x0C); /* size */
5066 avio_wb32(pb
, 0x0B); /* type */
5067 avio_wb16(pb
, language_code("und")); /* language */
5068 avio_wb16(pb
, 0x0); /* ? */
5069 avio_wb16(pb
, 0x021C); /* data */
5071 if (!(s
->flags
& AVFMT_FLAG_BITEXACT
))
5072 mov_write_psp_udta_tag(pb
, LIBAVFORMAT_IDENT
, "eng", 0x04);
5073 mov_write_psp_udta_tag(pb
, title
->value
, "eng", 0x01);
5074 mov_write_psp_udta_tag(pb
, "2006/04/01 11:11:11", "und", 0x03);
5076 update_size(pb
, pos2
);
5077 return update_size(pb
, pos
);
5083 static int mov_write_pssh_tag(AVIOContext
*pb
, AVStream
*st
)
5085 AVEncryptionInitInfo
*info
;
5086 const AVPacketSideData
*sd
= av_packet_side_data_get(st
->codecpar
->coded_side_data
,
5087 st
->codecpar
->nb_coded_side_data
,
5088 AV_PKT_DATA_ENCRYPTION_INIT_INFO
);
5092 info
= av_encryption_init_info_get_side_data(sd
->data
, sd
->size
);
5093 for (AVEncryptionInitInfo
*copy
= info
; copy
; copy
= copy
->next
) {
5096 if (!copy
->data_size
&& !copy
->num_key_ids
)
5099 pos
= avio_tell(pb
);
5100 avio_wb32(pb
, 0); /* size placeholder */
5101 ffio_wfourcc(pb
, "pssh");
5102 avio_w8(pb
, 1); /* version */
5104 for (int i
= 0; i
< copy
->system_id_size
; i
++)
5105 avio_w8(pb
, copy
->system_id
[i
]);
5106 avio_wb32(pb
, copy
->num_key_ids
);
5107 for (int i
= 0; i
< copy
->num_key_ids
; i
++)
5108 for (int j
= 0; j
< copy
->key_id_size
; j
++)
5109 avio_w8(pb
, copy
->key_ids
[i
][j
]);
5110 avio_wb32(pb
, copy
->data_size
);
5111 avio_write(pb
, copy
->data
, copy
->data_size
);
5112 update_size(pb
, pos
);
5115 av_encryption_init_info_free(info
);
5120 static void build_chunks(MOVTrack
*trk
)
5123 MOVIentry
*chunk
= &trk
->cluster
[0];
5124 uint64_t chunkSize
= chunk
->size
;
5125 chunk
->chunkNum
= 1;
5126 if (trk
->chunkCount
)
5128 trk
->chunkCount
= 1;
5129 for (i
= 1; i
<trk
->entry
; i
++){
5130 if (chunk
->pos
+ chunkSize
== trk
->cluster
[i
].pos
&&
5131 chunk
->stsd_index
== trk
->cluster
[i
].stsd_index
&&
5132 chunkSize
+ trk
->cluster
[i
].size
< (1<<20)){
5133 chunkSize
+= trk
->cluster
[i
].size
;
5134 chunk
->samples_in_chunk
+= trk
->cluster
[i
].entries
;
5136 trk
->cluster
[i
].chunkNum
= chunk
->chunkNum
+1;
5137 chunk
=&trk
->cluster
[i
];
5138 chunkSize
= chunk
->size
;
5145 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5146 * the stream ids are used as track ids.
5148 * This assumes mov->tracks and s->streams are in the same order and
5149 * there are no gaps in either of them (so mov->tracks[n] refers to
5152 * As an exception, there can be more entries in
5153 * s->streams than in mov->tracks, in which case new track ids are
5154 * generated (starting after the largest found stream id).
5156 static int mov_setup_track_ids(MOVMuxContext
*mov
, AVFormatContext
*s
)
5160 if (mov
->track_ids_ok
)
5163 if (mov
->use_stream_ids_as_track_ids
) {
5164 int next_generated_track_id
= 0;
5165 for (i
= 0; i
< mov
->nb_streams
; i
++) {
5166 AVStream
*st
= mov
->tracks
[i
].st
;
5167 if (st
->id
> next_generated_track_id
)
5168 next_generated_track_id
= st
->id
;
5171 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5172 if (mov
->tracks
[i
].entry
<= 0 && !(mov
->flags
& FF_MOV_FLAG_FRAGMENT
))
5175 mov
->tracks
[i
].track_id
= i
>= mov
->nb_streams
? ++next_generated_track_id
: mov
->tracks
[i
].st
->id
;
5178 int last_track_id
= 0;
5179 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5180 if (mov
->tracks
[i
].entry
<= 0 && !(mov
->flags
& FF_MOV_FLAG_FRAGMENT
))
5184 mov
->tracks
[i
].track_id
= (mov
->tracks
[i
].st
5185 ? FFMAX(mov
->tracks
[i
].st
->index
, last_track_id
)
5186 : FFMAX(i
, last_track_id
)) + 1;
5190 mov
->track_ids_ok
= 1;
5195 static int mov_write_moov_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
5199 int64_t pos
= avio_tell(pb
);
5200 avio_wb32(pb
, 0); /* size placeholder*/
5201 ffio_wfourcc(pb
, "moov");
5203 mov_setup_track_ids(mov
, s
);
5205 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5206 if (mov
->tracks
[i
].entry
<= 0 && !(mov
->flags
& FF_MOV_FLAG_FRAGMENT
))
5209 mov
->tracks
[i
].time
= mov
->time
;
5211 if (mov
->tracks
[i
].entry
)
5212 build_chunks(&mov
->tracks
[i
]);
5215 if (mov
->chapter_track
)
5216 for (i
= 0; i
< mov
->nb_streams
; i
++) {
5217 mov
->tracks
[i
].tref_tag
= MKTAG('c','h','a','p');
5218 mov
->tracks
[i
].tref_id
= mov
->tracks
[mov
->chapter_track
].track_id
;
5220 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5221 MOVTrack
*track
= &mov
->tracks
[i
];
5222 if (track
->tag
== MKTAG('r','t','p',' ')) {
5223 track
->tref_tag
= MKTAG('h','i','n','t');
5224 track
->tref_id
= mov
->tracks
[track
->src_track
].track_id
;
5225 } else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
5226 const AVPacketSideData
*sd
= av_packet_side_data_get(track
->st
->codecpar
->coded_side_data
,
5227 track
->st
->codecpar
->nb_coded_side_data
,
5228 AV_PKT_DATA_FALLBACK_TRACK
);
5229 if (sd
&& sd
->size
== sizeof(int)) {
5230 int *fallback
= (int *)sd
->data
;
5231 if (*fallback
>= 0 && *fallback
< mov
->nb_tracks
) {
5232 track
->tref_tag
= MKTAG('f','a','l','l');
5233 track
->tref_id
= mov
->tracks
[*fallback
].track_id
;
5238 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5239 if (mov
->tracks
[i
].tag
== MKTAG('t','m','c','d')) {
5240 int src_trk
= mov
->tracks
[i
].src_track
;
5241 mov
->tracks
[src_trk
].tref_tag
= mov
->tracks
[i
].tag
;
5242 mov
->tracks
[src_trk
].tref_id
= mov
->tracks
[i
].track_id
;
5243 //src_trk may have a different timescale than the tmcd track
5244 mov
->tracks
[i
].track_duration
= av_rescale(mov
->tracks
[src_trk
].track_duration
,
5245 mov
->tracks
[i
].timescale
,
5246 mov
->tracks
[src_trk
].timescale
);
5250 mov_write_mvhd_tag(pb
, mov
);
5251 if (mov
->mode
!= MODE_MOV
&& mov
->mode
!= MODE_AVIF
&& !mov
->iods_skip
)
5252 mov_write_iods_tag(pb
, mov
);
5253 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5254 if (mov
->tracks
[i
].entry
> 0 || mov
->flags
& FF_MOV_FLAG_FRAGMENT
||
5255 mov
->mode
== MODE_AVIF
) {
5256 int ret
= mov_write_trak_tag(s
, pb
, mov
, &(mov
->tracks
[i
]), i
< mov
->nb_streams
? mov
->tracks
[i
].st
: NULL
);
5261 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5262 * (mov->moov_written != 0)
5264 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
&&
5265 !(mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
&& mov
->moov_written
))
5266 mov_write_mvex_tag(pb
, mov
); /* QuickTime requires trak to precede this */
5268 if (mov
->mode
== MODE_PSP
)
5269 mov_write_uuidusmt_tag(pb
, s
);
5270 else if (mov
->mode
!= MODE_AVIF
)
5271 mov_write_udta_tag(pb
, mov
, s
);
5272 for (i
= 0; i
< mov
->nb_streams
; i
++)
5273 mov_write_pssh_tag(pb
, mov
->tracks
[i
].st
);
5275 return update_size(pb
, pos
);
5278 static void param_write_int(AVIOContext
*pb
, const char *name
, int value
)
5280 avio_printf(pb
, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name
, value
);
5283 static void param_write_string(AVIOContext
*pb
, const char *name
, const char *value
)
5285 avio_printf(pb
, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name
, value
);
5288 static void param_write_hex(AVIOContext
*pb
, const char *name
, const uint8_t *value
, int len
)
5291 len
= FFMIN(sizeof(buf
) / 2 - 1, len
);
5292 ff_data_to_hex(buf
, value
, len
, 0);
5293 avio_printf(pb
, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name
, buf
);
5296 static int mov_write_isml_manifest(AVIOContext
*pb
, MOVMuxContext
*mov
, AVFormatContext
*s
)
5298 int64_t pos
= avio_tell(pb
);
5301 static const AVUUID uuid
= {
5302 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5303 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5307 ffio_wfourcc(pb
, "uuid");
5308 avio_write(pb
, uuid
, AV_UUID_LEN
);
5311 avio_printf(pb
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5312 avio_printf(pb
, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5313 avio_printf(pb
, "<head>\n");
5314 if (!(mov
->fc
->flags
& AVFMT_FLAG_BITEXACT
))
5315 avio_printf(pb
, "<meta name=\"creator\" content=\"%s\" />\n",
5317 avio_printf(pb
, "</head>\n");
5318 avio_printf(pb
, "<body>\n");
5319 avio_printf(pb
, "<switch>\n");
5321 mov_setup_track_ids(mov
, s
);
5323 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5324 MOVTrack
*track
= &mov
->tracks
[i
];
5325 struct mpeg4_bit_rate_values bit_rates
=
5326 calculate_mpeg4_bit_rates(track
);
5328 int track_id
= track
->track_id
;
5329 char track_name_buf
[32] = { 0 };
5331 AVStream
*st
= track
->st
;
5332 AVDictionaryEntry
*lang
= av_dict_get(st
->metadata
, "language", NULL
,0);
5334 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
&& !is_cover_image(st
)) {
5336 } else if (track
->par
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
5342 avio_printf(pb
, "<%s systemBitrate=\"%"PRIu32
"\">\n", type
,
5343 bit_rates
.avg_bit_rate
);
5344 param_write_int(pb
, "systemBitrate", bit_rates
.avg_bit_rate
);
5345 param_write_int(pb
, "trackID", track_id
);
5346 param_write_string(pb
, "systemLanguage", lang
? lang
->value
: "und");
5348 /* Build track name piece by piece: */
5350 av_strlcat(track_name_buf
, type
, sizeof(track_name_buf
));
5351 /* 2. track language, if available */
5353 av_strlcatf(track_name_buf
, sizeof(track_name_buf
),
5354 "_%s", lang
->value
);
5355 /* 3. special type suffix */
5356 /* "_cc" = closed captions, "_ad" = audio_description */
5357 if (st
->disposition
& AV_DISPOSITION_HEARING_IMPAIRED
)
5358 av_strlcat(track_name_buf
, "_cc", sizeof(track_name_buf
));
5359 else if (st
->disposition
& AV_DISPOSITION_VISUAL_IMPAIRED
)
5360 av_strlcat(track_name_buf
, "_ad", sizeof(track_name_buf
));
5362 param_write_string(pb
, "trackName", track_name_buf
);
5364 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
5365 if (track
->par
->codec_id
== AV_CODEC_ID_H264
) {
5367 int size
= track
->extradata_size
[track
->last_stsd_index
];
5368 if (!ff_avc_write_annexb_extradata(track
->extradata
[track
->last_stsd_index
], &ptr
,
5370 param_write_hex(pb
, "CodecPrivateData",
5371 ptr
? ptr
: track
->extradata
[track
->last_stsd_index
],
5375 param_write_string(pb
, "FourCC", "H264");
5376 } else if (track
->par
->codec_id
== AV_CODEC_ID_VC1
) {
5377 param_write_string(pb
, "FourCC", "WVC1");
5378 param_write_hex(pb
, "CodecPrivateData", track
->extradata
[track
->last_stsd_index
],
5379 track
->extradata_size
[track
->last_stsd_index
]);
5381 param_write_int(pb
, "MaxWidth", track
->par
->width
);
5382 param_write_int(pb
, "MaxHeight", track
->par
->height
);
5383 param_write_int(pb
, "DisplayWidth", track
->par
->width
);
5384 param_write_int(pb
, "DisplayHeight", track
->par
->height
);
5386 if (track
->par
->codec_id
== AV_CODEC_ID_AAC
) {
5387 switch (track
->par
->profile
) {
5388 case AV_PROFILE_AAC_HE_V2
:
5389 param_write_string(pb
, "FourCC", "AACP");
5391 case AV_PROFILE_AAC_HE
:
5392 param_write_string(pb
, "FourCC", "AACH");
5395 param_write_string(pb
, "FourCC", "AACL");
5397 } else if (track
->par
->codec_id
== AV_CODEC_ID_WMAPRO
) {
5398 param_write_string(pb
, "FourCC", "WMAP");
5400 param_write_hex(pb
, "CodecPrivateData", track
->extradata
[track
->last_stsd_index
],
5401 track
->extradata_size
[track
->last_stsd_index
]);
5402 param_write_int(pb
, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags
,
5403 track
->par
->codec_id
));
5404 param_write_int(pb
, "Channels", track
->par
->ch_layout
.nb_channels
);
5405 param_write_int(pb
, "SamplingRate", track
->tag
== MKTAG('i','a','m','f') ?
5406 0 : track
->par
->sample_rate
);
5407 param_write_int(pb
, "BitsPerSample", 16);
5408 param_write_int(pb
, "PacketSize", track
->par
->block_align
?
5409 track
->par
->block_align
: 4);
5411 avio_printf(pb
, "</%s>\n", type
);
5413 avio_printf(pb
, "</switch>\n");
5414 avio_printf(pb
, "</body>\n");
5415 avio_printf(pb
, "</smil>\n");
5417 return update_size(pb
, pos
);
5420 static int mov_write_mfhd_tag(AVIOContext
*pb
, MOVMuxContext
*mov
)
5423 ffio_wfourcc(pb
, "mfhd");
5425 avio_wb32(pb
, mov
->fragments
);
5429 static uint32_t get_sample_flags(MOVTrack
*track
, MOVIentry
*entry
)
5431 return entry
->flags
& MOV_SYNC_SAMPLE
? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO
:
5432 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES
| MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC
);
5435 static int mov_write_tfhd_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
5436 MOVTrack
*track
, int64_t moof_offset
)
5438 int64_t pos
= avio_tell(pb
);
5439 uint32_t flags
= MOV_TFHD_DEFAULT_SIZE
| MOV_TFHD_DEFAULT_DURATION
|
5440 MOV_TFHD_BASE_DATA_OFFSET
;
5441 if (!track
->entry
) {
5442 flags
|= MOV_TFHD_DURATION_IS_EMPTY
;
5444 flags
|= MOV_TFHD_DEFAULT_FLAGS
;
5446 if (mov
->flags
& FF_MOV_FLAG_OMIT_TFHD_OFFSET
)
5447 flags
&= ~MOV_TFHD_BASE_DATA_OFFSET
;
5448 if (mov
->flags
& FF_MOV_FLAG_DEFAULT_BASE_MOOF
) {
5449 flags
&= ~MOV_TFHD_BASE_DATA_OFFSET
;
5450 flags
|= MOV_TFHD_DEFAULT_BASE_IS_MOOF
;
5452 /* CMAF requires all values to be explicit in tfhd atoms */
5453 if (mov
->flags
& FF_MOV_FLAG_CMAF
)
5454 flags
|= MOV_TFHD_STSD_ID
;
5456 /* Don't set a default sample size, the silverlight player refuses
5457 * to play files with that set. Don't set a default sample duration,
5458 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5459 * file format says it MUST NOT be set. */
5460 if (track
->mode
== MODE_ISM
)
5461 flags
&= ~(MOV_TFHD_DEFAULT_SIZE
| MOV_TFHD_DEFAULT_DURATION
|
5462 MOV_TFHD_BASE_DATA_OFFSET
| MOV_TFHD_STSD_ID
);
5464 avio_wb32(pb
, 0); /* size placeholder */
5465 ffio_wfourcc(pb
, "tfhd");
5466 avio_w8(pb
, 0); /* version */
5467 avio_wb24(pb
, flags
);
5469 avio_wb32(pb
, track
->track_id
); /* track-id */
5470 if (flags
& MOV_TFHD_BASE_DATA_OFFSET
)
5471 avio_wb64(pb
, moof_offset
);
5472 if (flags
& MOV_TFHD_STSD_ID
) {
5475 if (flags
& MOV_TFHD_DEFAULT_DURATION
) {
5476 track
->default_duration
= get_cluster_duration(track
, 0);
5477 avio_wb32(pb
, track
->default_duration
);
5479 if (flags
& MOV_TFHD_DEFAULT_SIZE
) {
5480 track
->default_size
= track
->entry
? track
->cluster
[0].size
: 1;
5481 avio_wb32(pb
, track
->default_size
);
5483 track
->default_size
= -1;
5485 if (flags
& MOV_TFHD_DEFAULT_FLAGS
) {
5486 /* Set the default flags based on the second sample, if available.
5487 * If the first sample is different, that can be signaled via a separate field. */
5488 if (track
->entry
> 1)
5489 track
->default_sample_flags
= get_sample_flags(track
, &track
->cluster
[1]);
5491 track
->default_sample_flags
=
5492 track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
?
5493 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES
| MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC
) :
5494 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO
;
5495 avio_wb32(pb
, track
->default_sample_flags
);
5498 return update_size(pb
, pos
);
5501 static int mov_write_trun_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
5502 MOVTrack
*track
, int moof_size
,
5505 int64_t pos
= avio_tell(pb
);
5506 uint32_t flags
= MOV_TRUN_DATA_OFFSET
;
5509 for (i
= first
; i
< end
; i
++) {
5510 if (get_cluster_duration(track
, i
) != track
->default_duration
)
5511 flags
|= MOV_TRUN_SAMPLE_DURATION
;
5512 if (track
->cluster
[i
].size
!= track
->default_size
)
5513 flags
|= MOV_TRUN_SAMPLE_SIZE
;
5514 if (i
> first
&& get_sample_flags(track
, &track
->cluster
[i
]) != track
->default_sample_flags
)
5515 flags
|= MOV_TRUN_SAMPLE_FLAGS
;
5517 if (!(flags
& MOV_TRUN_SAMPLE_FLAGS
) && track
->entry
> first
&&
5518 get_sample_flags(track
, &track
->cluster
[first
]) != track
->default_sample_flags
)
5519 flags
|= MOV_TRUN_FIRST_SAMPLE_FLAGS
;
5520 if (track
->flags
& MOV_TRACK_CTTS
)
5521 flags
|= MOV_TRUN_SAMPLE_CTS
;
5523 avio_wb32(pb
, 0); /* size placeholder */
5524 ffio_wfourcc(pb
, "trun");
5525 if (mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
)
5526 avio_w8(pb
, 1); /* version */
5528 avio_w8(pb
, 0); /* version */
5529 avio_wb24(pb
, flags
);
5531 avio_wb32(pb
, end
- first
); /* sample count */
5532 if (mov
->flags
& FF_MOV_FLAG_OMIT_TFHD_OFFSET
&&
5533 !(mov
->flags
& FF_MOV_FLAG_DEFAULT_BASE_MOOF
) &&
5535 avio_wb32(pb
, 0); /* Later tracks follow immediately after the previous one */
5537 avio_wb32(pb
, moof_size
+ 8 + track
->data_offset
+
5538 track
->cluster
[first
].pos
); /* data offset */
5539 if (flags
& MOV_TRUN_FIRST_SAMPLE_FLAGS
)
5540 avio_wb32(pb
, get_sample_flags(track
, &track
->cluster
[first
]));
5542 for (i
= first
; i
< end
; i
++) {
5543 if (flags
& MOV_TRUN_SAMPLE_DURATION
)
5544 avio_wb32(pb
, get_cluster_duration(track
, i
));
5545 if (flags
& MOV_TRUN_SAMPLE_SIZE
)
5546 avio_wb32(pb
, track
->cluster
[i
].size
);
5547 if (flags
& MOV_TRUN_SAMPLE_FLAGS
)
5548 avio_wb32(pb
, get_sample_flags(track
, &track
->cluster
[i
]));
5549 if (flags
& MOV_TRUN_SAMPLE_CTS
)
5550 avio_wb32(pb
, track
->cluster
[i
].cts
);
5553 mov
->first_trun
= 0;
5554 return update_size(pb
, pos
);
5557 static int mov_write_tfxd_tag(AVIOContext
*pb
, MOVTrack
*track
)
5559 int64_t pos
= avio_tell(pb
);
5560 static const uint8_t uuid
[] = {
5561 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5562 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5565 avio_wb32(pb
, 0); /* size placeholder */
5566 ffio_wfourcc(pb
, "uuid");
5567 avio_write(pb
, uuid
, AV_UUID_LEN
);
5570 avio_wb64(pb
, track
->cluster
[0].dts
+ track
->cluster
[0].cts
);
5571 avio_wb64(pb
, track
->end_pts
-
5572 (track
->cluster
[0].dts
+ track
->cluster
[0].cts
));
5574 return update_size(pb
, pos
);
5577 static int mov_write_tfrf_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
5578 MOVTrack
*track
, int entry
)
5580 int n
= track
->nb_frag_info
- 1 - entry
, i
;
5581 int size
= 8 + 16 + 4 + 1 + 16*n
;
5582 static const uint8_t uuid
[] = {
5583 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5584 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5590 avio_seek(pb
, track
->frag_info
[entry
].tfrf_offset
, SEEK_SET
);
5591 avio_wb32(pb
, size
);
5592 ffio_wfourcc(pb
, "uuid");
5593 avio_write(pb
, uuid
, AV_UUID_LEN
);
5597 for (i
= 0; i
< n
; i
++) {
5598 int index
= entry
+ 1 + i
;
5599 avio_wb64(pb
, track
->frag_info
[index
].time
);
5600 avio_wb64(pb
, track
->frag_info
[index
].duration
);
5602 if (n
< mov
->ism_lookahead
) {
5603 int free_size
= 16 * (mov
->ism_lookahead
- n
);
5604 avio_wb32(pb
, free_size
);
5605 ffio_wfourcc(pb
, "free");
5606 ffio_fill(pb
, 0, free_size
- 8);
5612 static int mov_write_tfrf_tags(AVIOContext
*pb
, MOVMuxContext
*mov
,
5615 int64_t pos
= avio_tell(pb
);
5617 for (i
= 0; i
< mov
->ism_lookahead
; i
++) {
5618 /* Update the tfrf tag for the last ism_lookahead fragments,
5619 * nb_frag_info - 1 is the next fragment to be written. */
5620 mov_write_tfrf_tag(pb
, mov
, track
, track
->nb_frag_info
- 2 - i
);
5622 avio_seek(pb
, pos
, SEEK_SET
);
5626 static int mov_add_tfra_entries(AVIOContext
*pb
, MOVMuxContext
*mov
, int tracks
,
5630 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5631 MOVTrack
*track
= &mov
->tracks
[i
];
5632 MOVFragmentInfo
*info
;
5633 if ((tracks
>= 0 && i
!= tracks
) || !track
->entry
)
5635 track
->nb_frag_info
++;
5636 if (track
->nb_frag_info
>= track
->frag_info_capacity
) {
5637 unsigned new_capacity
= track
->nb_frag_info
+ MOV_FRAG_INFO_ALLOC_INCREMENT
;
5638 if (av_reallocp_array(&track
->frag_info
,
5640 sizeof(*track
->frag_info
)))
5641 return AVERROR(ENOMEM
);
5642 track
->frag_info_capacity
= new_capacity
;
5644 info
= &track
->frag_info
[track
->nb_frag_info
- 1];
5645 info
->offset
= avio_tell(pb
);
5647 // Try to recreate the original pts for the first packet
5648 // from the fields we have stored
5649 info
->time
= track
->cluster
[0].dts
+ track
->cluster
[0].cts
;
5650 info
->duration
= track
->end_pts
-
5651 (track
->cluster
[0].dts
+ track
->cluster
[0].cts
);
5652 // If the pts is less than zero, we will have trimmed
5653 // away parts of the media track using an edit list,
5654 // and the corresponding start presentation time is zero.
5655 if (info
->time
< 0) {
5656 info
->duration
+= info
->time
;
5659 info
->tfrf_offset
= 0;
5660 mov_write_tfrf_tags(pb
, mov
, track
);
5665 static void mov_prune_frag_info(MOVMuxContext
*mov
, int tracks
, int max
)
5668 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5669 MOVTrack
*track
= &mov
->tracks
[i
];
5670 if ((tracks
>= 0 && i
!= tracks
) || !track
->entry
)
5672 if (track
->nb_frag_info
> max
) {
5673 memmove(track
->frag_info
, track
->frag_info
+ (track
->nb_frag_info
- max
), max
* sizeof(*track
->frag_info
));
5674 track
->nb_frag_info
= max
;
5679 static int mov_write_tfdt_tag(AVIOContext
*pb
, MOVTrack
*track
)
5681 int64_t pos
= avio_tell(pb
);
5683 avio_wb32(pb
, 0); /* size */
5684 ffio_wfourcc(pb
, "tfdt");
5685 avio_w8(pb
, 1); /* version */
5687 avio_wb64(pb
, track
->cluster
[0].dts
- track
->start_dts
);
5688 return update_size(pb
, pos
);
5691 static int mov_write_traf_tag(AVIOContext
*pb
, MOVMuxContext
*mov
,
5692 MOVTrack
*track
, int64_t moof_offset
,
5695 int64_t pos
= avio_tell(pb
);
5697 avio_wb32(pb
, 0); /* size placeholder */
5698 ffio_wfourcc(pb
, "traf");
5700 mov_write_tfhd_tag(pb
, mov
, track
, moof_offset
);
5701 if (mov
->mode
!= MODE_ISM
)
5702 mov_write_tfdt_tag(pb
, track
);
5703 for (i
= 1; i
< track
->entry
; i
++) {
5704 if (track
->cluster
[i
].pos
!= track
->cluster
[i
- 1].pos
+ track
->cluster
[i
- 1].size
) {
5705 mov_write_trun_tag(pb
, mov
, track
, moof_size
, start
, i
);
5709 mov_write_trun_tag(pb
, mov
, track
, moof_size
, start
, track
->entry
);
5710 if (mov
->mode
== MODE_ISM
) {
5711 mov_write_tfxd_tag(pb
, track
);
5713 if (mov
->ism_lookahead
) {
5714 int size
= 16 + 4 + 1 + 16 * mov
->ism_lookahead
;
5716 if (track
->nb_frag_info
> 0) {
5717 MOVFragmentInfo
*info
= &track
->frag_info
[track
->nb_frag_info
- 1];
5718 if (!info
->tfrf_offset
)
5719 info
->tfrf_offset
= avio_tell(pb
);
5721 avio_wb32(pb
, 8 + size
);
5722 ffio_wfourcc(pb
, "free");
5723 ffio_fill(pb
, 0, size
);
5727 if (track
->cenc
.aes_ctr
&& (mov
->flags
& FF_MOV_FLAG_FRAGMENT
))
5728 ff_mov_cenc_write_stbl_atoms(&track
->cenc
, pb
, moof_offset
);
5730 return update_size(pb
, pos
);
5733 static int mov_write_moof_tag_internal(AVIOContext
*pb
, MOVMuxContext
*mov
,
5734 int tracks
, int moof_size
)
5736 int64_t pos
= avio_tell(pb
);
5739 avio_wb32(pb
, 0); /* size placeholder */
5740 ffio_wfourcc(pb
, "moof");
5741 mov
->first_trun
= 1;
5743 mov_write_mfhd_tag(pb
, mov
);
5744 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5745 MOVTrack
*track
= &mov
->tracks
[i
];
5746 if (tracks
>= 0 && i
!= tracks
)
5750 if (track
->cenc
.aes_ctr
&& (mov
->flags
& FF_MOV_FLAG_FRAGMENT
))
5751 mov_write_pssh_tag(pb
, track
->st
);
5752 mov_write_traf_tag(pb
, mov
, track
, pos
, moof_size
);
5755 return update_size(pb
, pos
);
5758 static int mov_write_sidx_tag(AVIOContext
*pb
,
5759 MOVTrack
*track
, int ref_size
, int total_sidx_size
)
5761 int64_t pos
= avio_tell(pb
), offset_pos
, end_pos
;
5762 int64_t presentation_time
, duration
, offset
;
5763 unsigned starts_with_SAP
;
5768 presentation_time
= track
->cluster
[0].dts
+ track
->cluster
[0].cts
;
5769 duration
= track
->end_pts
-
5770 (track
->cluster
[0].dts
+ track
->cluster
[0].cts
);
5771 starts_with_SAP
= track
->cluster
[0].flags
& MOV_SYNC_SAMPLE
;
5773 // pts<0 should be cut away using edts
5774 if (presentation_time
< 0) {
5775 duration
+= presentation_time
;
5776 presentation_time
= 0;
5779 entries
= track
->nb_frag_info
;
5782 presentation_time
= track
->frag_info
[0].time
;
5785 avio_wb32(pb
, 0); /* size */
5786 ffio_wfourcc(pb
, "sidx");
5787 avio_w8(pb
, 1); /* version */
5789 avio_wb32(pb
, track
->track_id
); /* reference_ID */
5790 avio_wb32(pb
, track
->timescale
); /* timescale */
5791 avio_wb64(pb
, presentation_time
); /* earliest_presentation_time */
5792 offset_pos
= avio_tell(pb
);
5793 avio_wb64(pb
, 0); /* first_offset (offset to referenced moof) */
5794 avio_wb16(pb
, 0); /* reserved */
5796 avio_wb16(pb
, entries
); /* reference_count */
5797 for (i
= 0; i
< entries
; i
++) {
5798 if (!track
->entry
) {
5799 if (i
> 1 && track
->frag_info
[i
].offset
!= track
->frag_info
[i
- 1].offset
+ track
->frag_info
[i
- 1].size
) {
5800 av_log(NULL
, AV_LOG_ERROR
, "Non-consecutive fragments, writing incorrect sidx\n");
5802 duration
= track
->frag_info
[i
].duration
;
5803 ref_size
= track
->frag_info
[i
].size
;
5804 starts_with_SAP
= 1;
5806 avio_wb32(pb
, (0 << 31) | (ref_size
& 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5807 avio_wb32(pb
, duration
); /* subsegment_duration */
5808 avio_wb32(pb
, (starts_with_SAP
<< 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5811 end_pos
= avio_tell(pb
);
5812 offset
= pos
+ total_sidx_size
- end_pos
;
5813 avio_seek(pb
, offset_pos
, SEEK_SET
);
5814 avio_wb64(pb
, offset
);
5815 avio_seek(pb
, end_pos
, SEEK_SET
);
5816 return update_size(pb
, pos
);
5819 static int mov_write_sidx_tags(AVIOContext
*pb
, MOVMuxContext
*mov
,
5820 int tracks
, int ref_size
)
5823 AVIOContext
*avio_buf
;
5825 for (round
= 0; round
< 2; round
++) {
5826 // First run one round to calculate the total size of all
5828 // This would be much simpler if we'd only write one sidx
5829 // atom, for the first track in the moof.
5831 if ((ret
= ffio_open_null_buf(&avio_buf
)) < 0)
5836 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5837 MOVTrack
*track
= &mov
->tracks
[i
];
5838 if (tracks
>= 0 && i
!= tracks
)
5840 // When writing a sidx for the full file, entry is 0, but
5841 // we want to include all tracks. ref_size is 0 in this case,
5842 // since we read it from frag_info instead.
5843 if (!track
->entry
&& ref_size
> 0)
5845 total_size
-= mov_write_sidx_tag(avio_buf
, track
, ref_size
,
5849 total_size
= ffio_close_null_buf(avio_buf
);
5854 static int mov_write_prft_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, int tracks
)
5856 int64_t pos
= avio_tell(pb
), pts_us
, ntp_ts
;
5857 MOVTrack
*first_track
;
5860 /* PRFT should be associated with at most one track. So, choosing only the
5864 first_track
= &(mov
->tracks
[0]);
5866 if (!first_track
->entry
) {
5867 av_log(mov
->fc
, AV_LOG_WARNING
, "Unable to write PRFT, no entries in the track\n");
5871 if (first_track
->cluster
[0].pts
== AV_NOPTS_VALUE
) {
5872 av_log(mov
->fc
, AV_LOG_WARNING
, "Unable to write PRFT, first PTS is invalid\n");
5876 if (mov
->write_prft
== MOV_PRFT_SRC_WALLCLOCK
) {
5877 if (first_track
->cluster
[0].prft
.wallclock
) {
5878 /* Round the NTP time to whole milliseconds. */
5879 ntp_ts
= ff_get_formatted_ntp_time((first_track
->cluster
[0].prft
.wallclock
/ 1000) * 1000 +
5881 flags
= first_track
->cluster
[0].prft
.flags
;
5883 ntp_ts
= ff_get_formatted_ntp_time(ff_ntp_time());
5884 } else if (mov
->write_prft
== MOV_PRFT_SRC_PTS
) {
5885 pts_us
= av_rescale_q(first_track
->cluster
[0].pts
,
5886 first_track
->st
->time_base
, AV_TIME_BASE_Q
);
5887 ntp_ts
= ff_get_formatted_ntp_time(pts_us
+ NTP_OFFSET_US
);
5889 av_log(mov
->fc
, AV_LOG_WARNING
, "Unsupported PRFT box configuration: %d\n",
5894 avio_wb32(pb
, 0); // Size place holder
5895 ffio_wfourcc(pb
, "prft"); // Type
5896 avio_w8(pb
, 1); // Version
5897 avio_wb24(pb
, flags
); // Flags
5898 avio_wb32(pb
, first_track
->track_id
); // reference track ID
5899 avio_wb64(pb
, ntp_ts
); // NTP time stamp
5900 avio_wb64(pb
, first_track
->cluster
[0].pts
); //media time
5901 return update_size(pb
, pos
);
5904 static int mov_write_moof_tag(AVIOContext
*pb
, MOVMuxContext
*mov
, int tracks
,
5907 AVIOContext
*avio_buf
;
5910 if ((ret
= ffio_open_null_buf(&avio_buf
)) < 0)
5912 mov_write_moof_tag_internal(avio_buf
, mov
, tracks
, 0);
5913 moof_size
= ffio_close_null_buf(avio_buf
);
5915 if (mov
->flags
& FF_MOV_FLAG_DASH
&&
5916 !(mov
->flags
& (FF_MOV_FLAG_GLOBAL_SIDX
| FF_MOV_FLAG_SKIP_SIDX
)))
5917 mov_write_sidx_tags(pb
, mov
, tracks
, moof_size
+ 8 + mdat_size
);
5919 if (mov
->write_prft
> MOV_PRFT_NONE
&& mov
->write_prft
< MOV_PRFT_NB
)
5920 mov_write_prft_tag(pb
, mov
, tracks
);
5922 if (mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
||
5923 !(mov
->flags
& FF_MOV_FLAG_SKIP_TRAILER
) ||
5924 mov
->ism_lookahead
) {
5925 if ((ret
= mov_add_tfra_entries(pb
, mov
, tracks
, moof_size
+ 8 + mdat_size
)) < 0)
5927 if (!(mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
) &&
5928 mov
->flags
& FF_MOV_FLAG_SKIP_TRAILER
) {
5929 mov_prune_frag_info(mov
, tracks
, mov
->ism_lookahead
+ 1);
5933 return mov_write_moof_tag_internal(pb
, mov
, tracks
, moof_size
);
5936 static int mov_write_tfra_tag(AVIOContext
*pb
, MOVTrack
*track
)
5938 int64_t pos
= avio_tell(pb
);
5941 avio_wb32(pb
, 0); /* size placeholder */
5942 ffio_wfourcc(pb
, "tfra");
5943 avio_w8(pb
, 1); /* version */
5946 avio_wb32(pb
, track
->track_id
);
5947 avio_wb32(pb
, 0); /* length of traf/trun/sample num */
5948 avio_wb32(pb
, track
->nb_frag_info
);
5949 for (i
= 0; i
< track
->nb_frag_info
; i
++) {
5950 avio_wb64(pb
, track
->frag_info
[i
].time
);
5951 avio_wb64(pb
, track
->frag_info
[i
].offset
+ track
->data_offset
);
5952 avio_w8(pb
, 1); /* traf number */
5953 avio_w8(pb
, 1); /* trun number */
5954 avio_w8(pb
, 1); /* sample number */
5957 return update_size(pb
, pos
);
5960 static int mov_write_mfra_tag(AVIOContext
*pb
, MOVMuxContext
*mov
)
5962 AVIOContext
*mfra_pb
;
5966 ret
= avio_open_dyn_buf(&mfra_pb
);
5970 avio_wb32(mfra_pb
, 0); /* size placeholder */
5971 ffio_wfourcc(mfra_pb
, "mfra");
5972 /* An empty mfra atom is enough to indicate to the publishing point that
5973 * the stream has ended. */
5974 if (mov
->flags
& FF_MOV_FLAG_ISML
)
5977 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
5978 MOVTrack
*track
= &mov
->tracks
[i
];
5979 if (track
->nb_frag_info
)
5980 mov_write_tfra_tag(mfra_pb
, track
);
5983 avio_wb32(mfra_pb
, 16);
5984 ffio_wfourcc(mfra_pb
, "mfro");
5985 avio_wb32(mfra_pb
, 0); /* version + flags */
5986 avio_wb32(mfra_pb
, avio_tell(mfra_pb
) + 4);
5990 sz
= update_size(mfra_pb
, 0);
5991 ret
= avio_get_dyn_buf(mfra_pb
, &buf
);
5992 avio_write(pb
, buf
, ret
);
5993 ffio_free_dyn_buf(&mfra_pb
);
5998 static int mov_write_mdat_tag(AVIOContext
*pb
, MOVMuxContext
*mov
)
6000 avio_wb32(pb
, 8); // placeholder for extended size field (64 bit)
6001 ffio_wfourcc(pb
, mov
->mode
== MODE_MOV
? "wide" : "free");
6003 mov
->mdat_pos
= avio_tell(pb
);
6004 avio_wb32(pb
, 0); /* size placeholder*/
6005 ffio_wfourcc(pb
, "mdat");
6009 static void mov_write_ftyp_tag_internal(AVIOContext
*pb
, AVFormatContext
*s
,
6010 int has_h264
, int has_video
, int write_minor
)
6012 MOVMuxContext
*mov
= s
->priv_data
;
6015 if (mov
->major_brand
&& strlen(mov
->major_brand
) >= 4)
6016 ffio_wfourcc(pb
, mov
->major_brand
);
6017 else if (mov
->mode
== MODE_3GP
) {
6018 ffio_wfourcc(pb
, has_h264
? "3gp6" : "3gp4");
6019 minor
= has_h264
? 0x100 : 0x200;
6020 } else if (mov
->mode
== MODE_AVIF
) {
6021 ffio_wfourcc(pb
, mov
->is_animated_avif
? "avis" : "avif");
6023 } else if (mov
->mode
& MODE_3G2
) {
6024 ffio_wfourcc(pb
, has_h264
? "3g2b" : "3g2a");
6025 minor
= has_h264
? 0x20000 : 0x10000;
6026 } else if (mov
->mode
== MODE_PSP
)
6027 ffio_wfourcc(pb
, "MSNV");
6028 else if (mov
->mode
== MODE_MP4
&& mov
->flags
& FF_MOV_FLAG_FRAGMENT
&&
6029 mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
)
6030 ffio_wfourcc(pb
, "iso6"); // Required when using signed CTS offsets in trun boxes
6031 else if (mov
->mode
== MODE_MP4
&& mov
->flags
& FF_MOV_FLAG_DEFAULT_BASE_MOOF
)
6032 ffio_wfourcc(pb
, "iso5"); // Required when using default-base-is-moof
6033 else if (mov
->mode
== MODE_MP4
&& mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
)
6034 ffio_wfourcc(pb
, "iso4");
6035 else if (mov
->mode
== MODE_MP4
)
6036 ffio_wfourcc(pb
, "isom");
6037 else if (mov
->mode
== MODE_IPOD
)
6038 ffio_wfourcc(pb
, has_video
? "M4V ":"M4A ");
6039 else if (mov
->mode
== MODE_ISM
)
6040 ffio_wfourcc(pb
, "isml");
6041 else if (mov
->mode
== MODE_F4V
)
6042 ffio_wfourcc(pb
, "f4v ");
6044 ffio_wfourcc(pb
, "qt ");
6047 avio_wb32(pb
, minor
);
6050 static int mov_write_ftyp_tag(AVIOContext
*pb
, AVFormatContext
*s
)
6052 MOVMuxContext
*mov
= s
->priv_data
;
6053 int64_t pos
= avio_tell(pb
);
6054 int has_h264
= 0, has_av1
= 0, has_video
= 0, has_dolby
= 0, has_id3
= 0;
6058 for (int i
= 0; i
< s
->nb_stream_groups
; i
++) {
6059 const AVStreamGroup
*stg
= s
->stream_groups
[i
];
6061 if (stg
->type
== AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
||
6062 stg
->type
== AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION
) {
6068 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
6069 AVStream
*st
= mov
->tracks
[i
].st
;
6070 if (is_cover_image(st
))
6072 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
)
6074 if (st
->codecpar
->codec_id
== AV_CODEC_ID_H264
)
6076 if (st
->codecpar
->codec_id
== AV_CODEC_ID_AV1
)
6078 if (st
->codecpar
->codec_id
== AV_CODEC_ID_AC3
||
6079 st
->codecpar
->codec_id
== AV_CODEC_ID_EAC3
||
6080 st
->codecpar
->codec_id
== AV_CODEC_ID_TRUEHD
||
6081 av_packet_side_data_get(st
->codecpar
->coded_side_data
,
6082 st
->codecpar
->nb_coded_side_data
,
6083 AV_PKT_DATA_DOVI_CONF
))
6085 if (st
->codecpar
->codec_id
== AV_CODEC_ID_TIMED_ID3
)
6089 avio_wb32(pb
, 0); /* size */
6090 ffio_wfourcc(pb
, "ftyp");
6092 // Write major brand
6093 mov_write_ftyp_tag_internal(pb
, s
, has_h264
, has_video
, 1);
6094 // Write the major brand as the first compatible brand as well
6095 mov_write_ftyp_tag_internal(pb
, s
, has_h264
, has_video
, 0);
6097 // Write compatible brands, ensuring that we don't write the major brand as a
6098 // compatible brand a second time.
6099 if (mov
->mode
== MODE_ISM
) {
6100 ffio_wfourcc(pb
, "piff");
6101 } else if (mov
->mode
== MODE_AVIF
) {
6102 const AVPixFmtDescriptor
*pix_fmt_desc
=
6103 av_pix_fmt_desc_get(s
->streams
[0]->codecpar
->format
);
6104 const int depth
= pix_fmt_desc
->comp
[0].depth
;
6105 if (mov
->is_animated_avif
) {
6106 // For animated AVIF, major brand is "avis". Add "avif" as a
6107 // compatible brand.
6108 ffio_wfourcc(pb
, "avif");
6109 ffio_wfourcc(pb
, "msf1");
6110 ffio_wfourcc(pb
, "iso8");
6112 ffio_wfourcc(pb
, "mif1");
6113 ffio_wfourcc(pb
, "miaf");
6114 if (depth
== 8 || depth
== 10) {
6115 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6116 // computing that is based on chroma subsampling type. 420 chroma
6117 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6118 if (!pix_fmt_desc
->log2_chroma_w
&& !pix_fmt_desc
->log2_chroma_h
) {
6119 // 444 chroma subsampling.
6120 ffio_wfourcc(pb
, "MA1A");
6122 // 420 chroma subsampling.
6123 ffio_wfourcc(pb
, "MA1B");
6126 } else if (mov
->mode
!= MODE_MOV
) {
6127 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6128 // brand, if not already the major brand. This is compatible with users that
6129 // don't understand tfdt.
6130 if (mov
->mode
== MODE_MP4
) {
6131 if (mov
->flags
& FF_MOV_FLAG_CMAF
)
6132 ffio_wfourcc(pb
, "cmfc");
6133 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
&& !(mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
))
6134 ffio_wfourcc(pb
, "iso6");
6136 ffio_wfourcc(pb
, "av01");
6138 ffio_wfourcc(pb
, "dby1");
6140 ffio_wfourcc(pb
, "iamf");
6142 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
)
6143 ffio_wfourcc(pb
, "iso6");
6144 if (mov
->flags
& FF_MOV_FLAG_DEFAULT_BASE_MOOF
)
6145 ffio_wfourcc(pb
, "iso5");
6146 else if (mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
)
6147 ffio_wfourcc(pb
, "iso4");
6149 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6150 if (!(mov
->flags
& FF_MOV_FLAG_DEFAULT_BASE_MOOF
)) {
6151 // write isom for mp4 only if it it's not the major brand already.
6152 if (mov
->mode
!= MODE_MP4
|| mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
)
6153 ffio_wfourcc(pb
, "isom");
6154 ffio_wfourcc(pb
, "iso2");
6156 ffio_wfourcc(pb
, "avc1");
6160 if (mov
->mode
== MODE_MP4
)
6161 ffio_wfourcc(pb
, "mp41");
6163 if (mov
->flags
& FF_MOV_FLAG_DASH
&& mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
)
6164 ffio_wfourcc(pb
, "dash");
6167 ffio_wfourcc(pb
, "aid3");
6169 return update_size(pb
, pos
);
6172 static int mov_write_uuidprof_tag(AVIOContext
*pb
, AVFormatContext
*s
)
6174 AVStream
*video_st
= s
->streams
[0];
6175 AVCodecParameters
*video_par
= s
->streams
[0]->codecpar
;
6176 AVCodecParameters
*audio_par
= s
->streams
[1]->codecpar
;
6177 int audio_rate
= audio_par
->sample_rate
;
6178 int64_t frame_rate
= video_st
->avg_frame_rate
.den
?
6179 (video_st
->avg_frame_rate
.num
* 0x10000LL
) / video_st
->avg_frame_rate
.den
:
6181 int audio_kbitrate
= audio_par
->bit_rate
/ 1000;
6182 int video_kbitrate
= FFMIN(video_par
->bit_rate
/ 1000, 800 - audio_kbitrate
);
6184 if (frame_rate
< 0 || frame_rate
> INT32_MAX
) {
6185 av_log(s
, AV_LOG_ERROR
, "Frame rate %f outside supported range\n", frame_rate
/ (double)0x10000);
6186 return AVERROR(EINVAL
);
6189 avio_wb32(pb
, 0x94); /* size */
6190 ffio_wfourcc(pb
, "uuid");
6191 ffio_wfourcc(pb
, "PROF");
6193 avio_wb32(pb
, 0x21d24fce); /* 96 bit UUID */
6194 avio_wb32(pb
, 0xbb88695c);
6195 avio_wb32(pb
, 0xfac9c740);
6197 avio_wb32(pb
, 0x0); /* ? */
6198 avio_wb32(pb
, 0x3); /* 3 sections ? */
6200 avio_wb32(pb
, 0x14); /* size */
6201 ffio_wfourcc(pb
, "FPRF");
6202 avio_wb32(pb
, 0x0); /* ? */
6203 avio_wb32(pb
, 0x0); /* ? */
6204 avio_wb32(pb
, 0x0); /* ? */
6206 avio_wb32(pb
, 0x2c); /* size */
6207 ffio_wfourcc(pb
, "APRF"); /* audio */
6209 avio_wb32(pb
, 0x2); /* TrackID */
6210 ffio_wfourcc(pb
, "mp4a");
6211 avio_wb32(pb
, 0x20f);
6213 avio_wb32(pb
, audio_kbitrate
);
6214 avio_wb32(pb
, audio_kbitrate
);
6215 avio_wb32(pb
, audio_rate
);
6216 avio_wb32(pb
, audio_par
->ch_layout
.nb_channels
);
6218 avio_wb32(pb
, 0x34); /* size */
6219 ffio_wfourcc(pb
, "VPRF"); /* video */
6221 avio_wb32(pb
, 0x1); /* TrackID */
6222 if (video_par
->codec_id
== AV_CODEC_ID_H264
) {
6223 ffio_wfourcc(pb
, "avc1");
6224 avio_wb16(pb
, 0x014D);
6225 avio_wb16(pb
, 0x0015);
6227 ffio_wfourcc(pb
, "mp4v");
6228 avio_wb16(pb
, 0x0000);
6229 avio_wb16(pb
, 0x0103);
6232 avio_wb32(pb
, video_kbitrate
);
6233 avio_wb32(pb
, video_kbitrate
);
6234 avio_wb32(pb
, frame_rate
);
6235 avio_wb32(pb
, frame_rate
);
6236 avio_wb16(pb
, video_par
->width
);
6237 avio_wb16(pb
, video_par
->height
);
6238 avio_wb32(pb
, 0x010001); /* ? */
6243 static int mov_write_identification(AVIOContext
*pb
, AVFormatContext
*s
)
6245 MOVMuxContext
*mov
= s
->priv_data
;
6248 mov_write_ftyp_tag(pb
,s
);
6249 if (mov
->mode
== MODE_PSP
) {
6250 int video_streams_nb
= 0, audio_streams_nb
= 0, other_streams_nb
= 0;
6251 for (i
= 0; i
< mov
->nb_streams
; i
++) {
6252 AVStream
*st
= mov
->tracks
[i
].st
;
6253 if (is_cover_image(st
))
6255 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
)
6257 else if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
)
6263 if (video_streams_nb
!= 1 || audio_streams_nb
!= 1 || other_streams_nb
) {
6264 av_log(s
, AV_LOG_ERROR
, "PSP mode need one video and one audio stream\n");
6265 return AVERROR(EINVAL
);
6267 return mov_write_uuidprof_tag(pb
, s
);
6272 static int mov_parse_mpeg2_frame(AVPacket
*pkt
, uint32_t *flags
)
6275 int i
, closed_gop
= 0;
6277 for (i
= 0; i
< pkt
->size
- 4; i
++) {
6278 c
= (c
<< 8) + pkt
->data
[i
];
6279 if (c
== 0x1b8) { // gop
6280 closed_gop
= pkt
->data
[i
+ 4] >> 6 & 0x01;
6281 } else if (c
== 0x100) { // pic
6282 int temp_ref
= (pkt
->data
[i
+ 1] << 2) | (pkt
->data
[i
+ 2] >> 6);
6283 if (!temp_ref
|| closed_gop
) // I picture is not reordered
6284 *flags
= MOV_SYNC_SAMPLE
;
6286 *flags
= MOV_PARTIAL_SYNC_SAMPLE
;
6293 static void mov_parse_vc1_frame(AVPacket
*pkt
, MOVTrack
*trk
)
6295 const uint8_t *start
, *next
, *end
= pkt
->data
+ pkt
->size
;
6296 int seq
= 0, entry
= 0;
6297 int key
= pkt
->flags
& AV_PKT_FLAG_KEY
;
6298 start
= find_next_marker(pkt
->data
, end
);
6299 for (next
= start
; next
< end
; start
= next
) {
6300 next
= find_next_marker(start
+ 4, end
);
6301 switch (AV_RB32(start
)) {
6302 case VC1_CODE_SEQHDR
:
6305 case VC1_CODE_ENTRYPOINT
:
6308 case VC1_CODE_SLICE
:
6309 trk
->vc1_info
.slices
= 1;
6313 if (!trk
->entry
&& trk
->vc1_info
.first_packet_seen
)
6314 trk
->vc1_info
.first_frag_written
= 1;
6315 if (!trk
->entry
&& !trk
->vc1_info
.first_frag_written
) {
6316 /* First packet in first fragment */
6317 trk
->vc1_info
.first_packet_seq
= seq
;
6318 trk
->vc1_info
.first_packet_entry
= entry
;
6319 trk
->vc1_info
.first_packet_seen
= 1;
6320 } else if ((seq
&& !trk
->vc1_info
.packet_seq
) ||
6321 (entry
&& !trk
->vc1_info
.packet_entry
)) {
6323 for (i
= 0; i
< trk
->entry
; i
++)
6324 trk
->cluster
[i
].flags
&= ~MOV_SYNC_SAMPLE
;
6325 trk
->has_keyframes
= 0;
6327 trk
->vc1_info
.packet_seq
= 1;
6329 trk
->vc1_info
.packet_entry
= 1;
6330 if (!trk
->vc1_info
.first_frag_written
) {
6331 /* First fragment */
6332 if ((!seq
|| trk
->vc1_info
.first_packet_seq
) &&
6333 (!entry
|| trk
->vc1_info
.first_packet_entry
)) {
6334 /* First packet had the same headers as this one, readd the
6335 * sync sample flag. */
6336 trk
->cluster
[0].flags
|= MOV_SYNC_SAMPLE
;
6337 trk
->has_keyframes
= 1;
6341 if (trk
->vc1_info
.packet_seq
&& trk
->vc1_info
.packet_entry
)
6343 else if (trk
->vc1_info
.packet_seq
)
6345 else if (trk
->vc1_info
.packet_entry
)
6348 trk
->cluster
[trk
->entry
].flags
|= MOV_SYNC_SAMPLE
;
6349 trk
->has_keyframes
++;
6353 static void mov_parse_truehd_frame(AVPacket
*pkt
, MOVTrack
*trk
)
6360 length
= (AV_RB16(pkt
->data
) & 0xFFF) * 2;
6361 if (length
< 8 || length
> pkt
->size
)
6364 if (AV_RB32(pkt
->data
+ 4) == 0xF8726FBA) {
6365 trk
->cluster
[trk
->entry
].flags
|= MOV_SYNC_SAMPLE
;
6366 trk
->has_keyframes
++;
6372 static int mov_flush_fragment_interleaving(AVFormatContext
*s
, MOVTrack
*track
)
6374 MOVMuxContext
*mov
= s
->priv_data
;
6379 if (!track
->mdat_buf
)
6381 if (!mov
->mdat_buf
) {
6382 if ((ret
= avio_open_dyn_buf(&mov
->mdat_buf
)) < 0)
6385 buf_size
= avio_get_dyn_buf(track
->mdat_buf
, &buf
);
6387 offset
= avio_tell(mov
->mdat_buf
);
6388 avio_write(mov
->mdat_buf
, buf
, buf_size
);
6389 ffio_free_dyn_buf(&track
->mdat_buf
);
6391 for (i
= track
->entries_flushed
; i
< track
->entry
; i
++)
6392 track
->cluster
[i
].pos
+= offset
;
6393 track
->entries_flushed
= track
->entry
;
6397 static int mov_write_squashed_packet(AVFormatContext
*s
, MOVTrack
*track
)
6399 MOVMuxContext
*mov
= s
->priv_data
;
6400 AVPacket
*squashed_packet
= mov
->pkt
;
6401 int ret
= AVERROR_BUG
;
6403 switch (track
->st
->codecpar
->codec_id
) {
6404 case AV_CODEC_ID_TTML
: {
6405 int had_packets
= !!track
->squashed_packet_queue
.head
;
6407 if ((ret
= ff_mov_generate_squashed_ttml_packet(s
, track
, squashed_packet
)) < 0) {
6411 // We have generated a padding packet (no actual input packets in
6412 // queue) and its duration is zero. Skipping writing it.
6413 if (!had_packets
&& squashed_packet
->duration
== 0) {
6417 track
->end_reliable
= 1;
6421 ret
= AVERROR(EINVAL
);
6425 squashed_packet
->stream_index
= track
->st
->index
;
6427 ret
= mov_write_single_packet(s
, squashed_packet
);
6430 av_packet_unref(squashed_packet
);
6435 static int mov_write_squashed_packets(AVFormatContext
*s
)
6437 MOVMuxContext
*mov
= s
->priv_data
;
6439 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
6440 MOVTrack
*track
= &mov
->tracks
[i
];
6441 int ret
= AVERROR_BUG
;
6443 if (track
->squash_fragment_samples_to_one
&& !track
->entry
) {
6444 if ((ret
= mov_write_squashed_packet(s
, track
)) < 0) {
6445 av_log(s
, AV_LOG_ERROR
,
6446 "Failed to write squashed packet for %s stream with "
6447 "index %d and track id %d. Error: %s\n",
6448 avcodec_get_name(track
->st
->codecpar
->codec_id
),
6449 track
->st
->index
, track
->track_id
,
6459 static int mov_finish_fragment(MOVMuxContext
*mov
, MOVTrack
*track
,
6465 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
) {
6466 for (i
= 0; i
< track
->entry
; i
++)
6467 track
->cluster
[i
].pos
+= ref_pos
+ track
->data_offset
;
6468 if (track
->cluster_written
== 0) {
6469 // First flush. Chunking for this fragment may already have been
6470 // done, either if we didn't use empty_moov, or if we did use
6471 // delay_moov. In either case, reset chunking here.
6472 for (i
= 0; i
< track
->entry
; i
++) {
6473 track
->cluster
[i
].chunkNum
= 0;
6474 track
->cluster
[i
].samples_in_chunk
= track
->cluster
[i
].entries
;
6477 if (av_reallocp_array(&track
->cluster_written
,
6478 track
->entry_written
+ track
->entry
,
6479 sizeof(*track
->cluster
)))
6480 return AVERROR(ENOMEM
);
6481 memcpy(&track
->cluster_written
[track
->entry_written
],
6482 track
->cluster
, track
->entry
* sizeof(*track
->cluster
));
6483 track
->entry_written
+= track
->entry
;
6486 track
->entries_flushed
= 0;
6487 track
->end_reliable
= 0;
6491 static int mov_flush_fragment(AVFormatContext
*s
, int force
)
6493 MOVMuxContext
*mov
= s
->priv_data
;
6494 int i
, first_track
= -1;
6495 int64_t mdat_size
= 0, mdat_start
= 0;
6497 int has_video
= 0, starts_with_key
= 0, first_video_track
= 1;
6499 if (!(mov
->flags
& FF_MOV_FLAG_FRAGMENT
))
6502 // Check if we have any tracks that require squashing.
6503 // In that case, we'll have to write the packet here.
6504 if ((ret
= mov_write_squashed_packets(s
)) < 0)
6507 // Try to fill in the duration of the last packet in each stream
6508 // from queued packets in the interleave queues. If the flushing
6509 // of fragments was triggered automatically by an AVPacket, we
6510 // already have reliable info for the end of that track, but other
6511 // tracks may need to be filled in.
6512 for (i
= 0; i
< mov
->nb_streams
; i
++) {
6513 MOVTrack
*track
= &mov
->tracks
[i
];
6514 if (!track
->end_reliable
) {
6515 const AVPacket
*pkt
= ff_interleaved_peek(s
, i
);
6517 int64_t offset
, dts
, pts
;
6518 ff_get_muxer_ts_offset(s
, i
, &offset
);
6519 pts
= pkt
->pts
+ offset
;
6520 dts
= pkt
->dts
+ offset
;
6521 if (track
->dts_shift
!= AV_NOPTS_VALUE
)
6522 dts
+= track
->dts_shift
;
6523 track
->track_duration
= dts
- track
->start_dts
;
6524 if (pts
!= AV_NOPTS_VALUE
)
6525 track
->end_pts
= pts
;
6527 track
->end_pts
= dts
;
6532 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
6533 MOVTrack
*track
= &mov
->tracks
[i
];
6534 if (track
->entry
<= 1)
6536 // Sample durations are calculated as the diff of dts values,
6537 // but for the last sample in a fragment, we don't know the dts
6538 // of the first sample in the next fragment, so we have to rely
6539 // on what was set as duration in the AVPacket. Not all callers
6540 // set this though, so we might want to replace it with an
6541 // estimate if it currently is zero.
6542 if (get_cluster_duration(track
, track
->entry
- 1) != 0)
6544 // Use the duration (i.e. dts diff) of the second last sample for
6545 // the last one. This is a wild guess (and fatal if it turns out
6546 // to be too long), but probably the best we can do - having a zero
6547 // duration is bad as well.
6548 track
->track_duration
+= get_cluster_duration(track
, track
->entry
- 2);
6549 track
->end_pts
+= get_cluster_duration(track
, track
->entry
- 2);
6550 if (!mov
->missing_duration_warned
) {
6551 av_log(s
, AV_LOG_WARNING
,
6552 "Estimating the duration of the last packet in a "
6553 "fragment, consider setting the duration field in "
6554 "AVPacket instead.\n");
6555 mov
->missing_duration_warned
= 1;
6559 if (!mov
->moov_written
) {
6560 int64_t pos
= avio_tell(s
->pb
);
6562 int buf_size
, moov_size
;
6564 for (i
= 0; i
< mov
->nb_tracks
; i
++)
6565 if (!mov
->tracks
[i
].entry
&& !is_cover_image(mov
->tracks
[i
].st
))
6567 /* Don't write the initial moov unless all tracks have data */
6568 if (i
< mov
->nb_tracks
&& !force
)
6571 moov_size
= get_moov_size(s
);
6572 for (i
= 0; i
< mov
->nb_tracks
; i
++)
6573 mov
->tracks
[i
].data_offset
= pos
+ moov_size
+ 8;
6575 avio_write_marker(s
->pb
, AV_NOPTS_VALUE
, AVIO_DATA_MARKER_HEADER
);
6576 if (mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
&&
6577 !(mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
))
6578 mov_write_identification(s
->pb
, s
);
6579 if ((ret
= mov_write_moov_tag(s
->pb
, mov
, s
)) < 0)
6582 if (mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
) {
6583 if (mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
)
6584 mov
->reserved_header_pos
= avio_tell(s
->pb
);
6585 avio_write_marker(s
->pb
, AV_NOPTS_VALUE
, AVIO_DATA_MARKER_FLUSH_POINT
);
6586 mov
->moov_written
= 1;
6590 buf_size
= avio_get_dyn_buf(mov
->mdat_buf
, &buf
);
6591 avio_wb32(s
->pb
, buf_size
+ 8);
6592 ffio_wfourcc(s
->pb
, "mdat");
6593 avio_write(s
->pb
, buf
, buf_size
);
6594 ffio_free_dyn_buf(&mov
->mdat_buf
);
6596 if (mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
)
6597 mov
->reserved_header_pos
= avio_tell(s
->pb
);
6599 mov
->moov_written
= 1;
6601 for (i
= 0; i
< mov
->nb_tracks
; i
++)
6602 mov_finish_fragment(mov
, &mov
->tracks
[i
], 0);
6603 avio_write_marker(s
->pb
, AV_NOPTS_VALUE
, AVIO_DATA_MARKER_FLUSH_POINT
);
6607 if (mov
->frag_interleave
) {
6608 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
6609 MOVTrack
*track
= &mov
->tracks
[i
];
6611 if ((ret
= mov_flush_fragment_interleaving(s
, track
)) < 0)
6617 mdat_size
= avio_tell(mov
->mdat_buf
);
6620 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
6621 MOVTrack
*track
= &mov
->tracks
[i
];
6622 if (mov
->flags
& FF_MOV_FLAG_SEPARATE_MOOF
|| mov
->frag_interleave
)
6623 track
->data_offset
= 0;
6625 track
->data_offset
= mdat_size
;
6626 if (track
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
6628 if (first_video_track
) {
6630 starts_with_key
= track
->cluster
[0].flags
& MOV_SYNC_SAMPLE
;
6631 first_video_track
= 0;
6636 if (track
->mdat_buf
)
6637 mdat_size
+= avio_tell(track
->mdat_buf
);
6638 if (first_track
< 0)
6645 avio_write_marker(s
->pb
,
6646 av_rescale(mov
->tracks
[first_track
].cluster
[0].dts
, AV_TIME_BASE
, mov
->tracks
[first_track
].timescale
),
6647 (has_video
? starts_with_key
: mov
->tracks
[first_track
].cluster
[0].flags
& MOV_SYNC_SAMPLE
) ? AVIO_DATA_MARKER_SYNC_POINT
: AVIO_DATA_MARKER_BOUNDARY_POINT
);
6649 for (i
= first_track
; i
< mov
->nb_tracks
; i
++) {
6650 MOVTrack
*track
= &mov
->tracks
[i
];
6651 int buf_size
, write_moof
= 1, moof_tracks
= -1;
6656 if (mov
->flags
& FF_MOV_FLAG_SEPARATE_MOOF
) {
6657 mdat_size
= avio_tell(track
->mdat_buf
);
6660 write_moof
= i
== first_track
;
6664 avio_write_marker(s
->pb
, AV_NOPTS_VALUE
, AVIO_DATA_MARKER_FLUSH_POINT
);
6666 mov_write_moof_tag(s
->pb
, mov
, moof_tracks
, mdat_size
);
6669 if (track
->cenc
.aes_ctr
)
6670 ff_mov_cenc_flush(&track
->cenc
);
6672 avio_wb32(s
->pb
, mdat_size
+ 8);
6673 ffio_wfourcc(s
->pb
, "mdat");
6674 mdat_start
= avio_tell(s
->pb
);
6677 mov_finish_fragment(mov
, &mov
->tracks
[i
], mdat_start
);
6678 if (!mov
->frag_interleave
) {
6679 if (!track
->mdat_buf
)
6681 buf_size
= avio_close_dyn_buf(track
->mdat_buf
, &buf
);
6682 track
->mdat_buf
= NULL
;
6686 buf_size
= avio_close_dyn_buf(mov
->mdat_buf
, &buf
);
6687 mov
->mdat_buf
= NULL
;
6690 avio_write(s
->pb
, buf
, buf_size
);
6696 avio_write_marker(s
->pb
, AV_NOPTS_VALUE
, AVIO_DATA_MARKER_FLUSH_POINT
);
6700 static int mov_auto_flush_fragment(AVFormatContext
*s
, int force
)
6702 MOVMuxContext
*mov
= s
->priv_data
;
6703 int had_moov
= mov
->moov_written
;
6704 int ret
= mov_flush_fragment(s
, force
);
6707 // If using delay_moov, the first flush only wrote the moov,
6708 // not the actual moof+mdat pair, thus flush once again.
6709 if (!had_moov
&& mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
)
6710 ret
= mov_flush_fragment(s
, force
);
6714 static int check_pkt(AVFormatContext
*s
, MOVTrack
*trk
, AVPacket
*pkt
)
6720 ref
= trk
->cluster
[trk
->entry
- 1].dts
;
6721 } else if ( trk
->start_dts
!= AV_NOPTS_VALUE
6722 && !trk
->frag_discont
) {
6723 ref
= trk
->start_dts
+ trk
->track_duration
;
6725 ref
= pkt
->dts
; // Skip tests for the first packet
6727 if (trk
->dts_shift
!= AV_NOPTS_VALUE
) {
6728 /* With negative CTS offsets we have set an offset to the DTS,
6729 * reverse this for the check. */
6730 ref
-= trk
->dts_shift
;
6733 duration
= pkt
->dts
- ref
;
6734 if (pkt
->dts
< ref
|| duration
>= INT_MAX
) {
6735 av_log(s
, AV_LOG_WARNING
, "Packet duration: %"PRId64
" / dts: %"PRId64
" in stream %d is out of range\n",
6736 duration
, pkt
->dts
, pkt
->stream_index
);
6739 pkt
->pts
= AV_NOPTS_VALUE
;
6742 if (pkt
->duration
< 0 || pkt
->duration
> INT_MAX
) {
6743 av_log(s
, AV_LOG_ERROR
, "Application provided duration: %"PRId64
" in stream %d is invalid\n", pkt
->duration
, pkt
->stream_index
);
6744 return AVERROR(EINVAL
);
6749 int ff_mov_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
6751 MOVMuxContext
*mov
= s
->priv_data
;
6752 AVIOContext
*pb
= s
->pb
;
6754 AVCodecParameters
*par
;
6755 AVProducerReferenceTime
*prft
;
6756 unsigned int samples_in_chunk
= 0;
6757 int size
= pkt
->size
, ret
= 0, offset
= 0;
6759 uint8_t *reformatted_data
= NULL
;
6761 if (pkt
->stream_index
< s
->nb_streams
)
6762 trk
= s
->streams
[pkt
->stream_index
]->priv_data
;
6763 else // Timecode or chapter
6764 trk
= &mov
->tracks
[pkt
->stream_index
];
6767 ret
= check_pkt(s
, trk
, pkt
);
6771 if (pkt
->pts
!= AV_NOPTS_VALUE
&&
6772 (uint64_t)pkt
->dts
- pkt
->pts
!= (int32_t)((uint64_t)pkt
->dts
- pkt
->pts
)) {
6773 av_log(s
, AV_LOG_WARNING
, "pts/dts pair unsupported\n");
6774 return AVERROR_PATCHWELCOME
;
6777 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
|| mov
->mode
== MODE_AVIF
) {
6779 if (mov
->moov_written
|| mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
) {
6780 if (mov
->frag_interleave
&& mov
->fragments
> 0) {
6781 if (trk
->entry
- trk
->entries_flushed
>= mov
->frag_interleave
) {
6782 if ((ret
= mov_flush_fragment_interleaving(s
, trk
)) < 0)
6787 if (!trk
->mdat_buf
) {
6788 if ((ret
= avio_open_dyn_buf(&trk
->mdat_buf
)) < 0)
6793 if (!mov
->mdat_buf
) {
6794 if ((ret
= avio_open_dyn_buf(&mov
->mdat_buf
)) < 0)
6801 if (par
->codec_id
== AV_CODEC_ID_AMR_NB
) {
6802 /* We must find out how many AMR blocks there are in one packet */
6803 static const uint16_t packed_size
[16] =
6804 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6807 while (len
< size
&& samples_in_chunk
< 100) {
6808 len
+= packed_size
[(pkt
->data
[len
] >> 3) & 0x0F];
6811 if (samples_in_chunk
> 1) {
6812 av_log(s
, AV_LOG_ERROR
, "fatal error, input is not a single packet, implement a AVParser for it\n");
6815 } else if (par
->codec_id
== AV_CODEC_ID_ADPCM_MS
||
6816 par
->codec_id
== AV_CODEC_ID_ADPCM_IMA_WAV
) {
6817 samples_in_chunk
= trk
->par
->frame_size
;
6818 } else if (trk
->sample_size
)
6819 samples_in_chunk
= size
/ trk
->sample_size
;
6821 samples_in_chunk
= 1;
6823 if (samples_in_chunk
< 1) {
6824 av_log(s
, AV_LOG_ERROR
, "fatal error, input packet contains no samples\n");
6825 return AVERROR_PATCHWELCOME
;
6828 /* copy extradata if it exists */
6829 if (trk
->extradata_size
[0] == 0 && par
->extradata_size
> 0 &&
6830 !TAG_IS_AVCI(trk
->tag
) &&
6831 (par
->codec_id
!= AV_CODEC_ID_DNXHD
)) {
6832 trk
->extradata
[0] = av_memdup(par
->extradata
, par
->extradata_size
);
6833 if (!trk
->extradata
[0]) {
6834 ret
= AVERROR(ENOMEM
);
6837 trk
->extradata_size
[0] = par
->extradata_size
;
6840 if ((par
->codec_id
== AV_CODEC_ID_DNXHD
||
6841 par
->codec_id
== AV_CODEC_ID_H264
||
6842 par
->codec_id
== AV_CODEC_ID_HEVC
||
6843 par
->codec_id
== AV_CODEC_ID_VVC
||
6844 par
->codec_id
== AV_CODEC_ID_VP9
||
6845 par
->codec_id
== AV_CODEC_ID_EVC
||
6846 par
->codec_id
== AV_CODEC_ID_TRUEHD
) && !trk
->extradata_size
[0] &&
6847 !TAG_IS_AVCI(trk
->tag
)) {
6848 /* copy frame to create needed atoms */
6849 trk
->extradata_size
[0] = size
;
6850 trk
->extradata
[0] = av_malloc(size
+ AV_INPUT_BUFFER_PADDING_SIZE
);
6851 if (!trk
->extradata
[0]) {
6852 ret
= AVERROR(ENOMEM
);
6855 memcpy(trk
->extradata
[0], pkt
->data
, size
);
6856 memset(trk
->extradata
[0] + size
, 0, AV_INPUT_BUFFER_PADDING_SIZE
);
6859 const AVPacketSideData
*sd
= av_packet_side_data_get(pkt
->side_data
, pkt
->side_data_elems
, AV_PKT_DATA_NEW_EXTRADATA
);
6860 if (pkt
->size
&& sd
&& sd
->size
> 0) {
6862 for (i
= 0; i
< trk
->stsd_count
; i
++) {
6863 if (trk
->extradata_size
[i
] == sd
->size
&& !memcmp(trk
->extradata
[i
], sd
->data
, sd
->size
))
6867 if (i
< trk
->stsd_count
)
6868 trk
->last_stsd_index
= i
;
6869 else if (trk
->stsd_count
<= INT_MAX
- 1) {
6870 int new_count
= trk
->stsd_count
+ 1;
6871 uint8_t **extradata
= av_realloc_array(trk
->extradata
, new_count
, sizeof(*trk
->extradata
));
6873 return AVERROR(ENOMEM
);
6874 trk
->extradata
= extradata
;
6876 int *extradata_size
= av_realloc_array(trk
->extradata_size
, new_count
, sizeof(*trk
->extradata_size
));
6877 if (!extradata_size
)
6878 return AVERROR(ENOMEM
);
6879 trk
->extradata_size
= extradata_size
;
6881 trk
->extradata
[trk
->stsd_count
] = av_memdup(sd
->data
, sd
->size
);
6882 if (!trk
->extradata
[trk
->stsd_count
])
6883 return AVERROR(ENOMEM
);
6885 trk
->extradata_size
[trk
->stsd_count
] = sd
->size
;
6886 trk
->last_stsd_index
= trk
->stsd_count
;
6887 trk
->stsd_count
= new_count
;
6889 return AVERROR(ENOMEM
);
6892 if (par
->codec_id
== AV_CODEC_ID_AAC
&& pkt
->size
> 2 &&
6893 (AV_RB16(pkt
->data
) & 0xfff0) == 0xfff0) {
6894 if (!trk
->st
->nb_frames
) {
6895 av_log(s
, AV_LOG_ERROR
, "Malformed AAC bitstream detected: "
6896 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6897 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6900 av_log(s
, AV_LOG_WARNING
, "aac bitstream error\n");
6902 if (par
->codec_id
== AV_CODEC_ID_H264
&& trk
->extradata_size
[trk
->last_stsd_index
] > 0 &&
6903 *(uint8_t *)trk
->extradata
[trk
->last_stsd_index
] != 1 && !TAG_IS_AVCI(trk
->tag
)) {
6904 /* from x264 or from bytestream H.264 */
6905 /* NAL reformatting needed */
6906 if (trk
->hint_track
>= 0 && trk
->hint_track
< mov
->nb_tracks
) {
6907 ret
= ff_nal_parse_units_buf(pkt
->data
, &reformatted_data
,
6911 avio_write(pb
, reformatted_data
, size
);
6913 if (trk
->cenc
.aes_ctr
) {
6914 size
= ff_mov_cenc_avc_parse_nal_units(&trk
->cenc
, pb
, pkt
->data
, size
);
6920 size
= ff_nal_parse_units(pb
, pkt
->data
, pkt
->size
);
6923 } else if (par
->codec_id
== AV_CODEC_ID_HEVC
&& trk
->extradata_size
[trk
->last_stsd_index
] > 6 &&
6924 (AV_RB24(trk
->extradata
[trk
->last_stsd_index
]) == 1 || AV_RB32(trk
->extradata
[trk
->last_stsd_index
]) == 1)) {
6925 /* extradata is Annex B, assume the bitstream is too and convert it */
6926 int filter_ps
= (trk
->tag
== MKTAG('h','v','c','1'));
6927 if (trk
->hint_track
>= 0 && trk
->hint_track
< mov
->nb_tracks
) {
6928 ret
= ff_hevc_annexb2mp4_buf(pkt
->data
, &reformatted_data
,
6929 &size
, filter_ps
, NULL
);
6932 avio_write(pb
, reformatted_data
, size
);
6934 if (trk
->cenc
.aes_ctr
) {
6935 size
= ff_mov_cenc_avc_parse_nal_units(&trk
->cenc
, pb
, pkt
->data
, size
);
6941 size
= ff_hevc_annexb2mp4(pb
, pkt
->data
, pkt
->size
, filter_ps
, NULL
);
6944 } else if (par
->codec_id
== AV_CODEC_ID_VVC
&& trk
->extradata_size
[trk
->last_stsd_index
] > 6 &&
6945 (AV_RB24(trk
->extradata
[trk
->last_stsd_index
]) == 1 || AV_RB32(trk
->extradata
[trk
->last_stsd_index
]) == 1)) {
6946 /* extradata is Annex B, assume the bitstream is too and convert it */
6947 if (trk
->hint_track
>= 0 && trk
->hint_track
< mov
->nb_tracks
) {
6948 ret
= ff_vvc_annexb2mp4_buf(pkt
->data
, &reformatted_data
,
6952 avio_write(pb
, reformatted_data
, size
);
6954 size
= ff_vvc_annexb2mp4(pb
, pkt
->data
, pkt
->size
, 0, NULL
);
6956 } else if (par
->codec_id
== AV_CODEC_ID_AV1
&& !trk
->cenc
.aes_ctr
) {
6957 if (trk
->hint_track
>= 0 && trk
->hint_track
< mov
->nb_tracks
) {
6958 ret
= ff_av1_filter_obus_buf(pkt
->data
, &reformatted_data
,
6962 avio_write(pb
, reformatted_data
, size
);
6964 size
= ff_av1_filter_obus(pb
, pkt
->data
, pkt
->size
);
6965 if (trk
->mode
== MODE_AVIF
&& !mov
->avif_extent_length
[pkt
->stream_index
]) {
6966 mov
->avif_extent_length
[pkt
->stream_index
] = size
;
6970 } else if (par
->codec_id
== AV_CODEC_ID_AC3
||
6971 par
->codec_id
== AV_CODEC_ID_EAC3
) {
6972 size
= handle_eac3(mov
, pkt
, trk
);
6977 avio_write(pb
, pkt
->data
, size
);
6978 } else if (par
->codec_id
== AV_CODEC_ID_EIA_608
) {
6981 for (int i
= 0; i
< pkt
->size
; i
+= 3) {
6982 if (pkt
->data
[i
] == 0xFC) {
6986 avio_wb32(pb
, size
);
6987 ffio_wfourcc(pb
, "cdat");
6988 for (int i
= 0; i
< pkt
->size
; i
+= 3) {
6989 if (pkt
->data
[i
] == 0xFC) {
6990 avio_w8(pb
, pkt
->data
[i
+ 1]);
6991 avio_w8(pb
, pkt
->data
[i
+ 2]);
6994 } else if (par
->codec_id
== AV_CODEC_ID_APV
) {
6995 ff_isom_parse_apvc(trk
->apv
, pkt
, s
);
6996 avio_wb32(s
->pb
, pkt
->size
);
6999 avio_write(s
->pb
, pkt
->data
, pkt
->size
);
7001 if (trk
->cenc
.aes_ctr
) {
7002 uint8_t *extradata
= trk
->extradata
[trk
->last_stsd_index
];
7003 int extradata_size
= trk
->extradata_size
[trk
->last_stsd_index
];
7004 if (par
->codec_id
== AV_CODEC_ID_H264
&& extradata_size
> 4) {
7005 int nal_size_length
= (extradata
[4] & 0x3) + 1;
7006 ret
= ff_mov_cenc_avc_write_nal_units(s
, &trk
->cenc
, nal_size_length
, pb
, pkt
->data
, size
);
7007 } else if(par
->codec_id
== AV_CODEC_ID_HEVC
&& extradata_size
> 21) {
7008 int nal_size_length
= (extradata
[21] & 0x3) + 1;
7009 ret
= ff_mov_cenc_avc_write_nal_units(s
, &trk
->cenc
, nal_size_length
, pb
, pkt
->data
, size
);
7010 } else if(par
->codec_id
== AV_CODEC_ID_VVC
) {
7011 ret
= AVERROR_PATCHWELCOME
;
7012 } else if(par
->codec_id
== AV_CODEC_ID_AV1
) {
7013 av_assert0(size
== pkt
->size
);
7014 ret
= ff_mov_cenc_av1_write_obus(s
, &trk
->cenc
, pb
, pkt
);
7020 ret
= ff_mov_cenc_write_packet(&trk
->cenc
, pb
, pkt
->data
, size
);
7027 avio_write(pb
, pkt
->data
, size
);
7031 if (trk
->entry
>= trk
->cluster_capacity
) {
7032 unsigned new_capacity
= trk
->entry
+ MOV_INDEX_CLUSTER_SIZE
;
7033 void *cluster
= av_realloc_array(trk
->cluster
, new_capacity
, sizeof(*trk
->cluster
));
7035 ret
= AVERROR(ENOMEM
);
7038 trk
->cluster
= cluster
;
7039 trk
->cluster_capacity
= new_capacity
;
7042 trk
->cluster
[trk
->entry
].pos
= avio_tell(pb
) - size
;
7043 trk
->cluster
[trk
->entry
].stsd_index
= trk
->last_stsd_index
;
7044 trk
->cluster
[trk
->entry
].samples_in_chunk
= samples_in_chunk
;
7045 trk
->cluster
[trk
->entry
].chunkNum
= 0;
7046 trk
->cluster
[trk
->entry
].size
= size
;
7047 trk
->cluster
[trk
->entry
].entries
= samples_in_chunk
;
7048 trk
->cluster
[trk
->entry
].dts
= pkt
->dts
;
7049 trk
->cluster
[trk
->entry
].pts
= pkt
->pts
;
7050 if (!trk
->squash_fragment_samples_to_one
&&
7051 !trk
->entry
&& trk
->start_dts
!= AV_NOPTS_VALUE
) {
7052 if (!trk
->frag_discont
) {
7053 /* First packet of a new fragment. We already wrote the duration
7054 * of the last packet of the previous fragment based on track_duration,
7055 * which might not exactly match our dts. Therefore adjust the dts
7056 * of this packet to be what the previous packets duration implies. */
7057 trk
->cluster
[trk
->entry
].dts
= trk
->start_dts
+ trk
->track_duration
;
7058 /* We also may have written the pts and the corresponding duration
7059 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7060 * the next fragment. This means the cts of the first sample must
7061 * be the same in all fragments, unless end_pts was updated by
7062 * the packet causing the fragment to be written. */
7063 if ((mov
->flags
& FF_MOV_FLAG_DASH
&&
7064 !(mov
->flags
& (FF_MOV_FLAG_GLOBAL_SIDX
| FF_MOV_FLAG_SKIP_SIDX
))) ||
7065 mov
->mode
== MODE_ISM
)
7066 pkt
->pts
= pkt
->dts
+ trk
->end_pts
- trk
->cluster
[trk
->entry
].dts
;
7068 /* New fragment, but discontinuous from previous fragments.
7069 * Pretend the duration sum of the earlier fragments is
7070 * pkt->dts - trk->start_dts. */
7071 trk
->end_pts
= AV_NOPTS_VALUE
;
7072 trk
->frag_discont
= 0;
7076 if (!trk
->entry
&& trk
->start_dts
== AV_NOPTS_VALUE
&& !mov
->use_editlist
&&
7077 s
->avoid_negative_ts
== AVFMT_AVOID_NEG_TS_MAKE_ZERO
) {
7078 /* Not using edit lists and shifting the first track to start from zero.
7079 * If the other streams start from a later timestamp, we won't be able
7080 * to signal the difference in starting time without an edit list.
7081 * Thus move the timestamp for this first sample to 0, increasing
7082 * its duration instead. */
7083 trk
->cluster
[trk
->entry
].dts
= trk
->start_dts
= 0;
7085 if (trk
->start_dts
== AV_NOPTS_VALUE
) {
7086 trk
->start_dts
= pkt
->dts
;
7087 if (trk
->frag_discont
) {
7088 if (mov
->use_editlist
) {
7089 /* Pretend the whole stream started at pts=0, with earlier fragments
7090 * already written. If the stream started at pts=0, the duration sum
7091 * of earlier fragments would have been pkt->pts. */
7092 trk
->start_dts
= pkt
->dts
- pkt
->pts
;
7094 /* Pretend the whole stream started at dts=0, with earlier fragments
7095 * already written, with a duration summing up to pkt->dts. */
7098 trk
->frag_discont
= 0;
7099 } else if (pkt
->dts
&& mov
->moov_written
)
7100 av_log(s
, AV_LOG_WARNING
,
7101 "Track %d starts with a nonzero dts %"PRId64
", while the moov "
7102 "already has been written. Set the delay_moov flag to handle "
7104 pkt
->stream_index
, pkt
->dts
);
7106 trk
->track_duration
= pkt
->dts
- trk
->start_dts
+ pkt
->duration
;
7107 trk
->last_sample_is_subtitle_end
= 0;
7109 if (pkt
->pts
== AV_NOPTS_VALUE
) {
7110 av_log(s
, AV_LOG_WARNING
, "pts has no value\n");
7111 pkt
->pts
= pkt
->dts
;
7113 if (pkt
->dts
!= pkt
->pts
)
7114 trk
->flags
|= MOV_TRACK_CTTS
;
7115 trk
->cluster
[trk
->entry
].cts
= pkt
->pts
- pkt
->dts
;
7116 trk
->cluster
[trk
->entry
].flags
= 0;
7117 if (trk
->start_cts
== AV_NOPTS_VALUE
|| (pkt
->dts
<= 0 && trk
->start_cts
> pkt
->pts
- pkt
->dts
))
7118 trk
->start_cts
= pkt
->pts
- pkt
->dts
;
7119 if (trk
->end_pts
== AV_NOPTS_VALUE
)
7120 trk
->end_pts
= trk
->cluster
[trk
->entry
].dts
+
7121 trk
->cluster
[trk
->entry
].cts
+ pkt
->duration
;
7123 trk
->end_pts
= FFMAX(trk
->end_pts
, trk
->cluster
[trk
->entry
].dts
+
7124 trk
->cluster
[trk
->entry
].cts
+
7127 if (par
->codec_id
== AV_CODEC_ID_VC1
) {
7128 mov_parse_vc1_frame(pkt
, trk
);
7129 } else if (par
->codec_id
== AV_CODEC_ID_TRUEHD
) {
7130 mov_parse_truehd_frame(pkt
, trk
);
7131 } else if (pkt
->flags
& AV_PKT_FLAG_KEY
) {
7132 if (mov
->mode
== MODE_MOV
&& par
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
&&
7133 trk
->entry
> 0) { // force sync sample for the first key frame
7134 mov_parse_mpeg2_frame(pkt
, &trk
->cluster
[trk
->entry
].flags
);
7135 if (trk
->cluster
[trk
->entry
].flags
& MOV_PARTIAL_SYNC_SAMPLE
)
7136 trk
->flags
|= MOV_TRACK_STPS
;
7138 trk
->cluster
[trk
->entry
].flags
= MOV_SYNC_SAMPLE
;
7140 if (trk
->cluster
[trk
->entry
].flags
& MOV_SYNC_SAMPLE
)
7141 trk
->has_keyframes
++;
7143 if (pkt
->flags
& AV_PKT_FLAG_DISPOSABLE
) {
7144 trk
->cluster
[trk
->entry
].flags
|= MOV_DISPOSABLE_SAMPLE
;
7145 trk
->has_disposable
++;
7148 prft
= (AVProducerReferenceTime
*)av_packet_get_side_data(pkt
, AV_PKT_DATA_PRFT
, &prft_size
);
7149 if (prft
&& prft_size
== sizeof(AVProducerReferenceTime
))
7150 memcpy(&trk
->cluster
[trk
->entry
].prft
, prft
, prft_size
);
7152 memset(&trk
->cluster
[trk
->entry
].prft
, 0, sizeof(AVProducerReferenceTime
));
7155 trk
->sample_count
+= samples_in_chunk
;
7156 mov
->mdat_size
+= size
;
7158 if (trk
->hint_track
>= 0 && trk
->hint_track
< mov
->nb_tracks
)
7159 ff_mov_add_hinted_packet(s
, pkt
, trk
->hint_track
, trk
->entry
,
7160 reformatted_data
? reformatted_data
+ offset
7166 if (pkt
->data
!= reformatted_data
)
7167 av_free(reformatted_data
);
7171 static int mov_write_single_packet(AVFormatContext
*s
, AVPacket
*pkt
)
7173 MOVMuxContext
*mov
= s
->priv_data
;
7174 MOVTrack
*trk
= s
->streams
[pkt
->stream_index
]->priv_data
;
7175 AVCodecParameters
*par
= trk
->par
;
7176 int64_t frag_duration
= 0;
7177 int size
= pkt
->size
;
7179 int ret
= check_pkt(s
, trk
, pkt
);
7183 if (mov
->flags
& FF_MOV_FLAG_FRAG_DISCONT
) {
7184 for (int i
= 0; i
< mov
->nb_streams
; i
++)
7185 mov
->tracks
[i
].frag_discont
= 1;
7186 mov
->flags
&= ~FF_MOV_FLAG_FRAG_DISCONT
;
7189 if (mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
) {
7190 if (trk
->dts_shift
== AV_NOPTS_VALUE
)
7191 trk
->dts_shift
= pkt
->pts
- pkt
->dts
;
7192 pkt
->dts
+= trk
->dts_shift
;
7195 if (trk
->par
->codec_id
== AV_CODEC_ID_MP4ALS
||
7196 trk
->par
->codec_id
== AV_CODEC_ID_AAC
||
7197 trk
->par
->codec_id
== AV_CODEC_ID_AV1
||
7198 trk
->par
->codec_id
== AV_CODEC_ID_FLAC
) {
7200 uint8_t *side
= av_packet_get_side_data(pkt
, AV_PKT_DATA_NEW_EXTRADATA
, &side_size
);
7201 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7202 if (side_size
> 0 && (!pkt
->size
|| !trk
->extradata_size
[trk
->last_stsd_index
])) {
7203 void *newextra
= av_memdup(side
, side_size
);
7205 return AVERROR(ENOMEM
);
7206 av_free(trk
->extradata
[trk
->last_stsd_index
]);
7207 trk
->extradata
[trk
->last_stsd_index
] = newextra
;
7208 trk
->extradata_size
[trk
->last_stsd_index
] = side_size
;
7213 if (trk
->start_dts
== AV_NOPTS_VALUE
&& trk
->frag_discont
) {
7214 trk
->start_dts
= pkt
->dts
;
7215 if (pkt
->pts
!= AV_NOPTS_VALUE
)
7216 trk
->start_cts
= pkt
->pts
- pkt
->dts
;
7221 return 0; /* Discard 0 sized packets */
7224 if (trk
->entry
&& pkt
->stream_index
< mov
->nb_streams
)
7225 frag_duration
= av_rescale_q(pkt
->dts
- trk
->cluster
[0].dts
,
7226 s
->streams
[pkt
->stream_index
]->time_base
,
7228 if ((mov
->max_fragment_duration
&&
7229 frag_duration
>= mov
->max_fragment_duration
) ||
7230 (mov
->max_fragment_size
&& mov
->mdat_size
+ size
>= mov
->max_fragment_size
) ||
7231 (mov
->flags
& FF_MOV_FLAG_FRAG_KEYFRAME
&&
7232 par
->codec_type
== AVMEDIA_TYPE_VIDEO
&&
7233 trk
->entry
&& pkt
->flags
& AV_PKT_FLAG_KEY
) ||
7234 (mov
->flags
& FF_MOV_FLAG_FRAG_EVERY_FRAME
)) {
7235 if (frag_duration
>= mov
->min_fragment_duration
) {
7237 // Set the duration of this track to line up with the next
7238 // sample in this track. This avoids relying on AVPacket
7239 // duration, but only helps for this particular track, not
7240 // for the other ones that are flushed at the same time.
7242 // If we have trk->entry == 0, no fragment will be written
7243 // for this track, and we can't adjust the track end here.
7244 trk
->track_duration
= pkt
->dts
- trk
->start_dts
;
7245 if (pkt
->pts
!= AV_NOPTS_VALUE
)
7246 trk
->end_pts
= pkt
->pts
;
7248 trk
->end_pts
= pkt
->dts
;
7249 trk
->end_reliable
= 1;
7251 mov_auto_flush_fragment(s
, 0);
7255 return ff_mov_write_packet(s
, pkt
);
7258 static int mov_write_subtitle_end_packet(AVFormatContext
*s
,
7261 MOVMuxContext
*mov
= s
->priv_data
;
7262 AVPacket
*end
= mov
->pkt
;
7263 uint8_t data
[2] = {0};
7266 end
->size
= sizeof(data
);
7271 end
->stream_index
= stream_index
;
7273 ret
= mov_write_single_packet(s
, end
);
7274 av_packet_unref(end
);
7280 static int mov_build_iamf_packet(AVFormatContext
*s
, MOVTrack
*trk
, AVPacket
*pkt
)
7285 if (pkt
->stream_index
== trk
->first_iamf_idx
) {
7286 ret
= ff_iamf_write_parameter_blocks(trk
->iamf
, trk
->iamf_buf
, pkt
, s
);
7291 ret
= ff_iamf_write_audio_frame(trk
->iamf
, trk
->iamf_buf
,
7292 s
->streams
[pkt
->stream_index
]->id
, pkt
);
7296 if (pkt
->stream_index
!= trk
->last_iamf_idx
)
7297 return AVERROR(EAGAIN
);
7299 ret
= avio_close_dyn_buf(trk
->iamf_buf
, &data
);
7300 trk
->iamf_buf
= NULL
;
7303 // Either all or none of the packets for a single
7304 // IA Sample may be empty.
7305 av_log(s
, AV_LOG_ERROR
, "Unexpected packet from "
7306 "stream #%d\n", pkt
->stream_index
);
7307 ret
= AVERROR_INVALIDDATA
;
7313 av_buffer_unref(&pkt
->buf
);
7314 pkt
->buf
= av_buffer_create(data
, ret
, NULL
, NULL
, 0);
7317 return AVERROR(ENOMEM
);
7321 pkt
->stream_index
= trk
->first_iamf_idx
;
7323 return avio_open_dyn_buf(&trk
->iamf_buf
);
7327 static int mov_write_emsg_tag(AVIOContext
*pb
, AVStream
*st
, AVPacket
*pkt
)
7329 int64_t pos
= avio_tell(pb
);
7330 const char *scheme_id_uri
= "https://aomedia.org/emsg/ID3";
7331 const char *value
= "";
7333 av_assert0(st
->time_base
.num
== 1);
7335 avio_write_marker(pb
,
7336 av_rescale_q(pkt
->pts
, st
->time_base
, AV_TIME_BASE_Q
),
7337 AVIO_DATA_MARKER_BOUNDARY_POINT
);
7339 avio_wb32(pb
, 0); /* size */
7340 ffio_wfourcc(pb
, "emsg");
7341 avio_w8(pb
, 1); /* version */
7343 avio_wb32(pb
, st
->time_base
.den
); /* timescale */
7344 avio_wb64(pb
, pkt
->pts
); /* presentation_time */
7345 avio_wb32(pb
, 0xFFFFFFFFU
); /* event_duration */
7346 avio_wb32(pb
, 0); /* id */
7347 /* null terminated UTF8 strings */
7348 avio_write(pb
, scheme_id_uri
, strlen(scheme_id_uri
) + 1);
7349 avio_write(pb
, value
, strlen(value
) + 1);
7350 avio_write(pb
, pkt
->data
, pkt
->size
);
7352 return update_size(pb
, pos
);
7355 static int mov_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
7357 MOVMuxContext
*mov
= s
->priv_data
;
7361 mov_flush_fragment(s
, 1);
7365 if (s
->streams
[pkt
->stream_index
]->codecpar
->codec_id
== AV_CODEC_ID_TIMED_ID3
) {
7366 mov_write_emsg_tag(s
->pb
, s
->streams
[pkt
->stream_index
], pkt
);
7370 trk
= s
->streams
[pkt
->stream_index
]->priv_data
;
7374 int ret
= mov_build_iamf_packet(s
, trk
, pkt
);
7376 if (ret
== AVERROR(EAGAIN
))
7378 av_log(s
, AV_LOG_ERROR
, "Error assembling an IAMF packet "
7379 "for stream #%d\n", trk
->st
->index
);
7385 if (is_cover_image(trk
->st
)) {
7388 if (trk
->st
->nb_frames
>= 1) {
7389 if (trk
->st
->nb_frames
== 1)
7390 av_log(s
, AV_LOG_WARNING
, "Got more than one picture in stream %d,"
7391 " ignoring.\n", pkt
->stream_index
);
7395 if ((ret
= av_packet_ref(trk
->cover_image
, pkt
)) < 0)
7403 return mov_write_single_packet(s
, pkt
); /* Passthrough. */
7406 * Subtitles require special handling.
7408 * 1) For full compliance, every track must have a sample at
7409 * dts == 0, which is rarely true for subtitles. So, as soon
7410 * as we see any packet with dts > 0, write an empty subtitle
7411 * at dts == 0 for any subtitle track with no samples in it.
7413 * 2) For each subtitle track, check if the current packet's
7414 * dts is past the duration of the last subtitle sample. If
7415 * so, we now need to write an end sample for that subtitle.
7417 * This must be done conditionally to allow for subtitles that
7418 * immediately replace each other, in which case an end sample
7419 * is not needed, and is, in fact, actively harmful.
7421 * 3) See mov_write_trailer for how the final end sample is
7424 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
7425 MOVTrack
*trk
= &mov
->tracks
[i
];
7428 if (trk
->par
->codec_id
== AV_CODEC_ID_MOV_TEXT
&&
7429 trk
->track_duration
< pkt
->dts
&&
7430 (trk
->entry
== 0 || !trk
->last_sample_is_subtitle_end
)) {
7431 ret
= mov_write_subtitle_end_packet(s
, i
, trk
->track_duration
);
7432 if (ret
< 0) return ret
;
7433 trk
->last_sample_is_subtitle_end
= 1;
7437 if (trk
->squash_fragment_samples_to_one
) {
7439 * If the track has to have its samples squashed into one sample,
7440 * we just take it into the track's queue.
7441 * This will then be utilized as the samples get written in either
7442 * mov_flush_fragment or when the mux is finalized in
7443 * mov_write_trailer.
7445 int ret
= AVERROR_BUG
;
7447 if (pkt
->pts
== AV_NOPTS_VALUE
) {
7448 av_log(s
, AV_LOG_ERROR
,
7449 "Packets without a valid presentation timestamp are "
7450 "not supported with packet squashing!\n");
7451 return AVERROR(EINVAL
);
7454 /* The following will reset pkt and is only allowed to be used
7455 * because we return immediately. afterwards. */
7456 if ((ret
= avpriv_packet_list_put(&trk
->squashed_packet_queue
,
7457 pkt
, NULL
, 0)) < 0) {
7465 if (trk
->mode
== MODE_MOV
&& trk
->par
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
7466 AVPacket
*opkt
= pkt
;
7467 int reshuffle_ret
, ret
;
7468 if (trk
->is_unaligned_qt_rgb
) {
7469 int64_t bpc
= trk
->par
->bits_per_coded_sample
!= 15 ? trk
->par
->bits_per_coded_sample
: 16;
7470 int expected_stride
= ((trk
->par
->width
* bpc
+ 15) >> 4)*2;
7471 reshuffle_ret
= ff_reshuffle_raw_rgb(s
, &pkt
, trk
->par
, expected_stride
);
7472 if (reshuffle_ret
< 0)
7473 return reshuffle_ret
;
7476 if (trk
->par
->format
== AV_PIX_FMT_PAL8
&& !trk
->pal_done
) {
7477 ret
= ff_get_packet_palette(s
, opkt
, reshuffle_ret
, trk
->palette
);
7482 } else if (trk
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&&
7483 (trk
->par
->format
== AV_PIX_FMT_GRAY8
||
7484 trk
->par
->format
== AV_PIX_FMT_MONOBLACK
)) {
7485 ret
= av_packet_make_writable(pkt
);
7488 for (i
= 0; i
< pkt
->size
; i
++)
7489 pkt
->data
[i
] = ~pkt
->data
[i
];
7491 if (reshuffle_ret
) {
7492 ret
= mov_write_single_packet(s
, pkt
);
7495 av_packet_free(&pkt
);
7500 return mov_write_single_packet(s
, pkt
);
7504 // QuickTime chapters involve an additional text track with the chapter names
7505 // as samples, and a tref pointing from the other tracks to the chapter one.
7506 static int mov_create_chapter_track(AVFormatContext
*s
, int tracknum
)
7508 static const uint8_t stub_header
[] = {
7510 0x00, 0x00, 0x00, 0x01, // displayFlags
7511 0x00, 0x00, // horizontal + vertical justification
7512 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7514 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7515 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7517 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7518 0x00, 0x01, // fontID
7519 0x00, 0x00, // fontStyleFlags + fontSize
7520 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7522 0x00, 0x00, 0x00, 0x0D, // box size
7523 'f', 't', 'a', 'b', // box atom name
7524 0x00, 0x01, // entry count
7526 0x00, 0x01, // font ID
7527 0x00, // font name length
7529 MOVMuxContext
*mov
= s
->priv_data
;
7530 MOVTrack
*track
= &mov
->tracks
[tracknum
];
7531 AVPacket
*pkt
= mov
->pkt
;
7535 track
->mode
= mov
->mode
;
7536 track
->tag
= MKTAG('t','e','x','t');
7537 track
->timescale
= mov
->movie_timescale
;
7538 track
->par
= avcodec_parameters_alloc();
7540 return AVERROR(ENOMEM
);
7541 track
->par
->codec_type
= AVMEDIA_TYPE_SUBTITLE
;
7542 ret
= ff_alloc_extradata(track
->par
, sizeof(stub_header
));
7545 memcpy(track
->par
->extradata
, stub_header
, sizeof(stub_header
));
7547 if (track
->extradata
== NULL
) {
7548 track
->stsd_count
= 1;
7549 track
->extradata
= av_calloc(1, sizeof(*track
->extradata
));
7550 track
->extradata_size
= av_calloc(1, sizeof(*track
->extradata_size
));
7551 if (!track
->extradata
|| !track
->extradata_size
)
7552 return AVERROR(ENOMEM
);
7555 track
->extradata
[0] = av_memdup(stub_header
, sizeof(stub_header
));
7556 if (!track
->extradata
[0])
7557 return AVERROR(ENOMEM
);
7558 track
->extradata_size
[0] = sizeof(stub_header
);
7560 pkt
->stream_index
= tracknum
;
7561 pkt
->flags
= AV_PKT_FLAG_KEY
;
7563 for (i
= 0; i
< s
->nb_chapters
; i
++) {
7564 AVChapter
*c
= s
->chapters
[i
];
7565 AVDictionaryEntry
*t
;
7567 int64_t end
= av_rescale_q(c
->end
, c
->time_base
, (AVRational
){1,mov
->movie_timescale
});
7568 pkt
->pts
= pkt
->dts
= av_rescale_q(c
->start
, c
->time_base
, (AVRational
){1,mov
->movie_timescale
});
7569 pkt
->duration
= end
- pkt
->dts
;
7571 if ((t
= av_dict_get(c
->metadata
, "title", NULL
, 0))) {
7572 static const char encd
[12] = {
7573 0x00, 0x00, 0x00, 0x0C,
7575 0x00, 0x00, 0x01, 0x00 };
7576 len
= strlen(t
->value
);
7577 pkt
->size
= len
+ 2 + 12;
7578 pkt
->data
= av_malloc(pkt
->size
);
7580 av_packet_unref(pkt
);
7581 return AVERROR(ENOMEM
);
7583 AV_WB16(pkt
->data
, len
);
7584 memcpy(pkt
->data
+ 2, t
->value
, len
);
7585 memcpy(pkt
->data
+ len
+ 2, encd
, sizeof(encd
));
7586 ff_mov_write_packet(s
, pkt
);
7587 av_freep(&pkt
->data
);
7591 av_packet_unref(mov
->pkt
);
7597 static int mov_check_timecode_track(AVFormatContext
*s
, AVTimecode
*tc
, AVStream
*src_st
, const char *tcstr
)
7601 /* compute the frame number */
7602 ret
= av_timecode_init_from_string(tc
, src_st
->avg_frame_rate
, tcstr
, s
);
7606 static int mov_create_timecode_track(AVFormatContext
*s
, int index
, int src_index
, AVTimecode tc
)
7608 MOVMuxContext
*mov
= s
->priv_data
;
7609 MOVTrack
*track
= &mov
->tracks
[index
];
7610 AVStream
*src_st
= mov
->tracks
[src_index
].st
;
7612 AVPacket
*pkt
= mov
->pkt
;
7613 AVRational rate
= src_st
->avg_frame_rate
;
7616 /* tmcd track based on video stream */
7617 track
->mode
= mov
->mode
;
7618 track
->tag
= MKTAG('t','m','c','d');
7619 track
->src_track
= src_index
;
7620 track
->timescale
= mov
->tracks
[src_index
].timescale
;
7621 if (tc
.flags
& AV_TIMECODE_FLAG_DROPFRAME
)
7622 track
->timecode_flags
|= MOV_TIMECODE_FLAG_DROPFRAME
;
7624 /* set st to src_st for metadata access*/
7627 /* encode context: tmcd data stream */
7628 track
->par
= avcodec_parameters_alloc();
7630 return AVERROR(ENOMEM
);
7631 track
->par
->codec_type
= AVMEDIA_TYPE_DATA
;
7632 track
->par
->codec_tag
= track
->tag
;
7633 track
->st
->avg_frame_rate
= rate
;
7635 /* the tmcd track just contains one packet with the frame number */
7637 pkt
->stream_index
= index
;
7638 pkt
->flags
= AV_PKT_FLAG_KEY
;
7639 pkt
->pts
= pkt
->dts
= av_rescale_q(tc
.start
, av_inv_q(rate
), (AVRational
){1,mov
->movie_timescale
});
7641 AV_WB32(pkt
->data
, tc
.start
);
7642 ret
= ff_mov_write_packet(s
, pkt
);
7643 av_packet_unref(pkt
);
7648 * st->disposition controls the "enabled" flag in the tkhd tag.
7649 * QuickTime will not play a track if it is not enabled. So make sure
7650 * that one track of each type (audio, video, subtitle) is enabled.
7652 * Subtitles are special. For audio and video, setting "enabled" also
7653 * makes the track "default" (i.e. it is rendered when played). For
7654 * subtitles, an "enabled" subtitle is not rendered by default, but
7655 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7658 static void enable_tracks(AVFormatContext
*s
)
7660 MOVMuxContext
*mov
= s
->priv_data
;
7662 int enabled
[AVMEDIA_TYPE_NB
];
7663 int first
[AVMEDIA_TYPE_NB
];
7665 for (i
= 0; i
< AVMEDIA_TYPE_NB
; i
++) {
7670 for (i
= 0; i
< mov
->nb_streams
; i
++) {
7671 AVStream
*st
= mov
->tracks
[i
].st
;
7673 if (st
->codecpar
->codec_type
<= AVMEDIA_TYPE_UNKNOWN
||
7674 st
->codecpar
->codec_type
>= AVMEDIA_TYPE_NB
||
7678 if (first
[st
->codecpar
->codec_type
] < 0)
7679 first
[st
->codecpar
->codec_type
] = i
;
7680 if (st
->disposition
& AV_DISPOSITION_DEFAULT
) {
7681 mov
->tracks
[i
].flags
|= MOV_TRACK_ENABLED
;
7682 enabled
[st
->codecpar
->codec_type
]++;
7686 for (i
= 0; i
< AVMEDIA_TYPE_NB
; i
++) {
7688 case AVMEDIA_TYPE_VIDEO
:
7689 case AVMEDIA_TYPE_AUDIO
:
7690 case AVMEDIA_TYPE_SUBTITLE
:
7692 mov
->per_stream_grouping
= 1;
7693 if (!enabled
[i
] && first
[i
] >= 0)
7694 mov
->tracks
[first
[i
]].flags
|= MOV_TRACK_ENABLED
;
7700 static void mov_free(AVFormatContext
*s
)
7702 MOVMuxContext
*mov
= s
->priv_data
;
7704 for (int i
= 0; i
< s
->nb_streams
; i
++)
7705 s
->streams
[i
]->priv_data
= NULL
;
7710 if (mov
->chapter_track
) {
7711 avcodec_parameters_free(&mov
->tracks
[mov
->chapter_track
].par
);
7714 for (int i
= 0; i
< mov
->nb_tracks
; i
++) {
7715 MOVTrack
*const track
= &mov
->tracks
[i
];
7717 if (track
->tag
== MKTAG('r','t','p',' '))
7718 ff_mov_close_hinting(track
);
7719 else if (track
->tag
== MKTAG('t','m','c','d') && mov
->nb_meta_tmcd
)
7720 av_freep(&track
->par
);
7721 av_freep(&track
->cluster
);
7722 av_freep(&track
->cluster_written
);
7723 av_freep(&track
->frag_info
);
7724 av_packet_free(&track
->cover_image
);
7726 if (track
->eac3_priv
) {
7727 struct eac3_info
*info
= track
->eac3_priv
;
7728 av_packet_free(&info
->pkt
);
7729 av_freep(&track
->eac3_priv
);
7731 for (int j
= 0; j
< track
->stsd_count
; j
++)
7732 av_freep(&track
->extradata
[j
]);
7733 av_freep(&track
->extradata
);
7734 av_freep(&track
->extradata_size
);
7736 ff_mov_cenc_free(&track
->cenc
);
7737 ffio_free_dyn_buf(&track
->mdat_buf
);
7740 ffio_free_dyn_buf(&track
->iamf_buf
);
7742 ff_iamf_uninit_context(track
->iamf
);
7743 av_freep(&track
->iamf
);
7745 ff_isom_close_apvc(&track
->apv
);
7747 avpriv_packet_list_free(&track
->squashed_packet_queue
);
7750 av_freep(&mov
->tracks
);
7751 ffio_free_dyn_buf(&mov
->mdat_buf
);
7754 static uint32_t rgb_to_yuv(uint32_t rgb
)
7759 r
= (rgb
>> 16) & 0xFF;
7760 g
= (rgb
>> 8) & 0xFF;
7763 y
= av_clip_uint8(( 16000 + 257 * r
+ 504 * g
+ 98 * b
)/1000);
7764 cb
= av_clip_uint8((128000 - 148 * r
- 291 * g
+ 439 * b
)/1000);
7765 cr
= av_clip_uint8((128000 + 439 * r
- 368 * g
- 71 * b
)/1000);
7767 return (y
<< 16) | (cr
<< 8) | cb
;
7770 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack
*track
,
7773 int i
, width
= 720, height
= 480;
7774 int have_palette
= 0, have_size
= 0;
7775 uint32_t palette
[16];
7776 char *cur
= track
->extradata
[track
->last_stsd_index
];
7778 while (cur
&& *cur
) {
7779 if (strncmp("palette:", cur
, 8) == 0) {
7781 count
= sscanf(cur
+ 8,
7782 "%06"PRIx32
", %06"PRIx32
", %06"PRIx32
", %06"PRIx32
", "
7783 "%06"PRIx32
", %06"PRIx32
", %06"PRIx32
", %06"PRIx32
", "
7784 "%06"PRIx32
", %06"PRIx32
", %06"PRIx32
", %06"PRIx32
", "
7785 "%06"PRIx32
", %06"PRIx32
", %06"PRIx32
", %06"PRIx32
"",
7786 &palette
[ 0], &palette
[ 1], &palette
[ 2], &palette
[ 3],
7787 &palette
[ 4], &palette
[ 5], &palette
[ 6], &palette
[ 7],
7788 &palette
[ 8], &palette
[ 9], &palette
[10], &palette
[11],
7789 &palette
[12], &palette
[13], &palette
[14], &palette
[15]);
7791 for (i
= 0; i
< count
; i
++) {
7792 palette
[i
] = rgb_to_yuv(palette
[i
]);
7795 } else if (!strncmp("size:", cur
, 5)) {
7796 sscanf(cur
+ 5, "%dx%d", &width
, &height
);
7799 if (have_palette
&& have_size
)
7801 cur
+= strcspn(cur
, "\n\r");
7802 cur
+= strspn(cur
, "\n\r");
7805 track
->extradata
[track
->last_stsd_index
] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE
);
7806 if (!track
->extradata
[track
->last_stsd_index
])
7807 return AVERROR(ENOMEM
);
7808 for (i
= 0; i
< 16; i
++) {
7809 AV_WB32(track
->extradata
[track
->last_stsd_index
] + i
* 4, palette
[i
]);
7811 memset(track
->extradata
[track
->last_stsd_index
] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE
);
7812 track
->extradata_size
[track
->last_stsd_index
] = 16 * 4;
7814 st
->codecpar
->width
= width
;
7815 st
->codecpar
->height
= track
->height
= height
;
7821 static int mov_init_iamf_track(AVFormatContext
*s
)
7823 MOVMuxContext
*mov
= s
->priv_data
;
7826 int first_iamf_idx
= INT_MAX
, last_iamf_idx
= 0;
7827 int nb_audio_elements
= 0, nb_mix_presentations
= 0;
7830 for (int i
= 0; i
< s
->nb_stream_groups
; i
++) {
7831 const AVStreamGroup
*stg
= s
->stream_groups
[i
];
7833 if (stg
->type
== AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
)
7834 nb_audio_elements
++;
7835 if (stg
->type
== AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION
)
7836 nb_mix_presentations
++;
7839 if (!nb_audio_elements
&& !nb_mix_presentations
)
7842 if (nb_audio_elements
< 1 || nb_audio_elements
> 2 || nb_mix_presentations
< 1) {
7843 av_log(s
, AV_LOG_ERROR
, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7844 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7845 return AVERROR(EINVAL
);
7848 iamf
= av_mallocz(sizeof(*iamf
));
7850 return AVERROR(ENOMEM
);
7853 for (int i
= 0; i
< s
->nb_stream_groups
; i
++) {
7854 const AVStreamGroup
*stg
= s
->stream_groups
[i
];
7856 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
:
7857 for (int j
= 0; j
< stg
->nb_streams
; j
++) {
7858 first_iamf_idx
= FFMIN(stg
->streams
[j
]->index
, first_iamf_idx
);
7859 last_iamf_idx
= FFMAX(stg
->streams
[j
]->index
, last_iamf_idx
);
7862 ret
= ff_iamf_add_audio_element(iamf
, stg
, s
);
7864 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION
:
7865 ret
= ff_iamf_add_mix_presentation(iamf
, stg
, s
);
7874 track
= &mov
->tracks
[first_iamf_idx
];
7876 track
->first_iamf_idx
= first_iamf_idx
;
7877 track
->last_iamf_idx
= last_iamf_idx
;
7878 track
->tag
= MKTAG('i','a','m','f');
7880 for (int i
= 0; i
< s
->nb_stream_groups
; i
++) {
7881 AVStreamGroup
*stg
= s
->stream_groups
[i
];
7882 if (stg
->type
!= AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
)
7884 for (int j
= 0; j
< stg
->nb_streams
; j
++)
7885 stg
->streams
[j
]->priv_data
= track
;
7888 ret
= avio_open_dyn_buf(&track
->iamf_buf
);
7896 static int mov_init(AVFormatContext
*s
)
7898 MOVMuxContext
*mov
= s
->priv_data
;
7903 mov
->pkt
= ffformatcontext(s
)->pkt
;
7905 /* Default mode == MP4 */
7906 mov
->mode
= MODE_MP4
;
7908 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7909 if (IS_MODE(3gp
, TGP
)) mov
->mode
= MODE_3GP
;
7910 else if (IS_MODE(3g2
, TG2
)) mov
->mode
= MODE_3GP
|MODE_3G2
;
7911 else if (IS_MODE(mov
, MOV
)) mov
->mode
= MODE_MOV
;
7912 else if (IS_MODE(psp
, PSP
)) mov
->mode
= MODE_PSP
;
7913 else if (IS_MODE(ipod
, IPOD
)) mov
->mode
= MODE_IPOD
;
7914 else if (IS_MODE(ismv
, ISMV
)) mov
->mode
= MODE_ISM
;
7915 else if (IS_MODE(f4v
, F4V
)) mov
->mode
= MODE_F4V
;
7916 else if (IS_MODE(avif
, AVIF
)) mov
->mode
= MODE_AVIF
;
7919 if (mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
)
7920 mov
->flags
|= FF_MOV_FLAG_EMPTY_MOOV
;
7922 if (mov
->mode
== MODE_AVIF
)
7923 mov
->flags
|= FF_MOV_FLAG_DELAY_MOOV
;
7925 /* Set the FRAGMENT flag if any of the fragmentation methods are
7927 if (mov
->max_fragment_duration
|| mov
->max_fragment_size
||
7928 mov
->flags
& (FF_MOV_FLAG_EMPTY_MOOV
|
7929 FF_MOV_FLAG_FRAG_KEYFRAME
|
7930 FF_MOV_FLAG_FRAG_CUSTOM
|
7931 FF_MOV_FLAG_FRAG_EVERY_FRAME
))
7932 mov
->flags
|= FF_MOV_FLAG_FRAGMENT
;
7934 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
&&
7935 mov
->flags
& FF_MOV_FLAG_FASTSTART
) {
7936 av_log(s
, AV_LOG_ERROR
, "Setting both hybrid_fragmented and faststart is not supported.\n");
7937 return AVERROR(EINVAL
);
7940 /* Set other implicit flags immediately */
7941 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
)
7942 mov
->flags
|= FF_MOV_FLAG_FRAGMENT
;
7944 if (mov
->mode
== MODE_ISM
)
7945 mov
->flags
|= FF_MOV_FLAG_EMPTY_MOOV
| FF_MOV_FLAG_SEPARATE_MOOF
|
7946 FF_MOV_FLAG_FRAGMENT
| FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
;
7947 if (mov
->flags
& FF_MOV_FLAG_DASH
)
7948 mov
->flags
|= FF_MOV_FLAG_FRAGMENT
| FF_MOV_FLAG_EMPTY_MOOV
|
7949 FF_MOV_FLAG_DEFAULT_BASE_MOOF
;
7950 if (mov
->flags
& FF_MOV_FLAG_CMAF
)
7951 mov
->flags
|= FF_MOV_FLAG_FRAGMENT
| FF_MOV_FLAG_EMPTY_MOOV
|
7952 FF_MOV_FLAG_DEFAULT_BASE_MOOF
| FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
;
7954 if (mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
&& s
->flags
& AVFMT_FLAG_AUTO_BSF
) {
7955 av_log(s
, AV_LOG_VERBOSE
, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7956 s
->flags
&= ~AVFMT_FLAG_AUTO_BSF
;
7959 if (mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
&& mov
->flags
& FF_MOV_FLAG_SKIP_SIDX
) {
7960 av_log(s
, AV_LOG_WARNING
, "Global SIDX enabled; Ignoring skip_sidx option\n");
7961 mov
->flags
&= ~FF_MOV_FLAG_SKIP_SIDX
;
7964 if (mov
->flags
& FF_MOV_FLAG_FASTSTART
) {
7965 mov
->reserved_moov_size
= -1;
7968 if (mov
->use_editlist
< 0) {
7969 mov
->use_editlist
= 1;
7970 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
&&
7971 !(mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
)) {
7972 // If we can avoid needing an edit list by shifting the
7973 // tracks, prefer that over (trying to) write edit lists
7974 // in fragmented output.
7975 if (s
->avoid_negative_ts
== AVFMT_AVOID_NEG_TS_AUTO
||
7976 s
->avoid_negative_ts
== AVFMT_AVOID_NEG_TS_MAKE_ZERO
)
7977 mov
->use_editlist
= 0;
7980 if (mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
&&
7981 !(mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
) && mov
->use_editlist
)
7982 av_log(s
, AV_LOG_WARNING
, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7984 if (!mov
->use_editlist
&& s
->avoid_negative_ts
== AVFMT_AVOID_NEG_TS_AUTO
&&
7985 !(mov
->flags
& FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS
))
7986 s
->avoid_negative_ts
= AVFMT_AVOID_NEG_TS_MAKE_ZERO
;
7988 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7989 * if the latter is set that's enough and omit_tfhd_offset doesn't
7990 * add anything extra on top of that. */
7991 if (mov
->flags
& FF_MOV_FLAG_OMIT_TFHD_OFFSET
&&
7992 mov
->flags
& FF_MOV_FLAG_DEFAULT_BASE_MOOF
)
7993 mov
->flags
&= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET
;
7995 if (mov
->frag_interleave
&&
7996 mov
->flags
& (FF_MOV_FLAG_OMIT_TFHD_OFFSET
| FF_MOV_FLAG_SEPARATE_MOOF
)) {
7997 av_log(s
, AV_LOG_ERROR
,
7998 "Sample interleaving in fragments is mutually exclusive with "
7999 "omit_tfhd_offset and separate_moof\n");
8000 return AVERROR(EINVAL
);
8003 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8004 * is enabled, we don't support non-seekable output at all. */
8005 if (!(s
->pb
->seekable
& AVIO_SEEKABLE_NORMAL
) &&
8006 (!(mov
->flags
& FF_MOV_FLAG_FRAGMENT
) || mov
->ism_lookahead
||
8007 mov
->mode
== MODE_AVIF
)) {
8008 av_log(s
, AV_LOG_ERROR
, "muxer does not support non seekable output\n");
8009 return AVERROR(EINVAL
);
8012 /* AVIF output must have at most two video streams (one for YUV and one for
8014 if (mov
->mode
== MODE_AVIF
) {
8015 if (s
->nb_streams
> 2) {
8016 av_log(s
, AV_LOG_ERROR
, "AVIF output requires exactly one or two streams\n");
8017 return AVERROR(EINVAL
);
8019 if (s
->streams
[0]->codecpar
->codec_type
!= AVMEDIA_TYPE_VIDEO
&&
8020 (s
->nb_streams
> 1 && s
->streams
[1]->codecpar
->codec_type
!= AVMEDIA_TYPE_VIDEO
)) {
8021 av_log(s
, AV_LOG_ERROR
, "AVIF output supports only video streams\n");
8022 return AVERROR(EINVAL
);
8024 if (s
->nb_streams
> 1) {
8025 const AVPixFmtDescriptor
*pixdesc
=
8026 av_pix_fmt_desc_get(s
->streams
[1]->codecpar
->format
);
8027 if (pixdesc
->nb_components
!= 1) {
8028 av_log(s
, AV_LOG_ERROR
, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8029 return AVERROR(EINVAL
);
8032 s
->streams
[0]->disposition
|= AV_DISPOSITION_DEFAULT
;
8036 for (i
= 0; i
< s
->nb_stream_groups
; i
++) {
8037 AVStreamGroup
*stg
= s
->stream_groups
[i
];
8039 if (stg
->type
!= AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
)
8042 for (int j
= 0; j
< stg
->nb_streams
; j
++) {
8043 AVStream
*st
= stg
->streams
[j
];
8045 if (st
->priv_data
) {
8046 av_log(s
, AV_LOG_ERROR
, "Stream %d is present in more than one Stream Group of type "
8047 "IAMF Audio Element\n", j
);
8048 return AVERROR(EINVAL
);
8054 if (!mov
->nb_tracks
) // We support one track for the entire IAMF structure
8059 for (i
= 0; i
< s
->nb_streams
; i
++) {
8060 AVStream
*st
= s
->streams
[i
];
8063 // Don't produce a track in the output file for timed ID3 streams.
8064 if (st
->codecpar
->codec_id
== AV_CODEC_ID_TIMED_ID3
) {
8065 // Leave priv_data set to NULL for these AVStreams that don't
8066 // have a corresponding track.
8073 mov
->nb_streams
= mov
->nb_tracks
;
8075 if (mov
->mode
& (MODE_MP4
|MODE_MOV
|MODE_IPOD
) && s
->nb_chapters
)
8076 mov
->chapter_track
= mov
->nb_tracks
++;
8078 if (mov
->flags
& FF_MOV_FLAG_RTP_HINT
) {
8079 for (i
= 0; i
< s
->nb_streams
; i
++)
8080 if (rtp_hinting_needed(s
->streams
[i
]))
8084 if (mov
->write_btrt
< 0) {
8085 mov
->write_btrt
= mov
->mode
== MODE_MP4
;
8088 if ( mov
->write_tmcd
== -1 && (mov
->mode
== MODE_MOV
|| mov
->mode
== MODE_MP4
)
8089 || mov
->write_tmcd
== 1) {
8090 AVDictionaryEntry
*global_tcr
= av_dict_get(s
->metadata
, "timecode",
8093 /* +1 tmcd track for each video stream with a timecode */
8094 for (i
= 0; i
< s
->nb_streams
; i
++) {
8095 AVStream
*st
= s
->streams
[i
];
8096 AVDictionaryEntry
*t
= global_tcr
;
8097 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
&&
8098 (t
|| (t
=av_dict_get(st
->metadata
, "timecode", NULL
, 0)))) {
8100 ret
= mov_check_timecode_track(s
, &tc
, st
, t
->value
);
8102 mov
->nb_meta_tmcd
++;
8106 /* check if there is already a tmcd track to remux */
8107 if (mov
->nb_meta_tmcd
) {
8108 for (i
= 0; i
< s
->nb_streams
; i
++) {
8109 AVStream
*st
= s
->streams
[i
];
8110 if (st
->codecpar
->codec_tag
== MKTAG('t','m','c','d')) {
8111 av_log(s
, AV_LOG_WARNING
, "You requested a copy of the original timecode track "
8112 "so timecode metadata are now ignored\n");
8113 mov
->nb_meta_tmcd
= 0;
8118 mov
->nb_tracks
+= mov
->nb_meta_tmcd
;
8121 // Reserve an extra stream for chapters for the case where chapters
8122 // are written in the trailer
8123 mov
->tracks
= av_calloc(mov
->nb_tracks
+ 1, sizeof(*mov
->tracks
));
8125 return AVERROR(ENOMEM
);
8127 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
8128 MOVTrack
*track
= &mov
->tracks
[i
];
8130 track
->stsd_count
= 1;
8131 track
->extradata
= av_calloc(track
->stsd_count
, sizeof(*track
->extradata
));
8132 track
->extradata_size
= av_calloc(track
->stsd_count
, sizeof(*track
->extradata_size
));
8133 if (!track
->extradata
|| !track
->extradata_size
)
8134 return AVERROR(ENOMEM
);
8137 if (mov
->encryption_scheme_str
!= NULL
&& strcmp(mov
->encryption_scheme_str
, "none") != 0) {
8138 if (strcmp(mov
->encryption_scheme_str
, "cenc-aes-ctr") == 0) {
8139 mov
->encryption_scheme
= MOV_ENC_CENC_AES_CTR
;
8141 if (mov
->encryption_key_len
!= AES_CTR_KEY_SIZE
) {
8142 av_log(s
, AV_LOG_ERROR
, "Invalid encryption key len %d expected %d\n",
8143 mov
->encryption_key_len
, AES_CTR_KEY_SIZE
);
8144 return AVERROR(EINVAL
);
8147 if (mov
->encryption_kid_len
!= CENC_KID_SIZE
) {
8148 av_log(s
, AV_LOG_ERROR
, "Invalid encryption kid len %d expected %d\n",
8149 mov
->encryption_kid_len
, CENC_KID_SIZE
);
8150 return AVERROR(EINVAL
);
8153 av_log(s
, AV_LOG_ERROR
, "unsupported encryption scheme %s\n",
8154 mov
->encryption_scheme_str
);
8155 return AVERROR(EINVAL
);
8160 ret
= mov_init_iamf_track(s
);
8165 for (int j
= 0, i
= 0; j
< s
->nb_streams
; j
++) {
8166 AVStream
*st
= s
->streams
[j
];
8168 if (st
!= st
->priv_data
) {
8173 st
->priv_data
= &mov
->tracks
[i
++];
8176 for (i
= 0; i
< s
->nb_streams
; i
++) {
8177 AVStream
*st
= s
->streams
[i
];
8178 MOVTrack
*track
= st
->priv_data
;
8179 AVDictionaryEntry
*lang
= av_dict_get(st
->metadata
, "language", NULL
,0);
8186 track
->par
= st
->codecpar
;
8188 track
->language
= ff_mov_iso639_to_lang(lang
?lang
->value
:"und", mov
->mode
!=MODE_MOV
);
8189 if (track
->language
< 0)
8190 track
->language
= 32767; // Unspecified Macintosh language code
8191 track
->mode
= mov
->mode
;
8193 track
->tag
= mov_find_codec_tag(s
, track
);
8195 av_log(s
, AV_LOG_ERROR
, "Could not find tag for codec %s in stream #%d, "
8196 "codec not currently supported in container\n",
8197 avcodec_get_name(st
->codecpar
->codec_id
), i
);
8198 return AVERROR(EINVAL
);
8200 /* If hinting of this track is enabled by a later hint track,
8201 * this is updated. */
8202 track
->hint_track
= -1;
8203 track
->start_dts
= AV_NOPTS_VALUE
;
8204 track
->start_cts
= AV_NOPTS_VALUE
;
8205 track
->end_pts
= AV_NOPTS_VALUE
;
8206 track
->dts_shift
= AV_NOPTS_VALUE
;
8207 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
8208 if (track
->tag
== MKTAG('m','x','3','p') || track
->tag
== MKTAG('m','x','3','n') ||
8209 track
->tag
== MKTAG('m','x','4','p') || track
->tag
== MKTAG('m','x','4','n') ||
8210 track
->tag
== MKTAG('m','x','5','p') || track
->tag
== MKTAG('m','x','5','n')) {
8211 if (st
->codecpar
->width
!= 720 || (st
->codecpar
->height
!= 608 && st
->codecpar
->height
!= 512)) {
8212 av_log(s
, AV_LOG_ERROR
, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8213 return AVERROR(EINVAL
);
8215 track
->height
= track
->tag
>> 24 == 'n' ? 486 : 576;
8217 if (mov
->video_track_timescale
) {
8218 track
->timescale
= mov
->video_track_timescale
;
8219 if (mov
->mode
== MODE_ISM
&& mov
->video_track_timescale
!= 10000000)
8220 av_log(s
, AV_LOG_WARNING
, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8222 track
->timescale
= st
->time_base
.den
;
8223 while(track
->timescale
< 10000)
8224 track
->timescale
*= 2;
8226 if (st
->codecpar
->width
> 65535 || st
->codecpar
->height
> 65535) {
8227 av_log(s
, AV_LOG_ERROR
, "Resolution %dx%d too large for mov/mp4\n", st
->codecpar
->width
, st
->codecpar
->height
);
8228 return AVERROR(EINVAL
);
8230 if (track
->mode
== MODE_MOV
&& track
->timescale
> 100000)
8231 av_log(s
, AV_LOG_WARNING
,
8232 "WARNING codec timebase is very high. If duration is too long,\n"
8233 "file may not be playable by quicktime. Specify a shorter timebase\n"
8234 "or choose different container.\n");
8235 if (track
->mode
== MODE_MOV
&&
8236 track
->par
->codec_id
== AV_CODEC_ID_RAWVIDEO
&&
8237 track
->tag
== MKTAG('r','a','w',' ')) {
8238 enum AVPixelFormat pix_fmt
= track
->par
->format
;
8239 if (pix_fmt
== AV_PIX_FMT_NONE
&& track
->par
->bits_per_coded_sample
== 1)
8240 pix_fmt
= AV_PIX_FMT_MONOWHITE
;
8241 track
->is_unaligned_qt_rgb
=
8242 pix_fmt
== AV_PIX_FMT_RGB24
||
8243 pix_fmt
== AV_PIX_FMT_BGR24
||
8244 pix_fmt
== AV_PIX_FMT_PAL8
||
8245 pix_fmt
== AV_PIX_FMT_GRAY8
||
8246 pix_fmt
== AV_PIX_FMT_MONOWHITE
||
8247 pix_fmt
== AV_PIX_FMT_MONOBLACK
;
8249 if (track
->par
->codec_id
== AV_CODEC_ID_VP9
&& track
->mode
!= MODE_MP4
) {
8250 av_log(s
, AV_LOG_ERROR
, "%s only supported in MP4.\n", avcodec_get_name(track
->par
->codec_id
));
8251 return AVERROR(EINVAL
);
8252 } else if (track
->par
->codec_id
== AV_CODEC_ID_AV1
&&
8253 track
->mode
!= MODE_MP4
&& track
->mode
!= MODE_AVIF
) {
8254 av_log(s
, AV_LOG_ERROR
, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track
->par
->codec_id
));
8255 return AVERROR(EINVAL
);
8256 } else if (track
->par
->codec_id
== AV_CODEC_ID_VP8
) {
8257 /* altref frames handling is not defined in the spec as of version v1.0,
8258 * so just forbid muxing VP8 streams altogether until a new version does */
8259 av_log(s
, AV_LOG_ERROR
, "VP8 muxing is currently not supported.\n");
8260 return AVERROR_PATCHWELCOME
;
8261 } else if (track
->par
->codec_id
== AV_CODEC_ID_APV
) {
8262 ret
= ff_isom_init_apvc(&track
->apv
, s
);
8266 if (is_cover_image(st
)) {
8267 track
->cover_image
= av_packet_alloc();
8268 if (!track
->cover_image
)
8269 return AVERROR(ENOMEM
);
8271 } else if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
8272 track
->timescale
= st
->codecpar
->sample_rate
;
8273 if (!st
->codecpar
->frame_size
&& !av_get_bits_per_sample(st
->codecpar
->codec_id
)) {
8274 av_log(s
, AV_LOG_WARNING
, "track %d: codec frame size is not set\n", i
);
8275 track
->audio_vbr
= 1;
8276 }else if (st
->codecpar
->codec_id
== AV_CODEC_ID_ADPCM_MS
||
8277 st
->codecpar
->codec_id
== AV_CODEC_ID_ADPCM_IMA_WAV
||
8278 st
->codecpar
->codec_id
== AV_CODEC_ID_ILBC
){
8279 if (!st
->codecpar
->block_align
) {
8280 av_log(s
, AV_LOG_ERROR
, "track %d: codec block align is not set for adpcm\n", i
);
8281 return AVERROR(EINVAL
);
8283 track
->sample_size
= st
->codecpar
->block_align
;
8284 }else if (st
->codecpar
->frame_size
> 1){ /* assume compressed audio */
8285 track
->audio_vbr
= 1;
8287 track
->sample_size
= (av_get_bits_per_sample(st
->codecpar
->codec_id
) >> 3) *
8288 st
->codecpar
->ch_layout
.nb_channels
;
8290 if (st
->codecpar
->codec_id
== AV_CODEC_ID_ILBC
||
8291 st
->codecpar
->codec_id
== AV_CODEC_ID_ADPCM_IMA_QT
) {
8292 track
->audio_vbr
= 1;
8294 if (track
->mode
!= MODE_MOV
&&
8295 track
->par
->codec_id
== AV_CODEC_ID_MP3
&& track
->timescale
< 16000) {
8296 if (s
->strict_std_compliance
>= FF_COMPLIANCE_NORMAL
) {
8297 av_log(s
, AV_LOG_ERROR
, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8298 i
, track
->par
->sample_rate
);
8299 return AVERROR(EINVAL
);
8301 av_log(s
, AV_LOG_WARNING
, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8302 i
, track
->par
->sample_rate
);
8305 if (track
->par
->codec_id
== AV_CODEC_ID_FLAC
||
8306 track
->par
->codec_id
== AV_CODEC_ID_TRUEHD
||
8307 track
->par
->codec_id
== AV_CODEC_ID_OPUS
) {
8308 if (track
->mode
!= MODE_MP4
) {
8309 av_log(s
, AV_LOG_ERROR
, "%s only supported in MP4.\n", avcodec_get_name(track
->par
->codec_id
));
8310 return AVERROR(EINVAL
);
8312 if (track
->par
->codec_id
== AV_CODEC_ID_TRUEHD
&&
8313 s
->strict_std_compliance
> FF_COMPLIANCE_EXPERIMENTAL
) {
8314 av_log(s
, AV_LOG_ERROR
,
8315 "%s in MP4 support is experimental, add "
8316 "'-strict %d' if you want to use it.\n",
8317 avcodec_get_name(track
->par
->codec_id
), FF_COMPLIANCE_EXPERIMENTAL
);
8318 return AVERROR_EXPERIMENTAL
;
8321 } else if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_SUBTITLE
) {
8322 track
->timescale
= st
->time_base
.den
;
8324 if (track
->par
->codec_id
== AV_CODEC_ID_TTML
) {
8325 /* 14496-30 requires us to use a single sample per fragment
8326 for TTML, for which we define a per-track flag.
8328 We set the flag in case we are receiving TTML paragraphs
8329 from the input, in other words in case we are not doing
8331 track
->squash_fragment_samples_to_one
=
8332 ff_is_ttml_stream_paragraph_based(track
->par
);
8334 if (track
->mode
!= MODE_ISM
&&
8335 track
->par
->codec_tag
== MOV_ISMV_TTML_TAG
&&
8336 s
->strict_std_compliance
> FF_COMPLIANCE_UNOFFICIAL
) {
8337 av_log(s
, AV_LOG_ERROR
,
8338 "ISMV style TTML support with the 'dfxp' tag in "
8339 "non-ISMV formats is not officially supported. Add "
8340 "'-strict unofficial' if you want to use it.\n");
8341 return AVERROR_EXPERIMENTAL
;
8344 } else if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_DATA
) {
8345 track
->timescale
= st
->time_base
.den
;
8347 track
->timescale
= mov
->movie_timescale
;
8350 track
->height
= st
->codecpar
->height
;
8351 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8352 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8353 for video tracks, so if user-set, it isn't overwritten */
8354 if (mov
->mode
== MODE_ISM
&&
8355 (st
->codecpar
->codec_type
!= AVMEDIA_TYPE_VIDEO
||
8356 (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
&& !mov
->video_track_timescale
))) {
8357 track
->timescale
= 10000000;
8360 avpriv_set_pts_info(st
, 64, 1, track
->timescale
);
8362 if (mov
->encryption_scheme
== MOV_ENC_CENC_AES_CTR
) {
8363 ret
= ff_mov_cenc_init(&track
->cenc
, mov
->encryption_key
,
8364 (track
->par
->codec_id
== AV_CODEC_ID_H264
|| track
->par
->codec_id
== AV_CODEC_ID_HEVC
||
8365 track
->par
->codec_id
== AV_CODEC_ID_VVC
|| track
->par
->codec_id
== AV_CODEC_ID_AV1
),
8366 track
->par
->codec_id
, s
->flags
& AVFMT_FLAG_BITEXACT
);
8376 static int mov_write_header(AVFormatContext
*s
)
8378 AVIOContext
*pb
= s
->pb
;
8379 MOVMuxContext
*mov
= s
->priv_data
;
8380 int ret
, hint_track
= 0, tmcd_track
= 0, nb_tracks
= mov
->nb_streams
;
8382 if (mov
->mode
& (MODE_MP4
|MODE_MOV
|MODE_IPOD
) && s
->nb_chapters
)
8385 if (mov
->flags
& FF_MOV_FLAG_RTP_HINT
) {
8386 hint_track
= nb_tracks
;
8387 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
8388 if (rtp_hinting_needed(mov
->tracks
[i
].st
))
8393 if (mov
->nb_meta_tmcd
)
8394 tmcd_track
= nb_tracks
;
8396 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
8397 MOVTrack
*track
= &mov
->tracks
[i
];
8398 AVStream
*st
= track
->st
;
8400 /* copy extradata if it exists */
8401 if (st
->codecpar
->extradata_size
) {
8402 if (st
->codecpar
->codec_id
== AV_CODEC_ID_DVD_SUBTITLE
)
8403 mov_create_dvd_sub_decoder_specific_info(track
, st
);
8404 else if (!TAG_IS_AVCI(track
->tag
) && st
->codecpar
->codec_id
!= AV_CODEC_ID_DNXHD
) {
8405 track
->extradata_size
[track
->last_stsd_index
] = st
->codecpar
->extradata_size
;
8406 track
->extradata
[track
->last_stsd_index
] =
8407 av_malloc(track
->extradata_size
[track
->last_stsd_index
] + AV_INPUT_BUFFER_PADDING_SIZE
);
8408 if (!track
->extradata
[track
->last_stsd_index
]) {
8409 return AVERROR(ENOMEM
);
8411 memcpy(track
->extradata
[track
->last_stsd_index
],
8412 st
->codecpar
->extradata
, track
->extradata_size
[track
->last_stsd_index
]);
8413 memset(track
->extradata
[track
->last_stsd_index
] + track
->extradata_size
[track
->last_stsd_index
],
8414 0, AV_INPUT_BUFFER_PADDING_SIZE
);
8418 if (st
->codecpar
->codec_type
!= AVMEDIA_TYPE_AUDIO
||
8419 av_channel_layout_compare(&track
->par
->ch_layout
,
8420 &(AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
))
8423 for (int j
= 0; j
< mov
->nb_streams
; j
++) {
8424 AVStream
*stj
= mov
->tracks
[j
].st
;
8425 MOVTrack
*trackj
= &mov
->tracks
[j
];
8429 if (stj
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
&&
8430 (trackj
->par
->ch_layout
.nb_channels
!= 1 ||
8431 !av_channel_layout_compare(&trackj
->par
->ch_layout
,
8432 &(AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
))
8434 track
->mono_as_fc
= -1;
8436 if (stj
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
&&
8437 av_channel_layout_compare(&trackj
->par
->ch_layout
,
8438 &(AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
) &&
8439 trackj
->par
->ch_layout
.nb_channels
== 1 && track
->mono_as_fc
>= 0
8441 track
->mono_as_fc
++;
8443 if (stj
->codecpar
->codec_type
!= AVMEDIA_TYPE_AUDIO
||
8444 av_channel_layout_compare(&trackj
->par
->ch_layout
,
8445 &(AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
) ||
8446 trackj
->language
!= track
->language
||
8447 trackj
->tag
!= track
->tag
8450 track
->multichannel_as_mono
++;
8454 if (!(mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
) ||
8455 (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
)) {
8456 if ((ret
= mov_write_identification(pb
, s
)) < 0)
8460 if (mov
->reserved_moov_size
){
8461 mov
->reserved_header_pos
= avio_tell(pb
);
8462 if (mov
->reserved_moov_size
> 0)
8463 avio_skip(pb
, mov
->reserved_moov_size
);
8466 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
) {
8467 /* If no fragmentation options have been set, set a default. */
8468 if (!(mov
->flags
& (FF_MOV_FLAG_FRAG_KEYFRAME
|
8469 FF_MOV_FLAG_FRAG_CUSTOM
|
8470 FF_MOV_FLAG_FRAG_EVERY_FRAME
)) &&
8471 !mov
->max_fragment_duration
&& !mov
->max_fragment_size
)
8472 mov
->flags
|= FF_MOV_FLAG_FRAG_KEYFRAME
;
8473 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
) {
8474 avio_wb32(pb
, 8); // placeholder for extended size field (64 bit)
8475 ffio_wfourcc(pb
, mov
->mode
== MODE_MOV
? "wide" : "free");
8476 mov
->mdat_pos
= avio_tell(pb
);
8477 // The free/wide header that later will be converted into an
8478 // mdat, covering the initial moov and all the fragments.
8480 ffio_wfourcc(pb
, mov
->mode
== MODE_MOV
? "wide" : "free");
8481 // Write an ftyp atom, hidden in a free/wide. This is neither
8482 // exposed while the file is written, as fragmented, nor when the
8483 // file is finalized into non-fragmented form. However, this allows
8484 // accessing a pristine, sequential ftyp+moov init segment, even
8485 // after the file is finalized. It also allows dumping the whole
8486 // contents of the mdat box, to get the fragmented form of the
8488 if ((ret
= mov_write_identification(pb
, s
)) < 0)
8490 update_size(pb
, mov
->mdat_pos
);
8492 } else if (mov
->mode
!= MODE_AVIF
) {
8493 if (mov
->flags
& FF_MOV_FLAG_FASTSTART
)
8494 mov
->reserved_header_pos
= avio_tell(pb
);
8495 mov_write_mdat_tag(pb
, mov
);
8498 ff_parse_creation_time_metadata(s
, &mov
->time
, 1);
8500 mov
->time
+= 0x7C25B080; // 1970 based -> 1904 based
8502 if (mov
->chapter_track
)
8503 if ((ret
= mov_create_chapter_track(s
, mov
->chapter_track
)) < 0)
8506 if (mov
->flags
& FF_MOV_FLAG_RTP_HINT
) {
8507 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
8508 if (rtp_hinting_needed(mov
->tracks
[i
].st
)) {
8509 if ((ret
= ff_mov_init_hinting(s
, hint_track
, i
)) < 0)
8516 if (mov
->nb_meta_tmcd
) {
8517 const AVDictionaryEntry
*t
, *global_tcr
= av_dict_get(s
->metadata
,
8518 "timecode", NULL
, 0);
8519 /* Initialize the tmcd tracks */
8520 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
8521 AVStream
*st
= mov
->tracks
[i
].st
;
8524 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
8527 t
= av_dict_get(st
->metadata
, "timecode", NULL
, 0);
8530 if (mov_check_timecode_track(s
, &tc
, st
, t
->value
) < 0)
8532 if ((ret
= mov_create_timecode_track(s
, tmcd_track
, i
, tc
)) < 0)
8541 if (mov
->flags
& FF_MOV_FLAG_ISML
)
8542 mov_write_isml_manifest(pb
, mov
, s
);
8544 if (mov
->flags
& FF_MOV_FLAG_EMPTY_MOOV
&&
8545 !(mov
->flags
& FF_MOV_FLAG_DELAY_MOOV
)) {
8546 if ((ret
= mov_write_moov_tag(pb
, mov
, s
)) < 0)
8548 mov
->moov_written
= 1;
8549 if (mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
)
8550 mov
->reserved_header_pos
= avio_tell(pb
);
8556 static int get_moov_size(AVFormatContext
*s
)
8559 AVIOContext
*moov_buf
;
8560 MOVMuxContext
*mov
= s
->priv_data
;
8562 if ((ret
= ffio_open_null_buf(&moov_buf
)) < 0)
8564 if ((ret
= mov_write_moov_tag(moov_buf
, mov
, s
)) < 0)
8566 return ffio_close_null_buf(moov_buf
);
8569 static int get_sidx_size(AVFormatContext
*s
)
8573 MOVMuxContext
*mov
= s
->priv_data
;
8575 if ((ret
= ffio_open_null_buf(&buf
)) < 0)
8577 mov_write_sidx_tags(buf
, mov
, -1, 0);
8578 return ffio_close_null_buf(buf
);
8582 * This function gets the moov size if moved to the top of the file: the chunk
8583 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8584 * entries) when the moov is moved to the beginning, so the size of the moov
8585 * would change. It also updates the chunk offset tables.
8587 static int compute_moov_size(AVFormatContext
*s
)
8589 int i
, moov_size
, moov_size2
;
8590 MOVMuxContext
*mov
= s
->priv_data
;
8592 moov_size
= get_moov_size(s
);
8596 for (i
= 0; i
< mov
->nb_tracks
; i
++)
8597 mov
->tracks
[i
].data_offset
+= moov_size
;
8599 moov_size2
= get_moov_size(s
);
8603 /* if the size changed, we just switched from stco to co64 and need to
8604 * update the offsets */
8605 if (moov_size2
!= moov_size
)
8606 for (i
= 0; i
< mov
->nb_tracks
; i
++)
8607 mov
->tracks
[i
].data_offset
+= moov_size2
- moov_size
;
8612 static int compute_sidx_size(AVFormatContext
*s
)
8615 MOVMuxContext
*mov
= s
->priv_data
;
8617 sidx_size
= get_sidx_size(s
);
8621 for (i
= 0; i
< mov
->nb_tracks
; i
++)
8622 mov
->tracks
[i
].data_offset
+= sidx_size
;
8627 static int shift_data(AVFormatContext
*s
)
8630 MOVMuxContext
*mov
= s
->priv_data
;
8632 if (mov
->flags
& FF_MOV_FLAG_FRAGMENT
)
8633 moov_size
= compute_sidx_size(s
);
8635 moov_size
= compute_moov_size(s
);
8639 return ff_format_shift_data(s
, mov
->reserved_header_pos
, moov_size
);
8642 static void mov_write_mdat_size(AVFormatContext
*s
)
8644 MOVMuxContext
*mov
= s
->priv_data
;
8645 AVIOContext
*pb
= s
->pb
;
8647 /* Write size of mdat tag */
8648 if (mov
->mdat_size
+ 8 <= UINT32_MAX
) {
8649 avio_seek(pb
, mov
->mdat_pos
, SEEK_SET
);
8650 avio_wb32(pb
, mov
->mdat_size
+ 8);
8651 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
)
8652 ffio_wfourcc(pb
, "mdat"); // overwrite the original free/wide into a mdat
8654 /* overwrite 'wide' placeholder atom */
8655 avio_seek(pb
, mov
->mdat_pos
- 8, SEEK_SET
);
8656 /* special value: real atom size will be 64 bit value after
8659 ffio_wfourcc(pb
, "mdat");
8660 avio_wb64(pb
, mov
->mdat_size
+ 16);
8664 static int mov_write_trailer(AVFormatContext
*s
)
8666 MOVMuxContext
*mov
= s
->priv_data
;
8667 AVIOContext
*pb
= s
->pb
;
8673 * Before actually writing the trailer, make sure that there are no
8674 * dangling subtitles, that need a terminating sample.
8676 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
8677 MOVTrack
*trk
= &mov
->tracks
[i
];
8678 if (trk
->par
->codec_id
== AV_CODEC_ID_MOV_TEXT
&&
8679 !trk
->last_sample_is_subtitle_end
) {
8680 mov_write_subtitle_end_packet(s
, i
, trk
->track_duration
);
8681 trk
->last_sample_is_subtitle_end
= 1;
8685 // Check if we have any tracks that require squashing.
8686 // In that case, we'll have to write the packet here.
8687 if ((res
= mov_write_squashed_packets(s
)) < 0)
8690 // If there were no chapters when the header was written, but there
8691 // are chapters now, write them in the trailer. This only works
8692 // when we are not doing fragments.
8693 if (!mov
->chapter_track
&& !(mov
->flags
& FF_MOV_FLAG_FRAGMENT
)) {
8694 if (mov
->mode
& (MODE_MP4
|MODE_MOV
|MODE_IPOD
) && s
->nb_chapters
) {
8695 mov
->chapter_track
= mov
->nb_tracks
++;
8696 if ((res
= mov_create_chapter_track(s
, mov
->chapter_track
)) < 0)
8701 if (!(mov
->flags
& FF_MOV_FLAG_FRAGMENT
) ||
8702 mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
) {
8703 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
) {
8704 mov_auto_flush_fragment(s
, 1);
8705 mov
->mdat_size
= avio_tell(pb
) - mov
->mdat_pos
- 8;
8706 for (i
= 0; i
< mov
->nb_tracks
; i
++) {
8707 MOVTrack
*track
= &mov
->tracks
[i
];
8708 track
->data_offset
= 0;
8709 av_free(track
->cluster
);
8710 track
->cluster
= track
->cluster_written
;
8711 track
->entry
= track
->entry_written
;
8712 track
->cluster_written
= NULL
;
8713 track
->entry_written
= 0;
8714 track
->chunkCount
= 0; // Force build_chunks to rebuild the list of chunks
8716 // Clear the empty_moov flag, as we do want the moov to include
8717 // all the samples at this point.
8718 mov
->flags
&= ~FF_MOV_FLAG_EMPTY_MOOV
;
8721 moov_pos
= avio_tell(pb
);
8723 if (!(mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
))
8724 mov_write_mdat_size(s
);
8726 avio_seek(pb
, mov
->reserved_moov_size
> 0 ? mov
->reserved_header_pos
: moov_pos
, SEEK_SET
);
8728 if (mov
->flags
& FF_MOV_FLAG_FASTSTART
) {
8729 av_log(s
, AV_LOG_INFO
, "Starting second pass: moving the moov atom to the beginning of the file\n");
8730 res
= shift_data(s
);
8733 avio_seek(pb
, mov
->reserved_header_pos
, SEEK_SET
);
8734 if ((res
= mov_write_moov_tag(pb
, mov
, s
)) < 0)
8736 } else if (mov
->reserved_moov_size
> 0) {
8738 if ((res
= mov_write_moov_tag(pb
, mov
, s
)) < 0)
8740 size
= mov
->reserved_moov_size
- (avio_tell(pb
) - mov
->reserved_header_pos
);
8742 av_log(s
, AV_LOG_ERROR
, "reserved_moov_size is too small, needed %"PRId64
" additional\n", 8-size
);
8743 return AVERROR(EINVAL
);
8745 avio_wb32(pb
, size
);
8746 ffio_wfourcc(pb
, "free");
8747 ffio_fill(pb
, 0, size
- 8);
8748 avio_seek(pb
, moov_pos
, SEEK_SET
);
8750 if ((res
= mov_write_moov_tag(pb
, mov
, s
)) < 0)
8754 if (mov
->flags
& FF_MOV_FLAG_HYBRID_FRAGMENTED
) {
8755 // With hybrid fragmentation, only write the mdat size (hiding
8756 // the original moov and all the fragments within the mdat)
8757 // after we've successfully written the complete moov, to avoid
8758 // risk for an unreadable file if writing the final moov fails.
8759 mov_write_mdat_size(s
);
8764 mov_auto_flush_fragment(s
, 1);
8765 for (i
= 0; i
< mov
->nb_tracks
; i
++)
8766 mov
->tracks
[i
].data_offset
= 0;
8767 if (mov
->flags
& FF_MOV_FLAG_GLOBAL_SIDX
) {
8769 av_log(s
, AV_LOG_INFO
, "Starting second pass: inserting sidx atoms\n");
8770 res
= shift_data(s
);
8773 end
= avio_tell(pb
);
8774 avio_seek(pb
, mov
->reserved_header_pos
, SEEK_SET
);
8775 mov_write_sidx_tags(pb
, mov
, -1, 0);
8776 avio_seek(pb
, end
, SEEK_SET
);
8778 if (!(mov
->flags
& FF_MOV_FLAG_SKIP_TRAILER
)) {
8779 avio_write_marker(s
->pb
, AV_NOPTS_VALUE
, AVIO_DATA_MARKER_TRAILER
);
8780 res
= mov_write_mfra_tag(pb
, mov
);
8789 static int mov_check_bitstream(AVFormatContext
*s
, AVStream
*st
,
8790 const AVPacket
*pkt
)
8794 if (st
->codecpar
->codec_id
== AV_CODEC_ID_AAC
) {
8795 if (pkt
->size
> 2 && (AV_RB16(pkt
->data
) & 0xfff0) == 0xfff0)
8796 ret
= ff_stream_add_bitstream_filter(st
, "aac_adtstoasc", NULL
);
8797 } else if (st
->codecpar
->codec_id
== AV_CODEC_ID_VP9
) {
8798 ret
= ff_stream_add_bitstream_filter(st
, "vp9_superframe", NULL
);
8804 #if CONFIG_AVIF_MUXER
8805 static int avif_write_trailer(AVFormatContext
*s
)
8807 AVIOContext
*pb
= s
->pb
;
8808 MOVMuxContext
*mov
= s
->priv_data
;
8809 int64_t pos_backup
, extent_offsets
[2];
8811 int buf_size
, moov_size
;
8813 if (mov
->moov_written
) return 0;
8815 mov
->is_animated_avif
= s
->streams
[0]->nb_frames
> 1;
8816 if (mov
->is_animated_avif
&& mov
->nb_streams
> 1) {
8817 // For animated avif with alpha channel, we need to write a tref tag
8818 // with type "auxl".
8819 mov
->tracks
[1].tref_tag
= MKTAG('a', 'u', 'x', 'l');
8820 mov
->tracks
[1].tref_id
= 1;
8822 mov_write_identification(pb
, s
);
8823 mov_write_meta_tag(pb
, mov
, s
);
8825 moov_size
= get_moov_size(s
);
8826 for (int i
= 0; i
< mov
->nb_tracks
; i
++)
8827 mov
->tracks
[i
].data_offset
= avio_tell(pb
) + moov_size
+ 8;
8829 if (mov
->is_animated_avif
) {
8831 if ((ret
= mov_write_moov_tag(pb
, mov
, s
)) < 0)
8835 buf_size
= avio_get_dyn_buf(mov
->mdat_buf
, &buf
);
8836 avio_wb32(pb
, buf_size
+ 8);
8837 ffio_wfourcc(pb
, "mdat");
8839 // The offset for the YUV planes is the starting position of mdat.
8840 extent_offsets
[0] = avio_tell(pb
);
8841 // The offset for alpha plane is YUV offset + YUV size.
8842 extent_offsets
[1] = extent_offsets
[0] + mov
->avif_extent_length
[0];
8844 avio_write(pb
, buf
, buf_size
);
8846 // write extent offsets.
8847 pos_backup
= avio_tell(pb
);
8848 for (int i
= 0; i
< mov
->nb_streams
; i
++) {
8849 if (extent_offsets
[i
] != (uint32_t)extent_offsets
[i
]) {
8850 av_log(s
, AV_LOG_ERROR
, "extent offset does not fit in 32 bits\n");
8851 return AVERROR_INVALIDDATA
;
8853 avio_seek(pb
, mov
->avif_extent_pos
[i
], SEEK_SET
);
8854 avio_wb32(pb
, extent_offsets
[i
]); /* rewrite offset */
8856 avio_seek(pb
, pos_backup
, SEEK_SET
);
8862 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8863 static const AVCodecTag codec_3gp_tags
[] = {
8864 { AV_CODEC_ID_H263
, MKTAG('s','2','6','3') },
8865 { AV_CODEC_ID_H264
, MKTAG('a','v','c','1') },
8866 { AV_CODEC_ID_MPEG4
, MKTAG('m','p','4','v') },
8867 { AV_CODEC_ID_AAC
, MKTAG('m','p','4','a') },
8868 { AV_CODEC_ID_AMR_NB
, MKTAG('s','a','m','r') },
8869 { AV_CODEC_ID_AMR_WB
, MKTAG('s','a','w','b') },
8870 { AV_CODEC_ID_MOV_TEXT
, MKTAG('t','x','3','g') },
8871 { AV_CODEC_ID_NONE
, 0 },
8873 static const AVCodecTag
*const codec_3gp_tags_list
[] = { codec_3gp_tags
, NULL
};
8876 static const AVCodecTag codec_mp4_tags
[] = {
8877 { AV_CODEC_ID_MPEG4
, MKTAG('m', 'p', '4', 'v') },
8878 { AV_CODEC_ID_H264
, MKTAG('a', 'v', 'c', '1') },
8879 { AV_CODEC_ID_H264
, MKTAG('a', 'v', 'c', '3') },
8880 { AV_CODEC_ID_HEVC
, MKTAG('h', 'e', 'v', '1') },
8881 { AV_CODEC_ID_HEVC
, MKTAG('h', 'v', 'c', '1') },
8882 { AV_CODEC_ID_HEVC
, MKTAG('d', 'v', 'h', '1') },
8883 { AV_CODEC_ID_VVC
, MKTAG('v', 'v', 'c', '1') },
8884 { AV_CODEC_ID_VVC
, MKTAG('v', 'v', 'i', '1') },
8885 { AV_CODEC_ID_EVC
, MKTAG('e', 'v', 'c', '1') },
8886 { AV_CODEC_ID_APV
, MKTAG('a', 'p', 'v', '1') },
8887 { AV_CODEC_ID_MPEG2VIDEO
, MKTAG('m', 'p', '4', 'v') },
8888 { AV_CODEC_ID_MPEG1VIDEO
, MKTAG('m', 'p', '4', 'v') },
8889 { AV_CODEC_ID_MJPEG
, MKTAG('m', 'p', '4', 'v') },
8890 { AV_CODEC_ID_PNG
, MKTAG('m', 'p', '4', 'v') },
8891 { AV_CODEC_ID_JPEG2000
, MKTAG('m', 'p', '4', 'v') },
8892 { AV_CODEC_ID_VC1
, MKTAG('v', 'c', '-', '1') },
8893 { AV_CODEC_ID_DIRAC
, MKTAG('d', 'r', 'a', 'c') },
8894 { AV_CODEC_ID_TSCC2
, MKTAG('m', 'p', '4', 'v') },
8895 { AV_CODEC_ID_VP9
, MKTAG('v', 'p', '0', '9') },
8896 { AV_CODEC_ID_AV1
, MKTAG('a', 'v', '0', '1') },
8897 { AV_CODEC_ID_AAC
, MKTAG('m', 'p', '4', 'a') },
8898 { AV_CODEC_ID_ALAC
, MKTAG('a', 'l', 'a', 'c') },
8899 { AV_CODEC_ID_MP4ALS
, MKTAG('m', 'p', '4', 'a') },
8900 { AV_CODEC_ID_MP3
, MKTAG('m', 'p', '4', 'a') },
8901 { AV_CODEC_ID_MP2
, MKTAG('m', 'p', '4', 'a') },
8902 { AV_CODEC_ID_AC3
, MKTAG('a', 'c', '-', '3') },
8903 { AV_CODEC_ID_EAC3
, MKTAG('e', 'c', '-', '3') },
8904 { AV_CODEC_ID_DTS
, MKTAG('m', 'p', '4', 'a') },
8905 { AV_CODEC_ID_TRUEHD
, MKTAG('m', 'l', 'p', 'a') },
8906 { AV_CODEC_ID_FLAC
, MKTAG('f', 'L', 'a', 'C') },
8907 { AV_CODEC_ID_OPUS
, MKTAG('O', 'p', 'u', 's') },
8908 { AV_CODEC_ID_VORBIS
, MKTAG('m', 'p', '4', 'a') },
8909 { AV_CODEC_ID_QCELP
, MKTAG('m', 'p', '4', 'a') },
8910 { AV_CODEC_ID_EVRC
, MKTAG('m', 'p', '4', 'a') },
8911 { AV_CODEC_ID_DVD_SUBTITLE
, MKTAG('m', 'p', '4', 's') },
8912 { AV_CODEC_ID_MOV_TEXT
, MKTAG('t', 'x', '3', 'g') },
8913 { AV_CODEC_ID_BIN_DATA
, MKTAG('g', 'p', 'm', 'd') },
8914 { AV_CODEC_ID_MPEGH_3D_AUDIO
, MKTAG('m', 'h', 'm', '1') },
8915 { AV_CODEC_ID_TTML
, MOV_MP4_TTML_TAG
},
8916 { AV_CODEC_ID_TTML
, MOV_ISMV_TTML_TAG
},
8917 { AV_CODEC_ID_FFV1
, MKTAG('F', 'F', 'V', '1') },
8919 /* ISO/IEC 23003-5 integer formats */
8920 { AV_CODEC_ID_PCM_S16BE
, MOV_MP4_IPCM_TAG
},
8921 { AV_CODEC_ID_PCM_S16LE
, MOV_MP4_IPCM_TAG
},
8922 { AV_CODEC_ID_PCM_S24BE
, MOV_MP4_IPCM_TAG
},
8923 { AV_CODEC_ID_PCM_S24LE
, MOV_MP4_IPCM_TAG
},
8924 { AV_CODEC_ID_PCM_S32BE
, MOV_MP4_IPCM_TAG
},
8925 { AV_CODEC_ID_PCM_S32LE
, MOV_MP4_IPCM_TAG
},
8926 /* ISO/IEC 23003-5 floating-point formats */
8927 { AV_CODEC_ID_PCM_F32BE
, MOV_MP4_FPCM_TAG
},
8928 { AV_CODEC_ID_PCM_F32LE
, MOV_MP4_FPCM_TAG
},
8929 { AV_CODEC_ID_PCM_F64BE
, MOV_MP4_FPCM_TAG
},
8930 { AV_CODEC_ID_PCM_F64LE
, MOV_MP4_FPCM_TAG
},
8932 { AV_CODEC_ID_AVS3
, MKTAG('a', 'v', 's', '3') },
8934 { AV_CODEC_ID_NONE
, 0 },
8936 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8937 static const AVCodecTag
*const mp4_codec_tags_list
[] = { codec_mp4_tags
, NULL
};
8940 static const AVCodecTag codec_ism_tags
[] = {
8941 { AV_CODEC_ID_WMAPRO
, MKTAG('w', 'm', 'a', ' ') },
8942 { AV_CODEC_ID_TTML
, MOV_ISMV_TTML_TAG
},
8943 { AV_CODEC_ID_NONE
, 0 },
8946 static const AVCodecTag codec_ipod_tags
[] = {
8947 { AV_CODEC_ID_H264
, MKTAG('a','v','c','1') },
8948 { AV_CODEC_ID_MPEG4
, MKTAG('m','p','4','v') },
8949 { AV_CODEC_ID_AAC
, MKTAG('m','p','4','a') },
8950 { AV_CODEC_ID_ALAC
, MKTAG('a','l','a','c') },
8951 { AV_CODEC_ID_AC3
, MKTAG('a','c','-','3') },
8952 { AV_CODEC_ID_MOV_TEXT
, MKTAG('t','x','3','g') },
8953 { AV_CODEC_ID_MOV_TEXT
, MKTAG('t','e','x','t') },
8954 { AV_CODEC_ID_NONE
, 0 },
8957 static const AVCodecTag codec_f4v_tags
[] = {
8958 { AV_CODEC_ID_MP3
, MKTAG('.','m','p','3') },
8959 { AV_CODEC_ID_AAC
, MKTAG('m','p','4','a') },
8960 { AV_CODEC_ID_H264
, MKTAG('a','v','c','1') },
8961 { AV_CODEC_ID_VP6A
, MKTAG('V','P','6','A') },
8962 { AV_CODEC_ID_VP6F
, MKTAG('V','P','6','F') },
8963 { AV_CODEC_ID_NONE
, 0 },
8966 #if CONFIG_AVIF_MUXER
8968 static const AVOption avif_options
[] = {
8969 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext
, movie_timescale
), AV_OPT_TYPE_INT
, {.i64
= MOV_TIMESCALE
}, 1, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
},
8970 { "loop", "Number of times to loop animated AVIF: 0 - infinite loop", offsetof(MOVMuxContext
, avif_loop_count
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, AV_OPT_FLAG_ENCODING_PARAM
, .unit
= 0 },
8973 static const AVCodecTag codec_avif_tags
[] = {
8974 { AV_CODEC_ID_AV1
, MKTAG('a','v','0','1') },
8975 { AV_CODEC_ID_NONE
, 0 },
8977 static const AVCodecTag
*const codec_avif_tags_list
[] = { codec_avif_tags
, NULL
};
8979 static const AVClass mov_avif_muxer_class
= {
8980 .class_name
= "avif muxer",
8981 .item_name
= av_default_item_name
,
8982 .option
= avif_options
,
8983 .version
= LIBAVUTIL_VERSION_INT
,
8987 #if CONFIG_MOV_MUXER
8988 const FFOutputFormat ff_mov_muxer
= {
8990 .p
.long_name
= NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8991 .p
.extensions
= "mov",
8992 .priv_data_size
= sizeof(MOVMuxContext
),
8993 .p
.audio_codec
= AV_CODEC_ID_AAC
,
8994 .p
.video_codec
= CONFIG_LIBX264_ENCODER
?
8995 AV_CODEC_ID_H264
: AV_CODEC_ID_MPEG4
,
8997 .write_header
= mov_write_header
,
8998 .write_packet
= mov_write_packet
,
8999 .write_trailer
= mov_write_trailer
,
9001 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
| AVFMT_VARIABLE_FPS
,
9002 .p
.codec_tag
= (const AVCodecTag
* const []){
9003 ff_codec_movvideo_tags
, ff_codec_movaudio_tags
, ff_codec_movsubtitle_tags
, 0
9005 .check_bitstream
= mov_check_bitstream
,
9006 .p
.priv_class
= &mov_isobmff_muxer_class
,
9007 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9010 #if CONFIG_TGP_MUXER
9011 const FFOutputFormat ff_tgp_muxer
= {
9013 .p
.long_name
= NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9014 .p
.extensions
= "3gp",
9015 .priv_data_size
= sizeof(MOVMuxContext
),
9016 .p
.audio_codec
= AV_CODEC_ID_AMR_NB
,
9017 .p
.video_codec
= AV_CODEC_ID_H263
,
9019 .write_header
= mov_write_header
,
9020 .write_packet
= mov_write_packet
,
9021 .write_trailer
= mov_write_trailer
,
9023 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
,
9024 .p
.codec_tag
= codec_3gp_tags_list
,
9025 .check_bitstream
= mov_check_bitstream
,
9026 .p
.priv_class
= &mov_isobmff_muxer_class
,
9027 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9030 #if CONFIG_MP4_MUXER
9031 const FFOutputFormat ff_mp4_muxer
= {
9033 .p
.long_name
= NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9034 .p
.mime_type
= "video/mp4",
9035 .p
.extensions
= "mp4",
9036 .priv_data_size
= sizeof(MOVMuxContext
),
9037 .p
.audio_codec
= AV_CODEC_ID_AAC
,
9038 .p
.video_codec
= CONFIG_LIBX264_ENCODER
?
9039 AV_CODEC_ID_H264
: AV_CODEC_ID_MPEG4
,
9041 .write_header
= mov_write_header
,
9042 .write_packet
= mov_write_packet
,
9043 .write_trailer
= mov_write_trailer
,
9045 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
| AVFMT_VARIABLE_FPS
,
9046 .p
.codec_tag
= mp4_codec_tags_list
,
9047 .check_bitstream
= mov_check_bitstream
,
9048 .p
.priv_class
= &mov_isobmff_muxer_class
,
9049 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9052 #if CONFIG_PSP_MUXER
9053 const FFOutputFormat ff_psp_muxer
= {
9055 .p
.long_name
= NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9056 .p
.extensions
= "mp4,psp",
9057 .priv_data_size
= sizeof(MOVMuxContext
),
9058 .p
.audio_codec
= AV_CODEC_ID_AAC
,
9059 .p
.video_codec
= CONFIG_LIBX264_ENCODER
?
9060 AV_CODEC_ID_H264
: AV_CODEC_ID_MPEG4
,
9062 .write_header
= mov_write_header
,
9063 .write_packet
= mov_write_packet
,
9064 .write_trailer
= mov_write_trailer
,
9066 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
,
9067 .p
.codec_tag
= mp4_codec_tags_list
,
9068 .check_bitstream
= mov_check_bitstream
,
9069 .p
.priv_class
= &mov_isobmff_muxer_class
,
9070 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9073 #if CONFIG_TG2_MUXER
9074 const FFOutputFormat ff_tg2_muxer
= {
9076 .p
.long_name
= NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9077 .p
.extensions
= "3g2",
9078 .priv_data_size
= sizeof(MOVMuxContext
),
9079 .p
.audio_codec
= AV_CODEC_ID_AMR_NB
,
9080 .p
.video_codec
= AV_CODEC_ID_H263
,
9082 .write_header
= mov_write_header
,
9083 .write_packet
= mov_write_packet
,
9084 .write_trailer
= mov_write_trailer
,
9086 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
,
9087 .p
.codec_tag
= codec_3gp_tags_list
,
9088 .check_bitstream
= mov_check_bitstream
,
9089 .p
.priv_class
= &mov_isobmff_muxer_class
,
9090 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9093 #if CONFIG_IPOD_MUXER
9094 const FFOutputFormat ff_ipod_muxer
= {
9096 .p
.long_name
= NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9097 .p
.mime_type
= "video/mp4",
9098 .p
.extensions
= "m4v,m4a,m4b",
9099 .priv_data_size
= sizeof(MOVMuxContext
),
9100 .p
.audio_codec
= AV_CODEC_ID_AAC
,
9101 .p
.video_codec
= AV_CODEC_ID_H264
,
9103 .write_header
= mov_write_header
,
9104 .write_packet
= mov_write_packet
,
9105 .write_trailer
= mov_write_trailer
,
9107 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
,
9108 .p
.codec_tag
= (const AVCodecTag
* const []){ codec_ipod_tags
, 0 },
9109 .check_bitstream
= mov_check_bitstream
,
9110 .p
.priv_class
= &mov_isobmff_muxer_class
,
9111 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9114 #if CONFIG_ISMV_MUXER
9115 const FFOutputFormat ff_ismv_muxer
= {
9117 .p
.long_name
= NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9118 .p
.mime_type
= "video/mp4",
9119 .p
.extensions
= "ismv,isma",
9120 .priv_data_size
= sizeof(MOVMuxContext
),
9121 .p
.audio_codec
= AV_CODEC_ID_AAC
,
9122 .p
.video_codec
= AV_CODEC_ID_H264
,
9124 .write_header
= mov_write_header
,
9125 .write_packet
= mov_write_packet
,
9126 .write_trailer
= mov_write_trailer
,
9128 .p
.flags
= AVFMT_GLOBALHEADER
| AVFMT_TS_NEGATIVE
,
9129 .p
.codec_tag
= (const AVCodecTag
* const []){
9130 codec_mp4_tags
, codec_ism_tags
, 0 },
9131 .check_bitstream
= mov_check_bitstream
,
9132 .p
.priv_class
= &mov_isobmff_muxer_class
,
9133 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9136 #if CONFIG_F4V_MUXER
9137 const FFOutputFormat ff_f4v_muxer
= {
9139 .p
.long_name
= NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9140 .p
.mime_type
= "application/f4v",
9141 .p
.extensions
= "f4v",
9142 .priv_data_size
= sizeof(MOVMuxContext
),
9143 .p
.audio_codec
= AV_CODEC_ID_AAC
,
9144 .p
.video_codec
= AV_CODEC_ID_H264
,
9146 .write_header
= mov_write_header
,
9147 .write_packet
= mov_write_packet
,
9148 .write_trailer
= mov_write_trailer
,
9150 .p
.flags
= AVFMT_GLOBALHEADER
,
9151 .p
.codec_tag
= (const AVCodecTag
* const []){ codec_f4v_tags
, 0 },
9152 .check_bitstream
= mov_check_bitstream
,
9153 .p
.priv_class
= &mov_isobmff_muxer_class
,
9154 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
9157 #if CONFIG_AVIF_MUXER
9158 const FFOutputFormat ff_avif_muxer
= {
9160 .p
.long_name
= NULL_IF_CONFIG_SMALL("AVIF"),
9161 .p
.mime_type
= "image/avif",
9162 .p
.extensions
= "avif",
9163 .priv_data_size
= sizeof(MOVMuxContext
),
9164 .p
.video_codec
= AV_CODEC_ID_AV1
,
9166 .write_header
= mov_write_header
,
9167 .write_packet
= mov_write_packet
,
9168 .write_trailer
= avif_write_trailer
,
9170 .p
.flags
= AVFMT_GLOBALHEADER
,
9171 .p
.codec_tag
= codec_avif_tags_list
,
9172 .p
.priv_class
= &mov_avif_muxer_class
,
9173 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,