FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2025-07-02 09:19:21
Exec Total Coverage
Lines: 3627 5400 67.2%
Functions: 173 226 76.5%
Branches: 2149 3717 57.8%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
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>
6 *
7 * This file is part of FFmpeg.
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "libavcodec/ac3_parser_internal.h"
41 #include "libavcodec/dnxhddata.h"
42 #include "libavcodec/flac.h"
43 #include "libavcodec/get_bits.h"
44
45 #include "libavcodec/internal.h"
46 #include "libavcodec/put_bits.h"
47 #include "libavcodec/vc1_common.h"
48 #include "libavcodec/raw.h"
49 #include "internal.h"
50 #include "libavutil/avstring.h"
51 #include "libavutil/channel_layout.h"
52 #include "libavutil/csp.h"
53 #include "libavutil/intfloat.h"
54 #include "libavutil/mathematics.h"
55 #include "libavutil/libm.h"
56 #include "libavutil/mem.h"
57 #include "libavutil/opt.h"
58 #include "libavutil/dict.h"
59 #include "libavutil/pixdesc.h"
60 #include "libavutil/stereo3d.h"
61 #include "libavutil/timecode.h"
62 #include "libavutil/dovi_meta.h"
63 #include "libavutil/uuid.h"
64 #include "hevc.h"
65 #include "rtpenc.h"
66 #include "nal.h"
67 #include "mov_chan.h"
68 #include "movenc_ttml.h"
69 #include "mux.h"
70 #include "rawutils.h"
71 #include "ttmlenc.h"
72 #include "version.h"
73 #include "vpcc.h"
74 #include "vvc.h"
75
76 static const AVOption options[] = {
77 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
78 { "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},
79 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
80 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "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 },
82 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
83 { "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 },
84 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
85 { "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},
86 { "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},
87 { "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},
88 { "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},
89 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
90 { "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" },
91 { "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" },
92 { "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" },
93 { "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" },
94 { "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" },
95 { "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" },
96 { "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" },
97 { "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" },
98 { "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" },
99 { "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" },
100 { "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" },
101 { "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" },
102 { "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" },
103 { "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 },
104 { "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" },
105 { "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" },
106 { "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" },
107 { "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" },
108 { "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" },
109 { "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" },
110 { "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" },
111 { "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" },
112 { "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" },
113 { "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" },
114 { "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" },
115 { "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},
116 { "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},
117 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
118 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
119 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
120 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
121 { "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},
122 { "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},
123 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "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"},
125 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
128 { NULL },
129 };
130
131 static const AVClass mov_isobmff_muxer_class = {
132 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
133 .item_name = av_default_item_name,
134 .option = options,
135 .version = LIBAVUTIL_VERSION_INT,
136 };
137
138 static int get_moov_size(AVFormatContext *s);
139 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
140
141 26 static int utf8len(const uint8_t *b)
142 {
143 26 int len = 0;
144 int val;
145
2/2
✓ Branch 0 taken 523 times.
✓ Branch 1 taken 26 times.
549 while (*b) {
146
3/8
✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 523 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 523 times.
523 GET_UTF8(val, *b++, return -1;)
147 523 len++;
148 }
149 26 return len;
150 }
151
152 //FIXME support 64 bit variant with wide placeholders
153 6304 static int64_t update_size(AVIOContext *pb, int64_t pos)
154 {
155 6304 int64_t curpos = avio_tell(pb);
156 6304 avio_seek(pb, pos, SEEK_SET);
157 6304 avio_wb32(pb, curpos - pos); /* rewrite size */
158 6304 avio_seek(pb, curpos, SEEK_SET);
159
160 6304 return curpos - pos;
161 }
162
163 339 static int co64_required(const MOVTrack *track)
164 {
165
3/4
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 247 times.
339 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
166 return 1;
167 339 return 0;
168 }
169
170 19370 static int is_cover_image(const AVStream *st)
171 {
172 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
173 * is encoded as sparse video track */
174
3/4
✓ Branch 0 taken 19370 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 19358 times.
19370 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
175 }
176
177 6 static int rtp_hinting_needed(const AVStream *st)
178 {
179 /* Add hint tracks for each real audio and video stream */
180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
181 return 0;
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
183
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
184 }
185
186 /* Chunk offset atom */
187 339 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
188 {
189 int i;
190 339 int mode64 = co64_required(track); // use 32 bit size variant if possible
191 339 int64_t pos = avio_tell(pb);
192 339 avio_wb32(pb, 0); /* size */
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
339 if (mode64)
194 ffio_wfourcc(pb, "co64");
195 else
196 339 ffio_wfourcc(pb, "stco");
197 339 avio_wb32(pb, 0); /* version & flags */
198 339 avio_wb32(pb, track->chunkCount); /* entry count */
199
2/2
✓ Branch 0 taken 13671 times.
✓ Branch 1 taken 339 times.
14010 for (i = 0; i < track->entry; i++) {
200
2/2
✓ Branch 0 taken 10567 times.
✓ Branch 1 taken 3104 times.
13671 if (!track->cluster[i].chunkNum)
201 10567 continue;
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3104 times.
3104 if (mode64 == 1)
203 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
204 else
205 3104 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
206 }
207 339 return update_size(pb, pos);
208 }
209
210 /* Sample size atom */
211 339 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
212 {
213 339 int equalChunks = 1;
214 339 int i, j, entries = 0, tst = -1, oldtst = -1;
215
216 339 int64_t pos = avio_tell(pb);
217 339 avio_wb32(pb, 0); /* size */
218 339 ffio_wfourcc(pb, "stsz");
219 339 avio_wb32(pb, 0); /* version & flags */
220
221
2/2
✓ Branch 0 taken 13671 times.
✓ Branch 1 taken 339 times.
14010 for (i = 0; i < track->entry; i++) {
222 13671 tst = track->cluster[i].size / track->cluster[i].entries;
223
4/4
✓ Branch 0 taken 13424 times.
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 8730 times.
✓ Branch 3 taken 4694 times.
13671 if (oldtst != -1 && tst != oldtst)
224 8730 equalChunks = 0;
225 13671 oldtst = tst;
226 13671 entries += track->cluster[i].entries;
227 }
228
4/4
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 92 times.
452 if (equalChunks && track->entry) {
229
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
230 113 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
231 113 avio_wb32(pb, sSize); // sample size
232 113 avio_wb32(pb, entries); // sample count
233 } else {
234 226 avio_wb32(pb, 0); // sample size
235 226 avio_wb32(pb, entries); // sample count
236
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 226 times.
10118 for (i = 0; i < track->entry; i++) {
237
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 9892 times.
19784 for (j = 0; j < track->cluster[i].entries; j++) {
238 9892 avio_wb32(pb, track->cluster[i].size /
239 9892 track->cluster[i].entries);
240 }
241 }
242 }
243 339 return update_size(pb, pos);
244 }
245
246 /* Sample to chunk atom */
247 339 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
248 {
249 339 int index = 0, oldval = -1, i;
250 int64_t entryPos, curpos;
251
252 339 int64_t pos = avio_tell(pb);
253 339 avio_wb32(pb, 0); /* size */
254 339 ffio_wfourcc(pb, "stsc");
255 339 avio_wb32(pb, 0); // version & flags
256 339 entryPos = avio_tell(pb);
257 339 avio_wb32(pb, track->chunkCount); // entry count
258
2/2
✓ Branch 0 taken 13671 times.
✓ Branch 1 taken 339 times.
14010 for (i = 0; i < track->entry; i++) {
259
4/4
✓ Branch 0 taken 11389 times.
✓ Branch 1 taken 2282 times.
✓ Branch 2 taken 822 times.
✓ Branch 3 taken 10567 times.
13671 if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
260 822 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
261 822 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
262 822 avio_wb32(pb, 0x1); // sample description index
263 822 oldval = track->cluster[i].samples_in_chunk;
264 822 index++;
265 }
266 }
267 339 curpos = avio_tell(pb);
268 339 avio_seek(pb, entryPos, SEEK_SET);
269 339 avio_wb32(pb, index); // rewrite size
270 339 avio_seek(pb, curpos, SEEK_SET);
271
272 339 return update_size(pb, pos);
273 }
274
275 /* Sync sample atom */
276 58 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
277 {
278 int64_t curpos, entryPos;
279 58 int i, index = 0;
280 58 int64_t pos = avio_tell(pb);
281 58 avio_wb32(pb, 0); // size
282
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
283 58 avio_wb32(pb, 0); // version & flags
284 58 entryPos = avio_tell(pb);
285 58 avio_wb32(pb, track->entry); // entry count
286
2/2
✓ Branch 0 taken 3209 times.
✓ Branch 1 taken 58 times.
3267 for (i = 0; i < track->entry; i++) {
287
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 3002 times.
3209 if (track->cluster[i].flags & flag) {
288 207 avio_wb32(pb, i + 1);
289 207 index++;
290 }
291 }
292 58 curpos = avio_tell(pb);
293 58 avio_seek(pb, entryPos, SEEK_SET);
294 58 avio_wb32(pb, index); // rewrite size
295 58 avio_seek(pb, curpos, SEEK_SET);
296 58 return update_size(pb, pos);
297 }
298
299 /* Sample dependency atom */
300 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
301 {
302 int i;
303 uint8_t leading, dependent, reference, redundancy;
304 3 int64_t pos = avio_tell(pb);
305 3 avio_wb32(pb, 0); // size
306 3 ffio_wfourcc(pb, "sdtp");
307 3 avio_wb32(pb, 0); // version & flags
308
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
309 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
310 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
311
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
312 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
313 }
314
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
315 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
316 }
317 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
318 13 (reference << 2) | redundancy);
319 }
320 3 return update_size(pb, pos);
321 }
322
323 #if CONFIG_IAMFENC
324 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
325 {
326 AVIOContext *dyn_bc;
327 5 int64_t pos = avio_tell(pb);
328 5 uint8_t *dyn_buf = NULL;
329 int dyn_size;
330 5 int ret = avio_open_dyn_buf(&dyn_bc);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
332 return ret;
333
334 5 avio_wb32(pb, 0);
335 5 ffio_wfourcc(pb, "iacb");
336 5 avio_w8(pb, 1); // configurationVersion
337
338 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
340 return ret;
341
342 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
343 5 ffio_write_leb(pb, dyn_size);
344 5 avio_write(pb, dyn_buf, dyn_size);
345 5 av_free(dyn_buf);
346
347 5 return update_size(pb, pos);
348 }
349 #endif
350
351 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
352 {
353 avio_wb32(pb, 0x11); /* size */
354 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
355 else ffio_wfourcc(pb, "damr");
356 ffio_wfourcc(pb, "FFMP");
357 avio_w8(pb, 0); /* decoder version */
358
359 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
360 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
361 avio_w8(pb, 0x01); /* Frames per sample */
362 return 0x11;
363 }
364
365 struct eac3_info {
366 AVPacket *pkt;
367 uint8_t ec3_done;
368 uint8_t num_blocks;
369
370 /* Layout of the EC3SpecificBox */
371 /* maximum bitrate */
372 uint16_t data_rate;
373 int8_t ac3_bit_rate_code;
374 /* number of independent substreams */
375 uint8_t num_ind_sub;
376 struct {
377 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
378 uint8_t fscod;
379 /* bit stream identification 5 bits */
380 uint8_t bsid;
381 /* one bit reserved */
382 /* audio service mixing (not supported yet) 1 bit */
383 /* bit stream mode 3 bits */
384 uint8_t bsmod;
385 /* audio coding mode 3 bits */
386 uint8_t acmod;
387 /* sub woofer on 1 bit */
388 uint8_t lfeon;
389 /* 3 bits reserved */
390 /* number of dependent substreams associated with this substream 4 bits */
391 uint8_t num_dep_sub;
392 /* channel locations of the dependent substream(s), if any, 9 bits */
393 uint16_t chan_loc;
394 /* if there is no dependent substream, then one bit reserved instead */
395 } substream[1]; /* TODO: support 8 independent substreams */
396 /* indicates the decoding complexity, 8 bits */
397 uint8_t complexity_index_type_a;
398 };
399
400 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
401 {
402 5 struct eac3_info *info = track->eac3_priv;
403 PutBitContext pbc;
404 uint8_t buf[3];
405
406
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!info || !info->ec3_done) {
407 av_log(s, AV_LOG_ERROR,
408 "Cannot write moov atom before AC3 packets."
409 " Set the delay_moov flag to fix this.\n");
410 return AVERROR(EINVAL);
411 }
412
413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
414 av_log(s, AV_LOG_ERROR,
415 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
416 "ISOBMFF specification in ETSI TS 102 366!\n",
417 info->substream[0].bsid);
418 return AVERROR(EINVAL);
419 }
420
421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
422 av_log(s, AV_LOG_ERROR,
423 "No valid AC3 bit rate code for data rate of %d!\n",
424 info->data_rate);
425 return AVERROR(EINVAL);
426 }
427
428 5 avio_wb32(pb, 11);
429 5 ffio_wfourcc(pb, "dac3");
430
431 5 init_put_bits(&pbc, buf, sizeof(buf));
432 5 put_bits(&pbc, 2, info->substream[0].fscod);
433 5 put_bits(&pbc, 5, info->substream[0].bsid);
434 5 put_bits(&pbc, 3, info->substream[0].bsmod);
435 5 put_bits(&pbc, 3, info->substream[0].acmod);
436 5 put_bits(&pbc, 1, info->substream[0].lfeon);
437 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
438 5 put_bits(&pbc, 5, 0); // reserved
439
440 5 flush_put_bits(&pbc);
441 5 avio_write(pb, buf, sizeof(buf));
442
443 5 return 11;
444 }
445
446 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
447 {
448 1039 AC3HeaderInfo *hdr = NULL;
449 struct eac3_info *info;
450 int num_blocks, ret;
451
452
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
453
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
454 return AVERROR(ENOMEM);
455
456 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
457 }
458 1039 info = track->eac3_priv;
459
460
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
1039 if (!info->pkt && !(info->pkt = av_packet_alloc()))
461 return AVERROR(ENOMEM);
462
463
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1038 times.
1039 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
465 goto end;
466
467 /* drop the packets until we see a good one */
468
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
469 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
470 1 ret = 0;
471 } else
472 ret = AVERROR_INVALIDDATA;
473 1 goto end;
474 }
475
476 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
477 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
478 hdr->ac3_bit_rate_code);
479 1038 info->complexity_index_type_a = hdr->complexity_index_type_a;
480
481 1038 num_blocks = hdr->num_blocks;
482
483
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
484 /* AC-3 substream must be the first one */
485
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
486 ret = AVERROR(EINVAL);
487 goto end;
488 }
489
490 /* this should always be the case, given that our AC-3 parser
491 * concatenates dependent frames to their independent parent */
492
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
493
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
494 /* substream ids must be incremental */
495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
496 ret = AVERROR(EINVAL);
497 goto end;
498 }
499
500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
501 //info->num_ind_sub++;
502 avpriv_request_sample(mov->fc, "Multiple independent substreams");
503 ret = AVERROR_PATCHWELCOME;
504 goto end;
505
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
506
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 hdr->substreamid == 0 && info->substream[0].bsid) {
507 1 info->ec3_done = 1;
508 1 goto concatenate;
509 }
510 } else {
511 if (hdr->substreamid != 0) {
512 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
513 ret = AVERROR_PATCHWELCOME;
514 goto end;
515 }
516 }
517
518 /* fill the info needed for the "dec3" atom */
519 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
520 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
521 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
522 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
523 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
524
525
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
526 // with AC-3 we only require the information of a single packet,
527 // so we can finish as soon as the basic values of the bit stream
528 // have been set to the track's informational structure.
529 4 info->ec3_done = 1;
530 4 goto concatenate;
531 }
532
533 /* Parse dependent substream(s), if any */
534
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
535 int cumul_size = hdr->frame_size;
536 int parent = hdr->substreamid;
537
538 while (cumul_size != pkt->size) {
539 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
540 if (ret < 0)
541 goto end;
542 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
543 ret = AVERROR(EINVAL);
544 goto end;
545 }
546 info->substream[parent].num_dep_sub++;
547 ret /= 8;
548
549 /* get the dependent stream channel map, if exists */
550 if (hdr->channel_map_present)
551 info->substream[parent].chan_loc |= (hdr->channel_map >> 5) & 0x1f;
552 else
553 info->substream[parent].chan_loc |= hdr->channel_mode;
554 cumul_size += hdr->frame_size;
555 }
556 }
557 }
558
559 1033 concatenate:
560
2/4
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
1038 if (!info->num_blocks && num_blocks == 6) {
561 1038 ret = pkt->size;
562 1038 goto end;
563 }
564 else if (info->num_blocks + num_blocks > 6) {
565 ret = AVERROR_INVALIDDATA;
566 goto end;
567 }
568
569 if (!info->num_blocks) {
570 ret = av_packet_ref(info->pkt, pkt);
571 if (!ret)
572 info->num_blocks = num_blocks;
573 goto end;
574 } else {
575 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
576 goto end;
577 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
578 info->num_blocks += num_blocks;
579 info->pkt->duration += pkt->duration;
580 if (info->num_blocks != 6)
581 goto end;
582 av_packet_unref(pkt);
583 av_packet_move_ref(pkt, info->pkt);
584 info->num_blocks = 0;
585 }
586 ret = pkt->size;
587
588 1039 end:
589 1039 av_free(hdr);
590
591 1039 return ret;
592 }
593
594 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
595 {
596 PutBitContext pbc;
597 uint8_t *buf;
598 struct eac3_info *info;
599 int size, i;
600
601
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
602 av_log(s, AV_LOG_ERROR,
603 "Cannot write moov atom before EAC3 packets parsed.\n");
604 return AVERROR(EINVAL);
605 }
606
607 1 info = track->eac3_priv;
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
609 1 buf = av_malloc(size);
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
611 return AVERROR(ENOMEM);
612 }
613
614 1 init_put_bits(&pbc, buf, size);
615 1 put_bits(&pbc, 13, info->data_rate);
616 1 put_bits(&pbc, 3, info->num_ind_sub);
617
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
618 1 put_bits(&pbc, 2, info->substream[i].fscod);
619 1 put_bits(&pbc, 5, info->substream[i].bsid);
620 1 put_bits(&pbc, 1, 0); /* reserved */
621 1 put_bits(&pbc, 1, 0); /* asvc */
622 1 put_bits(&pbc, 3, info->substream[i].bsmod);
623 1 put_bits(&pbc, 3, info->substream[i].acmod);
624 1 put_bits(&pbc, 1, info->substream[i].lfeon);
625 1 put_bits(&pbc, 3, 0); /* reserved */
626 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
627
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
628 1 put_bits(&pbc, 1, 0); /* reserved */
629 } else {
630 put_bits(&pbc, 9, info->substream[i].chan_loc);
631 }
632 }
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (info->complexity_index_type_a) {
634 put_bits(&pbc, 7, 0); /* reserved */
635 put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
636 put_bits(&pbc, 8, info->complexity_index_type_a);
637 }
638 1 flush_put_bits(&pbc);
639 1 size = put_bytes_output(&pbc);
640
641 1 avio_wb32(pb, size + 8);
642 1 ffio_wfourcc(pb, "dec3");
643 1 avio_write(pb, buf, size);
644
645 1 av_free(buf);
646
647 1 return size;
648 }
649
650 /**
651 * This function writes extradata "as is".
652 * Extradata must be formatted like a valid atom (with size and tag).
653 */
654 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
655 {
656 12 avio_write(pb, track->par->extradata, track->par->extradata_size);
657 12 return track->par->extradata_size;
658 }
659
660 static int mov_write_enda_tag(AVIOContext *pb)
661 {
662 avio_wb32(pb, 10);
663 ffio_wfourcc(pb, "enda");
664 avio_wb16(pb, 1); /* little endian */
665 return 10;
666 }
667
668 2 static int mov_write_enda_tag_be(AVIOContext *pb)
669 {
670 2 avio_wb32(pb, 10);
671 2 ffio_wfourcc(pb, "enda");
672 2 avio_wb16(pb, 0); /* big endian */
673 2 return 10;
674 }
675
676 322 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
677 {
678 322 int i = 3;
679 322 avio_w8(pb, tag);
680
2/2
✓ Branch 0 taken 966 times.
✓ Branch 1 taken 322 times.
1288 for (; i > 0; i--)
681 966 avio_w8(pb, (size >> (7 * i)) | 0x80);
682 322 avio_w8(pb, size & 0x7F);
683 322 }
684
685 216 static unsigned compute_avg_bitrate(MOVTrack *track)
686 {
687 216 uint64_t size = 0;
688 int i;
689
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 176 times.
216 if (!track->track_duration)
690 40 return 0;
691
2/2
✓ Branch 0 taken 9063 times.
✓ Branch 1 taken 176 times.
9239 for (i = 0; i < track->entry; i++)
692 9063 size += track->cluster[i].size;
693 176 return size * 8 * track->timescale / track->track_duration;
694 }
695
696 struct mpeg4_bit_rate_values {
697 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
698 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
699 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
700 };
701
702 216 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
703 {
704 432 const AVPacketSideData *sd = track->st ?
705 215 av_packet_side_data_get(track->st->codecpar->coded_side_data,
706 215 track->st->codecpar->nb_coded_side_data,
707
2/2
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 1 times.
216 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
708
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 182 times.
216 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
709 216 struct mpeg4_bit_rate_values bit_rates = { 0 };
710
711 216 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
712
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 86 times.
216 if (!bit_rates.avg_bit_rate) {
713 // if the average bit rate cannot be calculated at this point, such as
714 // in the case of fragmented MP4, utilize the following values as
715 // fall-back in priority order:
716 //
717 // 1. average bit rate property
718 // 2. bit rate (usually average over the whole clip)
719 // 3. maximum bit rate property
720
721
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 127 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
130 if (props && props->avg_bitrate) {
722 3 bit_rates.avg_bit_rate = props->avg_bitrate;
723
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 122 times.
127 } else if (track->par->bit_rate) {
724 5 bit_rates.avg_bit_rate = track->par->bit_rate;
725
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
122 } else if (props && props->max_bitrate) {
726 bit_rates.avg_bit_rate = props->max_bitrate;
727 }
728 }
729
730 // (FIXME should be max rate in any 1 sec window)
731 216 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
732 bit_rates.avg_bit_rate);
733
734 // utilize values from properties if we have them available
735
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 182 times.
216 if (props) {
736 // no avg_bitrate signals that the track is VBR
737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!props->avg_bitrate)
738 bit_rates.avg_bit_rate = props->avg_bitrate;
739 34 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
740 props->max_bitrate);
741 34 bit_rates.buffer_size = props->buffer_size / 8;
742 }
743
744 216 return bit_rates;
745 }
746
747 81 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
748 {
749 81 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
750 81 int64_t pos = avio_tell(pb);
751
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 2 times.
81 int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0;
752
753 81 avio_wb32(pb, 0); // size
754 81 ffio_wfourcc(pb, "esds");
755 81 avio_wb32(pb, 0); // Version
756
757 // ES descriptor
758 81 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
759 81 avio_wb16(pb, track->track_id);
760 81 avio_w8(pb, 0x00); // flags (= no flags)
761
762 // DecoderConfig descriptor
763 81 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
764
765 // Object type indication
766
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
767
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 track->par->codec_id == AV_CODEC_ID_MP3) &&
768 track->par->sample_rate > 24000)
769 avio_w8(pb, 0x6B); // 11172-3
770 else
771 81 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
772
773 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
774 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
776 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
777
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 27 times.
81 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
778 54 avio_w8(pb, 0x15); // flags (= Audiostream)
779 else
780 27 avio_w8(pb, 0x11); // flags (= Visualstream)
781
782 81 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
783 81 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
784 81 avio_wb32(pb, bit_rates.avg_bit_rate);
785
786
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 2 times.
81 if (track->vos_len) {
787 // DecoderSpecific info descriptor
788 79 put_descr(pb, 0x05, track->vos_len);
789 79 avio_write(pb, track->vos_data, track->vos_len);
790 }
791
792 // SL descriptor
793 81 put_descr(pb, 0x06, 1);
794 81 avio_w8(pb, 0x02);
795 81 return update_size(pb, pos);
796 }
797
798 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
799 {
800
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
801
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
802
2/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
154 codec_id == AV_CODEC_ID_PCM_F32LE ||
803 codec_id == AV_CODEC_ID_PCM_F64LE;
804 }
805
806 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
807 {
808
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
809
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
810
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
150 codec_id == AV_CODEC_ID_PCM_F32BE ||
811 codec_id == AV_CODEC_ID_PCM_F64BE;
812 }
813
814 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
815 {
816 int ret;
817 int64_t pos = avio_tell(pb);
818 avio_wb32(pb, 0);
819 avio_wl32(pb, track->tag); // store it byteswapped
820 track->par->codec_tag = av_bswap16(track->tag >> 16);
821 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
822 return ret;
823 return update_size(pb, pos);
824 }
825
826 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
827 {
828 int ret;
829 int64_t pos = avio_tell(pb);
830 avio_wb32(pb, 0);
831 ffio_wfourcc(pb, "wfex");
832 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
833 return ret;
834 return update_size(pb, pos);
835 }
836
837 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
838 {
839 int64_t pos = avio_tell(pb);
840 avio_wb32(pb, 0);
841 ffio_wfourcc(pb, "dfLa");
842 avio_w8(pb, 0); /* version */
843 avio_wb24(pb, 0); /* flags */
844
845 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
846 if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
847 return AVERROR_INVALIDDATA;
848
849 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
850 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
851 avio_wb24(pb, track->par->extradata_size); /* Length */
852 avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
853
854 return update_size(pb, pos);
855 }
856
857 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
858 {
859 int64_t pos = avio_tell(pb);
860 int channels, channel_map;
861 avio_wb32(pb, 0);
862 ffio_wfourcc(pb, "dOps");
863 avio_w8(pb, 0); /* Version */
864 if (track->par->extradata_size < 19) {
865 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
866 return AVERROR_INVALIDDATA;
867 }
868 /* extradata contains an Ogg OpusHead, other than byte-ordering and
869 OpusHead's preceeding magic/version, OpusSpecificBox is currently
870 identical. */
871 channels = AV_RB8(track->par->extradata + 9);
872 channel_map = AV_RB8(track->par->extradata + 18);
873
874 avio_w8(pb, channels); /* OuputChannelCount */
875 avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */
876 avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */
877 avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */
878 avio_w8(pb, channel_map); /* ChannelMappingFamily */
879 /* Write the rest of the header out without byte-swapping. */
880 if (channel_map) {
881 if (track->par->extradata_size < 21 + channels) {
882 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
883 return AVERROR_INVALIDDATA;
884 }
885 avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */
886 }
887
888 return update_size(pb, pos);
889 }
890
891 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
892 {
893 int64_t pos = avio_tell(pb);
894 int length;
895 avio_wb32(pb, 0);
896 ffio_wfourcc(pb, "dmlp");
897
898 if (track->vos_len < 20) {
899 av_log(s, AV_LOG_ERROR,
900 "Cannot write moov atom before TrueHD packets."
901 " Set the delay_moov flag to fix this.\n");
902 return AVERROR(EINVAL);
903 }
904
905 length = (AV_RB16(track->vos_data) & 0xFFF) * 2;
906 if (length < 20 || length > track->vos_len)
907 return AVERROR_INVALIDDATA;
908
909 // Only TrueHD is supported
910 if (AV_RB32(track->vos_data + 4) != 0xF8726FBA)
911 return AVERROR_INVALIDDATA;
912
913 avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */
914 avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */
915 avio_wb32(pb, 0); /* reserved */
916
917 return update_size(pb, pos);
918 }
919
920 67 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
921 {
922 67 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
923 67 AVChannelLayout ch_layout = { 0 };
924 int64_t pos;
925 int ambisonic_order, ambi_channels, non_diegetic_channels;
926 int i, ret;
927
928
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 if (!str)
929 67 return 0;
930
931 ret = av_channel_layout_from_string(&ch_layout, str->value);
932 if (ret < 0) {
933 if (ret == AVERROR(EINVAL)) {
934 invalid:
935 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
936 ret = 0;
937 }
938 av_channel_layout_uninit(&ch_layout);
939 return ret;
940 }
941
942 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
943 goto invalid;
944
945 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
946 if (ambisonic_order < 0)
947 goto invalid;
948
949 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
950 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
951 if (non_diegetic_channels &&
952 (non_diegetic_channels != 2 ||
953 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
954 goto invalid;
955
956 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
957
958 pos = avio_tell(pb);
959
960 avio_wb32(pb, 0); // Size
961 ffio_wfourcc(pb, "SA3D");
962 avio_w8(pb, 0); // version
963 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
964 avio_wb32(pb, ambisonic_order); // ambisonic_order
965 avio_w8(pb, 0); // ambisonic_channel_ordering
966 avio_w8(pb, 0); // ambisonic_normalization
967 avio_wb32(pb, ch_layout.nb_channels); // num_channels
968 for (i = 0; i < ambi_channels; i++)
969 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
970 for (; i < ch_layout.nb_channels; i++)
971 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
972
973 av_channel_layout_uninit(&ch_layout);
974
975 return update_size(pb, pos);
976 }
977
978 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
979 {
980 uint32_t layout_tag, bitmap, *channel_desc;
981 40 int64_t pos = avio_tell(pb);
982 int num_desc, ret;
983
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
985 return 0;
986
987 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
988 &bitmap, &channel_desc);
989
990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
991 if (ret == AVERROR(ENOSYS)) {
992 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
993 "lack of channel information\n");
994 ret = 0;
995 }
996
997 return ret;
998 }
999
1000
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
40 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1002 1 channel_desc = av_malloc(sizeof(*channel_desc));
1003
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1004 return AVERROR(ENOMEM);
1005
1006 1 layout_tag = 0;
1007 1 bitmap = 0;
1008 1 *channel_desc = 3; // channel label "Center"
1009 }
1010
1011
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1012
1013 40 avio_wb32(pb, 0); // Size
1014 40 ffio_wfourcc(pb, "chan"); // Type
1015 40 avio_w8(pb, 0); // Version
1016 40 avio_wb24(pb, 0); // Flags
1017 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1018 40 avio_wb32(pb, bitmap); // mChannelBitmap
1019 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1020
1021
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1022 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1023 3 avio_wb32(pb, 0); // mChannelFlags
1024 3 avio_wl32(pb, 0); // mCoordinates[0]
1025 3 avio_wl32(pb, 0); // mCoordinates[1]
1026 3 avio_wl32(pb, 0); // mCoordinates[2]
1027 }
1028
1029 40 av_free(channel_desc);
1030
1031 40 return update_size(pb, pos);
1032 }
1033
1034 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1035 {
1036 15 int64_t pos = avio_tell(pb);
1037
1038 15 avio_wb32(pb, 0); /* size */
1039 15 ffio_wfourcc(pb, "wave");
1040
1041
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1042 15 avio_wb32(pb, 12); /* size */
1043 15 ffio_wfourcc(pb, "frma");
1044 15 avio_wl32(pb, track->tag);
1045 }
1046
1047
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1048 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1049 3 avio_wb32(pb, 12); /* size */
1050 3 ffio_wfourcc(pb, "mp4a");
1051 3 avio_wb32(pb, 0);
1052 3 mov_write_esds_tag(pb, track);
1053
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1054 mov_write_enda_tag(pb);
1055
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1056 2 mov_write_enda_tag_be(pb);
1057
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1058 mov_write_amr_tag(pb, track);
1059
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1060 1 mov_write_ac3_tag(s, pb, track);
1061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1062 mov_write_eac3_tag(s, pb, track);
1063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1064 track->par->codec_id == AV_CODEC_ID_QDM2) {
1065 9 mov_write_extradata_tag(pb, track);
1066 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1067 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1068 mov_write_ms_tag(s, pb, track);
1069 }
1070
1071 15 avio_wb32(pb, 8); /* size */
1072 15 avio_wb32(pb, 0); /* null tag */
1073
1074 15 return update_size(pb, pos);
1075 }
1076
1077 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1078 {
1079 uint8_t *unescaped;
1080 const uint8_t *start, *next, *end = track->vos_data + track->vos_len;
1081 int unescaped_size, seq_found = 0;
1082 int level = 0, interlace = 0;
1083 int packet_seq = track->vc1_info.packet_seq;
1084 int packet_entry = track->vc1_info.packet_entry;
1085 int slices = track->vc1_info.slices;
1086 PutBitContext pbc;
1087
1088 if (track->start_dts == AV_NOPTS_VALUE) {
1089 /* No packets written yet, vc1_info isn't authoritative yet. */
1090 /* Assume inline sequence and entry headers. */
1091 packet_seq = packet_entry = 1;
1092 av_log(NULL, AV_LOG_WARNING,
1093 "moov atom written before any packets, unable to write correct "
1094 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1095 }
1096
1097 unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
1098 if (!unescaped)
1099 return AVERROR(ENOMEM);
1100 start = find_next_marker(track->vos_data, end);
1101 for (next = start; next < end; start = next) {
1102 GetBitContext gb;
1103 int size;
1104 next = find_next_marker(start + 4, end);
1105 size = next - start - 4;
1106 if (size <= 0)
1107 continue;
1108 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1109 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1110 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1111 int profile = get_bits(&gb, 2);
1112 if (profile != PROFILE_ADVANCED) {
1113 av_free(unescaped);
1114 return AVERROR(ENOSYS);
1115 }
1116 seq_found = 1;
1117 level = get_bits(&gb, 3);
1118 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1119 * width, height */
1120 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1121 skip_bits(&gb, 1); /* broadcast */
1122 interlace = get_bits1(&gb);
1123 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1124 }
1125 }
1126 if (!seq_found) {
1127 av_free(unescaped);
1128 return AVERROR(ENOSYS);
1129 }
1130
1131 init_put_bits(&pbc, buf, 7);
1132 /* VC1DecSpecStruc */
1133 put_bits(&pbc, 4, 12); /* profile - advanced */
1134 put_bits(&pbc, 3, level);
1135 put_bits(&pbc, 1, 0); /* reserved */
1136 /* VC1AdvDecSpecStruc */
1137 put_bits(&pbc, 3, level);
1138 put_bits(&pbc, 1, 0); /* cbr */
1139 put_bits(&pbc, 6, 0); /* reserved */
1140 put_bits(&pbc, 1, !interlace); /* no interlace */
1141 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1142 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1143 put_bits(&pbc, 1, !slices); /* no slice code */
1144 put_bits(&pbc, 1, 0); /* no bframe */
1145 put_bits(&pbc, 1, 0); /* reserved */
1146
1147 /* framerate */
1148 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1149 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1150 else
1151 put_bits32(&pbc, 0xffffffff);
1152
1153 flush_put_bits(&pbc);
1154
1155 av_free(unescaped);
1156
1157 return 0;
1158 }
1159
1160 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1161 {
1162 uint8_t buf[7] = { 0 };
1163 int ret;
1164
1165 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1166 return ret;
1167
1168 avio_wb32(pb, track->vos_len + 8 + sizeof(buf));
1169 ffio_wfourcc(pb, "dvc1");
1170 avio_write(pb, buf, sizeof(buf));
1171 avio_write(pb, track->vos_data, track->vos_len);
1172
1173 return 0;
1174 }
1175
1176 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1177 {
1178 4 avio_wb32(pb, track->vos_len + 8);
1179 4 ffio_wfourcc(pb, "glbl");
1180 4 avio_write(pb, track->vos_data, track->vos_len);
1181 4 return 8 + track->vos_len;
1182 }
1183
1184 /**
1185 * Compute flags for 'lpcm' tag.
1186 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1187 */
1188 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1189 {
1190
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 switch (codec_id) {
1191 case AV_CODEC_ID_PCM_F32BE:
1192 case AV_CODEC_ID_PCM_F64BE:
1193 return 11;
1194 case AV_CODEC_ID_PCM_F32LE:
1195 case AV_CODEC_ID_PCM_F64LE:
1196 return 9;
1197 case AV_CODEC_ID_PCM_U8:
1198 return 10;
1199 case AV_CODEC_ID_PCM_S16BE:
1200 case AV_CODEC_ID_PCM_S24BE:
1201 case AV_CODEC_ID_PCM_S32BE:
1202 return 14;
1203 case AV_CODEC_ID_PCM_S8:
1204 case AV_CODEC_ID_PCM_S16LE:
1205 case AV_CODEC_ID_PCM_S24LE:
1206 case AV_CODEC_ID_PCM_S32LE:
1207 return 12;
1208 8 default:
1209 8 return 0;
1210 }
1211 }
1212
1213 25482 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1214 {
1215 int64_t next_dts;
1216
1217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25482 times.
25482 if (cluster_idx >= track->entry)
1218 return 0;
1219
1220
2/2
✓ Branch 0 taken 658 times.
✓ Branch 1 taken 24824 times.
25482 if (cluster_idx + 1 == track->entry)
1221 658 next_dts = track->track_duration + track->start_dts;
1222 else
1223 24824 next_dts = track->cluster[cluster_idx + 1].dts;
1224
1225 25482 next_dts -= track->cluster[cluster_idx].dts;
1226
1227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25482 times.
25482 av_assert0(next_dts >= 0);
1228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25482 times.
25482 av_assert0(next_dts <= INT_MAX);
1229
1230 25482 return next_dts;
1231 }
1232
1233 4 static int get_samples_per_packet(MOVTrack *track)
1234 {
1235 int i, first_duration;
1236
1237 /* use 1 for raw PCM */
1238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1239 return 1;
1240
1241 /* check to see if duration is constant for all clusters */
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1243 return 0;
1244 4 first_duration = get_cluster_duration(track, 0);
1245
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1246
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1247 4 return 0;
1248 }
1249 return first_duration;
1250 }
1251
1252 135 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1253 {
1254 135 int64_t pos = avio_tell(pb);
1255 135 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1256
3/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
135 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1257
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 !bit_rates.buffer_size)
1258 // no useful data to be written, skip
1259 81 return 0;
1260
1261 54 avio_wb32(pb, 0); /* size */
1262 54 ffio_wfourcc(pb, "btrt");
1263
1264 54 avio_wb32(pb, bit_rates.buffer_size);
1265 54 avio_wb32(pb, bit_rates.max_bit_rate);
1266 54 avio_wb32(pb, bit_rates.avg_bit_rate);
1267
1268 54 return update_size(pb, pos);
1269 }
1270
1271 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1272 {
1273 7 int64_t pos = avio_tell(pb);
1274 7 int config = 0;
1275 int ret;
1276 7 uint8_t *speaker_pos = NULL;
1277 7 const AVChannelLayout *layout = &track->par->ch_layout;
1278
1279 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1280
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
7 if (ret || !config) {
1281 4 config = 0;
1282 4 speaker_pos = av_malloc(layout->nb_channels);
1283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1284 return AVERROR(ENOMEM);
1285 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1286 4 speaker_pos, layout->nb_channels);
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1288 char buf[128] = {0};
1289
1290 av_freep(&speaker_pos);
1291 av_channel_layout_describe(layout, buf, sizeof(buf));
1292 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1293 return ret;
1294 }
1295 }
1296
1297 7 avio_wb32(pb, 0); /* size */
1298 7 ffio_wfourcc(pb, "chnl");
1299 7 avio_wb32(pb, 0); /* version & flags */
1300
1301 7 avio_w8(pb, 1); /* stream_structure */
1302 7 avio_w8(pb, config);
1303
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1304 3 avio_wb64(pb, 0);
1305 } else {
1306 4 avio_write(pb, speaker_pos, layout->nb_channels);
1307 4 av_freep(&speaker_pos);
1308 }
1309
1310 7 return update_size(pb, pos);
1311 }
1312
1313 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1314 {
1315 9 int64_t pos = avio_tell(pb);
1316 int format_flags;
1317 int sample_size;
1318
1319 9 avio_wb32(pb, 0); /* size */
1320 9 ffio_wfourcc(pb, "pcmC");
1321 9 avio_wb32(pb, 0); /* version & flags */
1322
1323 /* 0x01: indicates little-endian format */
1324 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1325
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1327
2/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1328 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1329 9 avio_w8(pb, format_flags);
1330 9 sample_size = track->par->bits_per_raw_sample;
1331
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1332 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1334 9 avio_w8(pb, sample_size);
1335
1336 9 return update_size(pb, pos);
1337 }
1338
1339 110 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1340 {
1341 110 int64_t pos = avio_tell(pb);
1342 110 int version = 0;
1343 110 uint32_t tag = track->tag;
1344 110 int ret = 0;
1345
1346
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 70 times.
110 if (track->mode == MODE_MOV) {
1347
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
40 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1348
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1349 tag = AV_RL32("lpcm");
1350 4 version = 2;
1351
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
62 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1352 26 mov_pcm_be_gt16(track->par->codec_id) ||
1353
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1354
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1356 12 version = 1;
1357 }
1358 }
1359
1360 110 avio_wb32(pb, 0); /* size */
1361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 if (mov->encryption_scheme != MOV_ENC_NONE) {
1362 ffio_wfourcc(pb, "enca");
1363 } else {
1364 110 avio_wl32(pb, tag); // store it byteswapped
1365 }
1366 110 avio_wb32(pb, 0); /* Reserved */
1367 110 avio_wb16(pb, 0); /* Reserved */
1368 110 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1369
1370 /* SoundDescription */
1371 110 avio_wb16(pb, version); /* Version */
1372 110 avio_wb16(pb, 0); /* Revision level */
1373 110 avio_wb32(pb, 0); /* Reserved */
1374
1375
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 106 times.
110 if (version == 2) {
1376 4 avio_wb16(pb, 3);
1377 4 avio_wb16(pb, 16);
1378 4 avio_wb16(pb, 0xfffe);
1379 4 avio_wb16(pb, 0);
1380 4 avio_wb32(pb, 0x00010000);
1381 4 avio_wb32(pb, 72);
1382 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1383 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1384 4 avio_wb32(pb, 0x7F000000);
1385 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1386 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1387 4 avio_wb32(pb, track->sample_size);
1388 4 avio_wb32(pb, get_samples_per_packet(track));
1389 } else {
1390
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 70 times.
106 if (track->mode == MODE_MOV) {
1391 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1392
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1393
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1394 1 avio_wb16(pb, 8); /* bits per sample */
1395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1396 avio_wb16(pb, track->par->bits_per_coded_sample);
1397 else
1398 35 avio_wb16(pb, 16);
1399
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1400 } else { /* reserved for mp4/3gp */
1401
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 5 times.
135 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1402 65 0 : track->par->ch_layout.nb_channels);
1403
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 5 times.
70 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
65 track->par->codec_id == AV_CODEC_ID_ALAC) {
1405 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1406 } else {
1407 65 avio_wb16(pb, 16);
1408 }
1409 70 avio_wb16(pb, 0);
1410 }
1411
1412 106 avio_wb16(pb, 0); /* packet size (= 0) */
1413
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 101 times.
106 if (track->tag == MKTAG('i','a','m','f'))
1414 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1416 avio_wb16(pb, 48000);
1417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1418 avio_wb32(pb, track->par->sample_rate);
1419 else
1420
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
202 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1421 101 track->par->sample_rate : 0);
1422
1423
1/2
✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
106 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1424 106 avio_wb16(pb, 0); /* Reserved */
1425 }
1426
1427
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 98 times.
110 if (version == 1) { /* SoundDescription V1 extended info */
1428
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
24 if (mov_pcm_le_gt16(track->par->codec_id) ||
1429 12 mov_pcm_be_gt16(track->par->codec_id))
1430 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1431 else
1432 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1433 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1434 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1435 12 avio_wb32(pb, 2); /* Bytes per sample */
1436 }
1437
1438
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 70 times.
110 if (track->mode == MODE_MOV &&
1439
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1440
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1441
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1442
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1443
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1444
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1445
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1446
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1447
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
54 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1448
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1449 15 ret = mov_write_wave_tag(s, pb, track);
1450
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 44 times.
95 else if (track->tag == MKTAG('m','p','4','a'))
1451 51 ret = mov_write_esds_tag(pb, track);
1452 #if CONFIG_IAMFENC
1453
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 39 times.
44 else if (track->tag == MKTAG('i','a','m','f'))
1454 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1455 #endif
1456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1457 ret = mov_write_amr_tag(pb, track);
1458
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1459 4 ret = mov_write_ac3_tag(s, pb, track);
1460
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1461 1 ret = mov_write_eac3_tag(s, pb, track);
1462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1463 ret = mov_write_extradata_tag(pb, track);
1464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1465 ret = mov_write_wfex_tag(s, pb, track);
1466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1467 ret = mov_write_dfla_tag(pb, track);
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1469 ret = mov_write_dops_tag(s, pb, track);
1470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1471 ret = mov_write_dmlp_tag(s, pb, track);
1472
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
34 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1473
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1474 7 ret = mov_write_chnl_tag(s, pb, track);
1475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1476 return ret;
1477 9 ret = mov_write_pcmc_tag(s, pb, track);
1478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->vos_len > 0)
1479 ret = mov_write_glbl_tag(pb, track);
1480
1481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 if (ret < 0)
1482 return ret;
1483
1484
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
110 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1485
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1486 return ret;
1487 }
1488
1489
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
110 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1490
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1491 return ret;
1492 }
1493
1494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 if (mov->encryption_scheme != MOV_ENC_NONE
1495 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1496 return ret;
1497 }
1498
1499
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
177 if (mov->write_btrt &&
1500 67 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1501 return ret;
1502
1503 110 ret = update_size(pb, pos);
1504 110 return ret;
1505 }
1506
1507 static int mov_write_d263_tag(AVIOContext *pb)
1508 {
1509 avio_wb32(pb, 0xf); /* size */
1510 ffio_wfourcc(pb, "d263");
1511 ffio_wfourcc(pb, "FFMP");
1512 avio_w8(pb, 0); /* decoder version */
1513 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1514 avio_w8(pb, 0xa); /* level */
1515 avio_w8(pb, 0); /* profile */
1516 return 0xf;
1517 }
1518
1519 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1520 {
1521 1 int64_t pos = avio_tell(pb);
1522
1523 1 avio_wb32(pb, 0);
1524 1 ffio_wfourcc(pb, "av1C");
1525 1 ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF);
1526 1 return update_size(pb, pos);
1527 }
1528
1529 53 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1530 {
1531 53 int64_t pos = avio_tell(pb);
1532
1533 53 avio_wb32(pb, 0);
1534 53 ffio_wfourcc(pb, "avcC");
1535 53 ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
1536 53 return update_size(pb, pos);
1537 }
1538
1539 /* AVS3 Intelligent Media Coding
1540 * Information Technology - Intelligent Media Coding
1541 * Part 6: Intelligent Media Format
1542 */
1543 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1544 {
1545 if (len < 4)
1546 return AVERROR_INVALIDDATA;
1547
1548 if (data[0] == 1) {
1549 // In Avs3DecoderConfigurationRecord format
1550 avio_write(pb, data, len);
1551 return 0;
1552 }
1553
1554 avio_w8(pb, 1); // version
1555 avio_wb16(pb, len); // sequence_header_length
1556 avio_write(pb, data, len); // sequence_header
1557 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1558
1559 return 0;
1560 }
1561
1562 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1563 {
1564 int64_t pos = avio_tell(pb);
1565 avio_wb32(pb, 0);
1566 ffio_wfourcc(pb, "av3c");
1567 mov_write_av3c(pb, track->vos_data, track->vos_len);
1568 return update_size(pb, pos);
1569 }
1570
1571 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1572 {
1573 int64_t pos = avio_tell(pb);
1574
1575 avio_wb32(pb, 0);
1576 ffio_wfourcc(pb, "vpcC");
1577 ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par);
1578 return update_size(pb, pos);
1579 }
1580
1581 3 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1582 {
1583 3 int64_t pos = avio_tell(pb);
1584
1585 3 avio_wb32(pb, 0);
1586 3 ffio_wfourcc(pb, "hvcC");
1587
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1588 1 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1, s);
1589 else
1590 2 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0, s);
1591 3 return update_size(pb, pos);
1592 }
1593
1594 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1595 {
1596 1 int64_t pos = avio_tell(pb);
1597 int ret;
1598
1599 1 avio_wb32(pb, 0);
1600 1 ffio_wfourcc(pb, "lhvC");
1601
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1602 1 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1, s);
1603 else
1604 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0, s);
1605
1606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1607 avio_seek(pb, pos, SEEK_SET);
1608 return ret;
1609 }
1610
1611 1 return update_size(pb, pos);
1612 }
1613
1614 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1615 {
1616 1 int64_t pos = avio_tell(pb);
1617
1618 1 avio_wb32(pb, 0);
1619 1 ffio_wfourcc(pb, "evcC");
1620
1621
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1622 1 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1);
1623 else
1624 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0);
1625
1626 1 return update_size(pb, pos);
1627 }
1628
1629 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1630 {
1631 1 int64_t pos = avio_tell(pb);
1632
1633 1 avio_wb32(pb, 0);
1634 1 ffio_wfourcc(pb, "vvcC");
1635
1636 1 avio_w8 (pb, 0); /* version */
1637 1 avio_wb24(pb, 0); /* flags */
1638
1639
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1640 1 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
1641 else
1642 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
1643 1 return update_size(pb, pos);
1644 }
1645
1646 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1647 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1648 {
1649 int interlaced;
1650 int cid;
1651 23 int display_width = track->par->width;
1652
1653
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (track->vos_data && track->vos_len > 0x29) {
1654
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) {
1655 /* looks like a DNxHD bit stream */
1656 23 interlaced = (track->vos_data[5] & 2);
1657 23 cid = AV_RB32(track->vos_data + 0x28);
1658 } else {
1659 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1660 return 0;
1661 }
1662 } else {
1663 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1664 return 0;
1665 }
1666
1667 23 avio_wb32(pb, 24); /* size */
1668 23 ffio_wfourcc(pb, "ACLR");
1669 23 ffio_wfourcc(pb, "ACLR");
1670 23 ffio_wfourcc(pb, "0001");
1671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1672 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1673 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1674 } else { /* Full range (0-255) */
1675 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1676 }
1677 23 avio_wb32(pb, 0); /* unknown */
1678
1679
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1680 12 avio_wb32(pb, 32);
1681 12 ffio_wfourcc(pb, "ADHR");
1682 12 ffio_wfourcc(pb, "0001");
1683 12 avio_wb32(pb, cid);
1684 12 avio_wb32(pb, 0); /* unknown */
1685 12 avio_wb32(pb, 1); /* unknown */
1686 12 avio_wb32(pb, 0); /* unknown */
1687 12 avio_wb32(pb, 0); /* unknown */
1688 12 return 0;
1689 }
1690
1691 11 avio_wb32(pb, 24); /* size */
1692 11 ffio_wfourcc(pb, "APRG");
1693 11 ffio_wfourcc(pb, "APRG");
1694 11 ffio_wfourcc(pb, "0001");
1695 11 avio_wb32(pb, 1); /* unknown */
1696 11 avio_wb32(pb, 0); /* unknown */
1697
1698 11 avio_wb32(pb, 120); /* size */
1699 11 ffio_wfourcc(pb, "ARES");
1700 11 ffio_wfourcc(pb, "ARES");
1701 11 ffio_wfourcc(pb, "0001");
1702 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1704 && track->par->sample_aspect_ratio.den > 0)
1705 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1706 11 avio_wb32(pb, display_width);
1707 /* values below are based on samples created with quicktime and avid codecs */
1708
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1709 11 avio_wb32(pb, track->par->height / 2);
1710 11 avio_wb32(pb, 2); /* unknown */
1711 11 avio_wb32(pb, 0); /* unknown */
1712 11 avio_wb32(pb, 4); /* unknown */
1713 } else {
1714 avio_wb32(pb, track->par->height);
1715 avio_wb32(pb, 1); /* unknown */
1716 avio_wb32(pb, 0); /* unknown */
1717 if (track->par->height == 1080)
1718 avio_wb32(pb, 5); /* unknown */
1719 else
1720 avio_wb32(pb, 6); /* unknown */
1721 }
1722 /* padding */
1723 11 ffio_fill(pb, 0, 10 * 8);
1724
1725 11 return 0;
1726 }
1727
1728 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1729 {
1730 avio_wb32(pb, 12);
1731 ffio_wfourcc(pb, "DpxE");
1732 if (track->par->extradata_size >= 12 &&
1733 !memcmp(&track->par->extradata[4], "DpxE", 4)) {
1734 avio_wb32(pb, track->par->extradata[11]);
1735 } else {
1736 avio_wb32(pb, 1);
1737 }
1738 return 0;
1739 }
1740
1741 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1742 {
1743 int tag;
1744
1745
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1746
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
1748 1 else tag = MKTAG('d','v','c',' ');
1749 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1750 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1751 else tag = MKTAG('d','v','p','p');
1752 } else if (track->par->height == 720) { /* HD 720 line */
1753 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1754 else tag = MKTAG('d','v','h','p');
1755 } else if (track->par->height == 1080) { /* HD 1080 line */
1756 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1757 else tag = MKTAG('d','v','h','6');
1758 } else {
1759 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1760 return 0;
1761 }
1762
1763 1 return tag;
1764 }
1765
1766 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1767 {
1768 3 AVRational rational_framerate = st->avg_frame_rate;
1769 3 int rate = 0;
1770
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1771 3 rate = av_q2d(rational_framerate);
1772 3 return rate;
1773 }
1774
1775 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1776 {
1777 1 int tag = track->par->codec_tag;
1778 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1779 1 AVStream *st = track->st;
1780 1 int rate = defined_frame_rate(s, st);
1781
1782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1783 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1784
1785
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1786
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (track->par->width == 1280 && track->par->height == 720) {
1787 if (!interlaced) {
1788 if (rate == 24) tag = MKTAG('x','d','v','4');
1789 else if (rate == 25) tag = MKTAG('x','d','v','5');
1790 else if (rate == 30) tag = MKTAG('x','d','v','1');
1791 else if (rate == 50) tag = MKTAG('x','d','v','a');
1792 else if (rate == 60) tag = MKTAG('x','d','v','9');
1793 }
1794
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1440 && track->par->height == 1080) {
1795 if (!interlaced) {
1796 if (rate == 24) tag = MKTAG('x','d','v','6');
1797 else if (rate == 25) tag = MKTAG('x','d','v','7');
1798 else if (rate == 30) tag = MKTAG('x','d','v','8');
1799 } else {
1800 if (rate == 25) tag = MKTAG('x','d','v','3');
1801 else if (rate == 30) tag = MKTAG('x','d','v','2');
1802 }
1803
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1920 && track->par->height == 1080) {
1804 if (!interlaced) {
1805 if (rate == 24) tag = MKTAG('x','d','v','d');
1806 else if (rate == 25) tag = MKTAG('x','d','v','e');
1807 else if (rate == 30) tag = MKTAG('x','d','v','f');
1808 } else {
1809 if (rate == 25) tag = MKTAG('x','d','v','c');
1810 else if (rate == 30) tag = MKTAG('x','d','v','b');
1811 }
1812 }
1813 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1814 if (track->par->width == 1280 && track->par->height == 720) {
1815 if (!interlaced) {
1816 if (rate == 24) tag = MKTAG('x','d','5','4');
1817 else if (rate == 25) tag = MKTAG('x','d','5','5');
1818 else if (rate == 30) tag = MKTAG('x','d','5','1');
1819 else if (rate == 50) tag = MKTAG('x','d','5','a');
1820 else if (rate == 60) tag = MKTAG('x','d','5','9');
1821 }
1822 } else if (track->par->width == 1920 && track->par->height == 1080) {
1823 if (!interlaced) {
1824 if (rate == 24) tag = MKTAG('x','d','5','d');
1825 else if (rate == 25) tag = MKTAG('x','d','5','e');
1826 else if (rate == 30) tag = MKTAG('x','d','5','f');
1827 } else {
1828 if (rate == 25) tag = MKTAG('x','d','5','c');
1829 else if (rate == 30) tag = MKTAG('x','d','5','b');
1830 }
1831 }
1832 }
1833
1834 1 return tag;
1835 }
1836
1837 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1838 {
1839 2 int tag = track->par->codec_tag;
1840 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1841 2 AVStream *st = track->st;
1842 2 int rate = defined_frame_rate(s, st);
1843
1844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1845 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1846
1847
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1848 if (track->par->width == 960 && track->par->height == 720) {
1849 if (!interlaced) {
1850 if (rate == 24) tag = MKTAG('a','i','5','p');
1851 else if (rate == 25) tag = MKTAG('a','i','5','q');
1852 else if (rate == 30) tag = MKTAG('a','i','5','p');
1853 else if (rate == 50) tag = MKTAG('a','i','5','q');
1854 else if (rate == 60) tag = MKTAG('a','i','5','p');
1855 }
1856 } else if (track->par->width == 1440 && track->par->height == 1080) {
1857 if (!interlaced) {
1858 if (rate == 24) tag = MKTAG('a','i','5','3');
1859 else if (rate == 25) tag = MKTAG('a','i','5','2');
1860 else if (rate == 30) tag = MKTAG('a','i','5','3');
1861 } else {
1862 if (rate == 50) tag = MKTAG('a','i','5','5');
1863 else if (rate == 60) tag = MKTAG('a','i','5','6');
1864 }
1865 }
1866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1867 if (track->par->width == 1280 && track->par->height == 720) {
1868 if (!interlaced) {
1869 if (rate == 24) tag = MKTAG('a','i','1','p');
1870 else if (rate == 25) tag = MKTAG('a','i','1','q');
1871 else if (rate == 30) tag = MKTAG('a','i','1','p');
1872 else if (rate == 50) tag = MKTAG('a','i','1','q');
1873 else if (rate == 60) tag = MKTAG('a','i','1','p');
1874 }
1875 } else if (track->par->width == 1920 && track->par->height == 1080) {
1876 if (!interlaced) {
1877 if (rate == 24) tag = MKTAG('a','i','1','3');
1878 else if (rate == 25) tag = MKTAG('a','i','1','2');
1879 else if (rate == 30) tag = MKTAG('a','i','1','3');
1880 } else {
1881 if (rate == 25) tag = MKTAG('a','i','1','5');
1882 else if (rate == 50) tag = MKTAG('a','i','1','5');
1883 else if (rate == 60) tag = MKTAG('a','i','1','6');
1884 }
1885 } else if ( track->par->width == 4096 && track->par->height == 2160
1886 || track->par->width == 3840 && track->par->height == 2160
1887 || track->par->width == 2048 && track->par->height == 1080) {
1888 tag = MKTAG('a','i','v','x');
1889 }
1890 }
1891
1892 2 return tag;
1893 }
1894
1895 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1896 {
1897 int tag = track->par->codec_tag;
1898
1899 if (!tag)
1900 tag = MKTAG('e', 'v', 'c', '1');
1901
1902 return tag;
1903 }
1904
1905 static const struct {
1906 enum AVPixelFormat pix_fmt;
1907 uint32_t tag;
1908 unsigned bps;
1909 } mov_pix_fmt_tags[] = {
1910 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1911 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1912 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1913 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
1914 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
1915 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
1916 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1917 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1918 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1919 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1920 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1921 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1922 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1923 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1924 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1925 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1926 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1927 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1928 };
1929
1930 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1931 {
1932 23 int tag = MKTAG('A','V','d','n');
1933
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1934
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1935 12 tag = MKTAG('A','V','d','h');
1936 23 return tag;
1937 }
1938
1939 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1940 {
1941 17 int tag = track->par->codec_tag;
1942 int i;
1943 enum AVPixelFormat pix_fmt;
1944
1945
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 12 times.
264 for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
1946
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1947 17 tag = mov_pix_fmt_tags[i].tag;
1948 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1949
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
1950 5 break;
1951 }
1952 }
1953
1954 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
1955 17 track->par->bits_per_coded_sample);
1956
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
1957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
1958 track->par->format != AV_PIX_FMT_GRAY8 &&
1959 track->par->format != AV_PIX_FMT_NONE)
1960 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
1961 av_get_pix_fmt_name(track->par->format));
1962 17 return tag;
1963 }
1964
1965 167 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
1966 {
1967 167 unsigned int tag = track->par->codec_tag;
1968
1969 // "rtp " is used to distinguish internally created RTP-hint tracks
1970 // (with rtp_ctx) from other tracks.
1971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (tag == MKTAG('r','t','p',' '))
1972 tag = 0;
1973
3/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✓ Branch 3 taken 36 times.
167 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
1974
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 1 times.
131 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
1975
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 17 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
1976
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 track->par->codec_id == AV_CODEC_ID_H263 ||
1977
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2 times.
113 track->par->codec_id == AV_CODEC_ID_H264 ||
1978
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 23 times.
111 track->par->codec_id == AV_CODEC_ID_DNXHD ||
1979
4/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 69 times.
175 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
1980 87 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
1981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
1982 1 tag = mov_get_dv_codec_tag(s, track);
1983
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
1984 17 tag = mov_get_rawvideo_codec_tag(s, track);
1985
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
1986 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
1987
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
1988 2 tag = mov_get_h264_codec_tag(s, track);
1989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
1990 tag = mov_get_evc_codec_tag(s, track);
1991
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
1992 23 tag = mov_get_dnxhd_codec_tag(s, track);
1993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
1994 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
1995 if (!tag) { // if no mac fcc found, try with Microsoft tags
1996 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
1997 if (tag)
1998 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
1999 "the file may be unplayable!\n");
2000 }
2001
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2002 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2003
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2004 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2005 if (ms_tag) {
2006 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2007 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2008 "the file may be unplayable!\n");
2009 }
2010 }
2011 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2012 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2013 }
2014
2015 167 return tag;
2016 }
2017
2018 static const AVCodecTag codec_cover_image_tags[] = {
2019 { AV_CODEC_ID_MJPEG, 0xD },
2020 { AV_CODEC_ID_PNG, 0xE },
2021 { AV_CODEC_ID_BMP, 0x1B },
2022 { AV_CODEC_ID_NONE, 0 },
2023 };
2024
2025 97 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2026 unsigned int tag, int codec_id)
2027 {
2028 int i;
2029
2030 /**
2031 * Check that tag + id is in the table
2032 */
2033
2/4
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97 times.
✗ Branch 3 not taken.
97 for (i = 0; tags && tags[i]; i++) {
2034 97 const AVCodecTag *codec_tags = tags[i];
2035
1/2
✓ Branch 0 taken 1353 times.
✗ Branch 1 not taken.
1353 while (codec_tags->id != AV_CODEC_ID_NONE) {
2036
2/2
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 1239 times.
1353 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2037
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 17 times.
114 codec_tags->id == codec_id)
2038 97 return codec_tags->tag;
2039 1256 codec_tags++;
2040 }
2041 }
2042 return 0;
2043 }
2044
2045 266 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2046 {
2047
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 264 times.
266 if (is_cover_image(track->st))
2048 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2049
2050
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 263 times.
264 if (track->mode == MODE_IPOD)
2051
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 if (!av_match_ext(s->url, "m4a") &&
2052
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2053 1 !av_match_ext(s->url, "m4b"))
2054 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2055 "Quicktime/Ipod might not play the file\n");
2056
2057
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 97 times.
264 if (track->mode == MODE_MOV) {
2058 167 return mov_get_codec_tag(s, track);
2059 } else
2060 97 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2061 97 track->par->codec_id);
2062 }
2063
2064 /** Write uuid atom.
2065 * Needed to make file play in iPods running newest firmware
2066 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2067 */
2068 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2069 {
2070 avio_wb32(pb, 28);
2071 ffio_wfourcc(pb, "uuid");
2072 avio_wb32(pb, 0x6b6840f2);
2073 avio_wb32(pb, 0x5f244fc5);
2074 avio_wb32(pb, 0xba39a51b);
2075 avio_wb32(pb, 0xcf0323f3);
2076 avio_wb32(pb, 0x0);
2077 return 28;
2078 }
2079
2080 static const uint16_t fiel_data[] = {
2081 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2082 };
2083
2084 97 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2085 {
2086 97 unsigned mov_field_order = 0;
2087
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2088 97 mov_field_order = fiel_data[field_order];
2089 else
2090 return 0;
2091 97 avio_wb32(pb, 10);
2092 97 ffio_wfourcc(pb, "fiel");
2093 97 avio_wb16(pb, mov_field_order);
2094 97 return 10;
2095 }
2096
2097 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2098 {
2099 4 MOVMuxContext *mov = s->priv_data;
2100 4 int ret = AVERROR_BUG;
2101 4 int64_t pos = avio_tell(pb);
2102 4 avio_wb32(pb, 0); /* size */
2103 4 avio_wl32(pb, track->tag); // store it byteswapped
2104 4 avio_wb32(pb, 0); /* Reserved */
2105 4 avio_wb16(pb, 0); /* Reserved */
2106 4 avio_wb16(pb, 1); /* Data-reference index */
2107
2108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2109 mov_write_esds_tag(pb, track);
2110
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2111
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
2112 1 case MOV_ISMV_TTML_TAG:
2113 // ISMV dfxp requires no extradata.
2114 2 break;
2115 1 case MOV_MP4_TTML_TAG:
2116 // As specified in 14496-30, XMLSubtitleSampleEntry
2117 // Namespace
2118 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2119 // Empty schema_location
2120 1 avio_w8(pb, 0);
2121 // Empty auxiliary_mime_types
2122 1 avio_w8(pb, 0);
2123 1 break;
2124 default:
2125 av_log(NULL, AV_LOG_ERROR,
2126 "Unknown codec tag '%s' utilized for TTML stream with "
2127 "index %d (track id %d)!\n",
2128 av_fourcc2str(track->par->codec_tag), track->st->index,
2129 track->track_id);
2130 return AVERROR(EINVAL);
2131 }
2132
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->par->extradata_size)
2133 2 avio_write(pb, track->par->extradata, track->par->extradata_size);
2134
2135
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
8 if (mov->write_btrt &&
2136 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2137 return ret;
2138
2139 4 return update_size(pb, pos);
2140 }
2141
2142 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2143 {
2144 int8_t stereo_mode;
2145
2146 if (stereo_3d->flags != 0) {
2147 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2148 return 0;
2149 }
2150
2151 switch (stereo_3d->type) {
2152 case AV_STEREO3D_2D:
2153 stereo_mode = 0;
2154 break;
2155 case AV_STEREO3D_TOPBOTTOM:
2156 stereo_mode = 1;
2157 break;
2158 case AV_STEREO3D_SIDEBYSIDE:
2159 stereo_mode = 2;
2160 break;
2161 default:
2162 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2163 return 0;
2164 }
2165 avio_wb32(pb, 13); /* size */
2166 ffio_wfourcc(pb, "st3d");
2167 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2168 avio_w8(pb, stereo_mode);
2169 return 13;
2170 }
2171
2172 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2173 {
2174 int64_t sv3d_pos, svhd_pos, proj_pos;
2175 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2176
2177 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2178 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2179 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2180 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2181 return 0;
2182 }
2183
2184 sv3d_pos = avio_tell(pb);
2185 avio_wb32(pb, 0); /* size */
2186 ffio_wfourcc(pb, "sv3d");
2187
2188 svhd_pos = avio_tell(pb);
2189 avio_wb32(pb, 0); /* size */
2190 ffio_wfourcc(pb, "svhd");
2191 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2192 avio_put_str(pb, metadata_source);
2193 update_size(pb, svhd_pos);
2194
2195 proj_pos = avio_tell(pb);
2196 avio_wb32(pb, 0); /* size */
2197 ffio_wfourcc(pb, "proj");
2198
2199 avio_wb32(pb, 24); /* size */
2200 ffio_wfourcc(pb, "prhd");
2201 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2202 avio_wb32(pb, spherical_mapping->yaw);
2203 avio_wb32(pb, spherical_mapping->pitch);
2204 avio_wb32(pb, spherical_mapping->roll);
2205
2206 switch (spherical_mapping->projection) {
2207 case AV_SPHERICAL_EQUIRECTANGULAR:
2208 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2209 avio_wb32(pb, 28); /* size */
2210 ffio_wfourcc(pb, "equi");
2211 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2212 avio_wb32(pb, spherical_mapping->bound_top);
2213 avio_wb32(pb, spherical_mapping->bound_bottom);
2214 avio_wb32(pb, spherical_mapping->bound_left);
2215 avio_wb32(pb, spherical_mapping->bound_right);
2216 break;
2217 case AV_SPHERICAL_CUBEMAP:
2218 avio_wb32(pb, 20); /* size */
2219 ffio_wfourcc(pb, "cbmp");
2220 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2221 avio_wb32(pb, 0); /* layout */
2222 avio_wb32(pb, spherical_mapping->padding); /* padding */
2223 break;
2224 }
2225 update_size(pb, proj_pos);
2226
2227 return update_size(pb, sv3d_pos);
2228 }
2229
2230 5 static inline int64_t rescale_rational(AVRational q, int b)
2231 {
2232 5 return av_rescale(q.num, b, q.den);
2233 }
2234
2235 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2236 const AVStereo3D *stereo3d)
2237 {
2238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2239 return;
2240
2241 1 avio_wb32(pb, 12); /* size */
2242 1 ffio_wfourcc(pb, "hfov");
2243 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2244 }
2245
2246 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2247 const AVSphericalMapping *spherical_mapping)
2248 {
2249 1 avio_wb32(pb, 24); /* size */
2250 1 ffio_wfourcc(pb, "proj");
2251 1 avio_wb32(pb, 16); /* size */
2252 1 ffio_wfourcc(pb, "prji");
2253 1 avio_wb32(pb, 0); /* version + flags */
2254
2255
1/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (spherical_mapping->projection) {
2256 1 case AV_SPHERICAL_RECTILINEAR:
2257 1 ffio_wfourcc(pb, "rect");
2258 1 break;
2259 case AV_SPHERICAL_EQUIRECTANGULAR:
2260 ffio_wfourcc(pb, "equi");
2261 break;
2262 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2263 ffio_wfourcc(pb, "hequ");
2264 break;
2265 case AV_SPHERICAL_FISHEYE:
2266 ffio_wfourcc(pb, "fish");
2267 break;
2268 default:
2269 av_assert0(0);
2270 }
2271 1 }
2272
2273 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2274 const AVStereo3D *stereo3d)
2275 {
2276 1 int64_t pos = avio_tell(pb);
2277 1 int view = 0;
2278
2279 1 avio_wb32(pb, 0); /* size */
2280 1 ffio_wfourcc(pb, "eyes");
2281
2282 // stri is mandatory
2283 1 avio_wb32(pb, 13); /* size */
2284 1 ffio_wfourcc(pb, "stri");
2285 1 avio_wb32(pb, 0); /* version + flags */
2286
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2287 case AV_STEREO3D_VIEW_LEFT:
2288 view |= 1 << 0;
2289 break;
2290 case AV_STEREO3D_VIEW_RIGHT:
2291 view |= 1 << 1;
2292 break;
2293 1 case AV_STEREO3D_VIEW_PACKED:
2294 1 view |= (1 << 0) | (1 << 1);
2295 1 break;
2296 }
2297 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2298 1 avio_w8(pb, view);
2299
2300 // hero is optional
2301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2302 avio_wb32(pb, 13); /* size */
2303 ffio_wfourcc(pb, "hero");
2304 avio_wb32(pb, 0); /* version + flags */
2305 avio_w8(pb, stereo3d->primary_eye);
2306 }
2307
2308 // it's not clear if cams is mandatory or optional
2309
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2310 1 avio_wb32(pb, 24); /* size */
2311 1 ffio_wfourcc(pb, "cams");
2312 1 avio_wb32(pb, 16); /* size */
2313 1 ffio_wfourcc(pb, "blin");
2314 1 avio_wb32(pb, 0); /* version + flags */
2315 1 avio_wb32(pb, stereo3d->baseline);
2316 }
2317
2318 // it's not clear if cmfy is mandatory or optional
2319
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2320 1 avio_wb32(pb, 24); /* size */
2321 1 ffio_wfourcc(pb, "cmfy");
2322 1 avio_wb32(pb, 16); /* size */
2323 1 ffio_wfourcc(pb, "dadj");
2324 1 avio_wb32(pb, 0); /* version + flags */
2325 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2326 }
2327
2328 1 return update_size(pb, pos);
2329 }
2330
2331 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2332 const AVStereo3D *stereo3d,
2333 const AVSphericalMapping *spherical_mapping)
2334 {
2335 int64_t pos;
2336
2337
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2339 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2340 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2341 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2342 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2343 spherical_mapping->projection);
2344 spherical_mapping = NULL;
2345 }
2346
2347
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2348
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2350 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2351 !stereo3d->baseline &&
2352 !stereo3d->horizontal_disparity_adjustment.num))) {
2353 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2354 stereo3d = NULL;
2355 }
2356
2357
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2358 return 0;
2359
2360 1 pos = avio_tell(pb);
2361 1 avio_wb32(pb, 0); /* size */
2362 1 ffio_wfourcc(pb, "vexu");
2363
2364
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2365 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2366
2367
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2368 1 mov_write_eyes_tag(s, pb, stereo3d);
2369
2370 1 return update_size(pb, pos);
2371 }
2372
2373 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2374 {
2375 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2376
2377 avio_wb32(pb, 32); /* size = 8 + 24 */
2378 if (dovi->dv_profile > 10)
2379 ffio_wfourcc(pb, "dvwC");
2380 else if (dovi->dv_profile > 7)
2381 ffio_wfourcc(pb, "dvvC");
2382 else
2383 ffio_wfourcc(pb, "dvcC");
2384
2385 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2386 avio_write(pb, buf, sizeof(buf));
2387
2388 return 32; /* 8 + 24 */
2389 }
2390
2391 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2392 uint32_t top, uint32_t bottom,
2393 uint32_t left, uint32_t right)
2394 {
2395 5 uint32_t cropped_width = track->par->width - left - right;
2396 5 uint32_t cropped_height = track->height - top - bottom;
2397 AVRational horizOff =
2398 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2399 5 (AVRational) { left, 1 });
2400 AVRational vertOff =
2401 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2402 5 (AVRational) { top, 1 });
2403
2404 5 avio_wb32(pb, 40);
2405 5 ffio_wfourcc(pb, "clap");
2406 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2407 5 avio_wb32(pb, 1); /* apertureWidthD */
2408 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2409 5 avio_wb32(pb, 1); /* apertureHeightD */
2410
2411 5 avio_wb32(pb, -horizOff.num);
2412 5 avio_wb32(pb, horizOff.den);
2413 5 avio_wb32(pb, -vertOff.num);
2414 5 avio_wb32(pb, vertOff.den);
2415
2416 5 return 40;
2417 }
2418
2419 8 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2420 {
2421 AVRational sar;
2422 8 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2423 8 track->par->sample_aspect_ratio.den, INT_MAX);
2424
2425 8 avio_wb32(pb, 16);
2426 8 ffio_wfourcc(pb, "pasp");
2427 8 avio_wb32(pb, sar.num);
2428 8 avio_wb32(pb, sar.den);
2429 8 return 16;
2430 }
2431
2432 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2433 {
2434 uint32_t gama = 0;
2435 if (gamma <= 0.0)
2436 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2437 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2438
2439 if (gamma > 1e-6) {
2440 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2441 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2442
2443 av_assert0(track->mode == MODE_MOV);
2444 avio_wb32(pb, 12);
2445 ffio_wfourcc(pb, "gama");
2446 avio_wb32(pb, gama);
2447 return 12;
2448 } else {
2449 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2450 }
2451 return 0;
2452 }
2453
2454 9 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2455 {
2456 9 int64_t pos = avio_tell(pb);
2457
2458 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2459 // Ref (MP4): ISO/IEC 14496-12:2012
2460
2461
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (prefer_icc) {
2462 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2463 4 track->st->codecpar->nb_coded_side_data,
2464 AV_PKT_DATA_ICC_PROFILE);
2465
2466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2467 avio_wb32(pb, 12 + sd->size);
2468 ffio_wfourcc(pb, "colr");
2469 ffio_wfourcc(pb, "prof");
2470 avio_write(pb, sd->data, sd->size);
2471 return 12 + sd->size;
2472 }
2473 else {
2474 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2475 }
2476 }
2477
2478 /* We should only ever be called for MOV, MP4 and AVIF. */
2479
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2480 track->mode == MODE_AVIF);
2481
2482 9 avio_wb32(pb, 0); /* size */
2483 9 ffio_wfourcc(pb, "colr");
2484
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2485 1 ffio_wfourcc(pb, "nclx");
2486 else
2487 8 ffio_wfourcc(pb, "nclc");
2488 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2489 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2490 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2491 9 avio_wb16(pb, track->par->color_primaries);
2492 9 avio_wb16(pb, track->par->color_trc);
2493 9 avio_wb16(pb, track->par->color_space);
2494
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2495 1 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2496 1 avio_w8(pb, full_range << 7);
2497 }
2498
2499 9 return update_size(pb, pos);
2500 }
2501
2502 204 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2503 {
2504 const AVPacketSideData *side_data;
2505 const AVContentLightMetadata *content_light_metadata;
2506
2507 204 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2508 204 track->st->codecpar->nb_coded_side_data,
2509 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2510
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 if (!side_data) {
2511 204 return 0;
2512 }
2513 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2514
2515 avio_wb32(pb, 12); // size
2516 ffio_wfourcc(pb, "clli");
2517 avio_wb16(pb, content_light_metadata->MaxCLL);
2518 avio_wb16(pb, content_light_metadata->MaxFALL);
2519 return 12;
2520 }
2521
2522 204 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2523 {
2524 204 const int chroma_den = 50000;
2525 204 const int luma_den = 10000;
2526 const AVPacketSideData *side_data;
2527 204 const AVMasteringDisplayMetadata *metadata = NULL;
2528
2529 204 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2530 204 track->st->codecpar->nb_coded_side_data,
2531 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 if (side_data)
2533 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2534
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
204 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2535 204 return 0;
2536 }
2537
2538 avio_wb32(pb, 32); // size
2539 ffio_wfourcc(pb, "mdcv");
2540 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2541 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2542 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2543 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2544 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2545 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2546 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2547 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2548 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2549 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2550 return 32;
2551 }
2552
2553 204 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2554 {
2555 204 const int illuminance_den = 10000;
2556 204 const int ambient_den = 50000;
2557 const AVPacketSideData *side_data;
2558 const AVAmbientViewingEnvironment *ambient;
2559
2560
2561 204 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2562 204 track->st->codecpar->nb_coded_side_data,
2563 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2564
2565
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 1 times.
204 if (!side_data)
2566 203 return 0;
2567
2568 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2569
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ambient || !ambient->ambient_illuminance.num)
2570 return 0;
2571
2572 1 avio_wb32(pb, 16); // size
2573 1 ffio_wfourcc(pb, "amve");
2574 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2575 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2576 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2577 1 return 16;
2578 }
2579
2580 209 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2581 {
2582 AVDictionaryEntry *encoder;
2583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2584
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
208 || (track->par->width == 1440 && track->par->height == 1080)
2585
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 195 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
418 || (track->par->width == 1920 && track->par->height == 1080);
2586
2587
1/2
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
209 if ((track->mode == MODE_AVIF ||
2588
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 140 times.
209 track->mode == MODE_MOV ||
2589
4/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 149 times.
✓ Branch 3 taken 55 times.
273 track->mode == MODE_MP4) &&
2590 204 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2591 149 av_strlcpy(compressor_name, encoder->value, 32);
2592
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2593 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2594 AVStream *st = track->st;
2595 int rate = defined_frame_rate(NULL, st);
2596 av_strlcatf(compressor_name, len, "XDCAM");
2597 if (track->par->format == AV_PIX_FMT_YUV422P) {
2598 av_strlcatf(compressor_name, len, " HD422");
2599 } else if(track->par->width == 1440) {
2600 av_strlcatf(compressor_name, len, " HD");
2601 } else
2602 av_strlcatf(compressor_name, len, " EX");
2603
2604 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2605
2606 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2607 }
2608 209 }
2609
2610 static int mov_write_ccst_tag(AVIOContext *pb)
2611 {
2612 int64_t pos = avio_tell(pb);
2613 // Write sane defaults:
2614 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2615 // intra_pred_used = 1 : intra prediction may or may not be used.
2616 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2617 // reference images can be used.
2618 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2619 (1 << 6) | /* intra_pred_used */
2620 (15 << 2); /* max_ref_per_pic */
2621 avio_wb32(pb, 0); /* size */
2622 ffio_wfourcc(pb, "ccst");
2623 avio_wb32(pb, 0); /* Version & flags */
2624 avio_w8(pb, ccstValue);
2625 avio_wb24(pb, 0); /* reserved */
2626 return update_size(pb, pos);
2627 }
2628
2629 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2630 {
2631 int64_t pos = avio_tell(pb);
2632 avio_wb32(pb, 0); /* size */
2633 ffio_wfourcc(pb, aux_type);
2634 avio_wb32(pb, 0); /* Version & flags */
2635 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2636 return update_size(pb, pos);
2637 }
2638
2639 209 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2640 {
2641 209 int ret = AVERROR_BUG;
2642 209 int64_t pos = avio_tell(pb);
2643 const AVPacketSideData *sd;
2644 209 char compressor_name[32] = { 0 };
2645 209 int avid = 0;
2646
2647
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422)
2648
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
209 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2649
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
209 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2650
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
209 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2651
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
209 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2652 #if FF_API_V408_CODECID
2653
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 || track->par->codec_id == AV_CODEC_ID_V308
2654
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 || track->par->codec_id == AV_CODEC_ID_V408
2655
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 || track->par->codec_id == AV_CODEC_ID_V410
2656 #endif
2657
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 205 times.
418 || track->par->codec_id == AV_CODEC_ID_V210);
2658
2659 209 avio_wb32(pb, 0); /* size */
2660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->encryption_scheme != MOV_ENC_NONE) {
2661 ffio_wfourcc(pb, "encv");
2662 } else {
2663 209 avio_wl32(pb, track->tag); // store it byteswapped
2664 }
2665 209 avio_wb32(pb, 0); /* Reserved */
2666 209 avio_wb16(pb, 0); /* Reserved */
2667 209 avio_wb16(pb, 1); /* Data-reference index */
2668
2669
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (uncompressed_ycbcr) {
2670 4 avio_wb16(pb, 2); /* Codec stream version */
2671 } else {
2672 205 avio_wb16(pb, 0); /* Codec stream version */
2673 }
2674 209 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2675
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 69 times.
209 if (track->mode == MODE_MOV) {
2676 140 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2677
3/4
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
140 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2678 17 avio_wb32(pb, 0); /* Temporal Quality */
2679 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2680 } else {
2681 123 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2682 123 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2683 }
2684 } else {
2685 69 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2686 }
2687 209 avio_wb16(pb, track->par->width); /* Video width */
2688 209 avio_wb16(pb, track->height); /* Video height */
2689 209 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2690 209 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2691 209 avio_wb32(pb, 0); /* Data size (= 0) */
2692 209 avio_wb16(pb, 1); /* Frame count (= 1) */
2693
2694 209 find_compressor(compressor_name, 32, track);
2695 209 avio_w8(pb, strlen(compressor_name));
2696 209 avio_write(pb, compressor_name, 31);
2697
2698
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 69 times.
209 if (track->mode == MODE_MOV &&
2699
2/4
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 140 times.
140 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2700 avio_wb16(pb, 0x18);
2701
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 107 times.
209 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2702 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2703
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2704 else
2705 176 avio_wb16(pb, 0x18); /* Reserved */
2706
2707
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 135 times.
214 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2708 int pal_size, i;
2709 5 avio_wb16(pb, 0); /* Color table ID */
2710 5 avio_wb32(pb, 0); /* Color table seed */
2711 5 avio_wb16(pb, 0x8000); /* Color table flags */
2712
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (track->par->bits_per_coded_sample < 0 || track->par->bits_per_coded_sample > 8)
2713 return AVERROR(EINVAL);
2714 5 pal_size = 1 << track->par->bits_per_coded_sample;
2715 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2716
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2717 1040 uint32_t rgb = track->palette[i];
2718 1040 uint16_t r = (rgb >> 16) & 0xff;
2719 1040 uint16_t g = (rgb >> 8) & 0xff;
2720 1040 uint16_t b = rgb & 0xff;
2721 1040 avio_wb16(pb, 0);
2722 1040 avio_wb16(pb, (r << 8) | r);
2723 1040 avio_wb16(pb, (g << 8) | g);
2724 1040 avio_wb16(pb, (b << 8) | b);
2725 }
2726 } else
2727 204 avio_wb16(pb, 0xffff); /* Reserved */
2728
2729
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 182 times.
209 if (track->tag == MKTAG('m','p','4','v'))
2730 27 mov_write_esds_tag(pb, track);
2731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
182 else if (track->par->codec_id == AV_CODEC_ID_H263)
2732 mov_write_d263_tag(pb);
2733
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 3 times.
182 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 179 times.
179 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2735 3 mov_write_extradata_tag(pb, track);
2736 3 avio_wb32(pb, 0);
2737
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 156 times.
179 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2738 23 mov_write_avid_tag(pb, track);
2739 23 avid = 1;
2740
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 153 times.
156 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2741 3 mov_write_hvcc_tag(mov->fc, pb, track);
2742
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2743 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2744
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2745 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2746 }
2747
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 152 times.
153 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2748 1 mov_write_vvcc_tag(pb, track);
2749
16/30
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 99 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 53 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 53 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 53 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 53 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 53 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 53 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 53 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 53 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 53 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 53 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 53 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 53 times.
✗ Branch 29 not taken.
152 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2750 53 mov_write_avcc_tag(pb, track);
2751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (track->mode == MODE_IPOD)
2752 mov_write_uuid_tag_ipod(pb);
2753 }
2754
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 98 times.
99 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2755 1 mov_write_evcc_tag(pb, track);
2756
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2757 mov_write_vpcc_tag(mov->fc, pb, track);
2758
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2759 1 mov_write_av1c_tag(pb, track);
2760
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
97 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
2761 mov_write_dvc1_tag(pb, track);
2762
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2763
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2764 /* Don't write any potential extradata here - the cropping
2765 * is signalled via the normal width/height fields. */
2766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2767 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2768 mov_write_dpxe_tag(pb, track);
2769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2770 mov_write_av3c_tag(pb, track);
2771
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->vos_len > 0)
2772 4 mov_write_glbl_tag(pb, track);
2773
2774
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 53 times.
209 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2775
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 25 times.
156 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2776
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 23 times.
131 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2777 108 int field_order = track->par->field_order;
2778
2779
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 11 times.
108 if (field_order != AV_FIELD_UNKNOWN)
2780 97 mov_write_fiel_tag(pb, track, field_order);
2781 }
2782
2783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2784 if (track->mode == MODE_MOV)
2785 mov_write_gama_tag(s, pb, track, mov->gamma);
2786 else
2787 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2788 }
2789
5/6
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
413 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2790 413 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2791
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
209 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2792
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2793
5/6
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 195 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 195 times.
399 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2794 195 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2795 AV_PKT_DATA_ICC_PROFILE)) {
2796
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
9 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2797 9 mov_write_colr_tag(pb, track, prefer_icc);
2798 }
2799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2800 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2801 }
2802
2803
4/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 5 times.
209 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2804 204 mov_write_clli_tag(pb, track);
2805 204 mov_write_mdcv_tag(pb, track);
2806 204 mov_write_amve_tag(pb, track);
2807 }
2808
2809
3/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
209 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2810 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2811 track->st->codecpar->nb_coded_side_data,
2812 AV_PKT_DATA_STEREO3D);
2813 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2814 track->st->codecpar->nb_coded_side_data,
2815 AV_PKT_DATA_SPHERICAL);
2816 if (stereo_3d)
2817 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2818 if (spherical_mapping)
2819 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2820 }
2821
2822
4/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 5 times.
209 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2824 140 const AVStereo3D *stereo3d = NULL;
2825 140 const AVSphericalMapping *spherical_mapping = NULL;
2826
2827 140 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2828 140 track->st->codecpar->nb_coded_side_data,
2829 AV_PKT_DATA_STEREO3D);
2830
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (sd)
2831 1 stereo3d = (AVStereo3D *)sd->data;
2832
2833 140 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2834 140 track->st->codecpar->nb_coded_side_data,
2835 AV_PKT_DATA_SPHERICAL);
2836
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (sd)
2837 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2838
2839
3/4
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
140 if (stereo3d || spherical_mapping)
2840 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2841
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (stereo3d)
2842 1 mov_write_hfov_tag(s, pb, stereo3d);
2843 }
2844
2845
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 145 times.
209 if (track->mode == MODE_MP4) {
2846 64 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2847 64 track->st->codecpar->nb_coded_side_data,
2848 AV_PKT_DATA_DOVI_CONF);
2849
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
64 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2850 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 } else if (dovi) {
2852 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2853 }
2854 }
2855
2856
3/4
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 201 times.
209 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2857 8 mov_write_pasp_tag(pb, track);
2858 }
2859
2860 209 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2861 209 track->st->codecpar->nb_coded_side_data,
2862 AV_PKT_DATA_FRAME_CROPPING);
2863
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
210 if (sd && sd->size >= sizeof(uint32_t) * 4) {
2864 1 uint64_t top = AV_RL32(sd->data + 0);
2865 1 uint64_t bottom = AV_RL32(sd->data + 4);
2866 1 uint64_t left = AV_RL32(sd->data + 8);
2867 1 uint64_t right = AV_RL32(sd->data + 12);
2868
2869
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2871 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2872 return AVERROR(EINVAL);
2873 }
2874
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (top || bottom || left || right)
2875 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2876
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 204 times.
208 } else if (uncompressed_ycbcr)
2877 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2878
2879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->encryption_scheme != MOV_ENC_NONE) {
2880 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2881 }
2882
2883
3/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
273 if (mov->write_btrt &&
2884 64 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2885 return ret;
2886
2887 /* extra padding for avid stsd */
2888 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2889
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 186 times.
209 if (avid)
2890 23 avio_wb32(pb, 0);
2891
2892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (track->mode == MODE_AVIF) {
2893 mov_write_ccst_tag(pb);
2894 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2895 mov_write_aux_tag(pb, "auxi");
2896 }
2897
2898 209 return update_size(pb, pos);
2899 }
2900
2901 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2902 {
2903 2 int64_t pos = avio_tell(pb);
2904 2 avio_wb32(pb, 0); /* size */
2905 2 ffio_wfourcc(pb, "rtp ");
2906 2 avio_wb32(pb, 0); /* Reserved */
2907 2 avio_wb16(pb, 0); /* Reserved */
2908 2 avio_wb16(pb, 1); /* Data-reference index */
2909
2910 2 avio_wb16(pb, 1); /* Hint track version */
2911 2 avio_wb16(pb, 1); /* Highest compatible version */
2912 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2913
2914 2 avio_wb32(pb, 12); /* size */
2915 2 ffio_wfourcc(pb, "tims");
2916 2 avio_wb32(pb, track->timescale);
2917
2918 2 return update_size(pb, pos);
2919 }
2920
2921 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2922 {
2923 2 uint64_t str_size =strlen(reel_name);
2924 2 int64_t pos = avio_tell(pb);
2925
2926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2927 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2928 avio_wb16(pb, 0);
2929 return AVERROR(EINVAL);
2930 }
2931
2932 2 avio_wb32(pb, 0); /* size */
2933 2 ffio_wfourcc(pb, "name"); /* Data format */
2934 2 avio_wb16(pb, str_size); /* string size */
2935 2 avio_wb16(pb, track->language); /* langcode */
2936 2 avio_write(pb, reel_name, str_size); /* reel name */
2937 2 return update_size(pb,pos);
2938 }
2939
2940 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2941 {
2942 13 int64_t pos = avio_tell(pb);
2943 #if 1
2944 int frame_duration;
2945 int nb_frames;
2946 13 AVDictionaryEntry *t = NULL;
2947
2948
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 if (!track->st->avg_frame_rate.num || !track->st->avg_frame_rate.den) {
2949 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
2950 return AVERROR(EINVAL);
2951 } else {
2952 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
2953
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 nb_frames = ROUNDED_DIV(track->st->avg_frame_rate.num, track->st->avg_frame_rate.den);
2954 }
2955
2956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
2957 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
2958 return AVERROR(EINVAL);
2959 }
2960
2961 13 avio_wb32(pb, 0); /* size */
2962 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
2963 13 avio_wb32(pb, 0); /* Reserved */
2964 13 avio_wb32(pb, 1); /* Data reference index */
2965 13 avio_wb32(pb, 0); /* Flags */
2966 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
2967 13 avio_wb32(pb, track->timescale); /* Timescale */
2968 13 avio_wb32(pb, frame_duration); /* Frame duration */
2969 13 avio_w8(pb, nb_frames); /* Number of frames */
2970 13 avio_w8(pb, 0); /* Reserved */
2971
2972 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
2973
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
13 if (t && utf8len(t->value) && track->mode != MODE_MP4)
2974 2 mov_write_source_reference_tag(pb, track, t->value);
2975 else
2976 11 avio_wb16(pb, 0); /* zero size */
2977 #else
2978
2979 avio_wb32(pb, 0); /* size */
2980 ffio_wfourcc(pb, "tmcd"); /* Data format */
2981 avio_wb32(pb, 0); /* Reserved */
2982 avio_wb32(pb, 1); /* Data reference index */
2983 if (track->par->extradata_size)
2984 avio_write(pb, track->par->extradata, track->par->extradata_size);
2985 #endif
2986 13 return update_size(pb, pos);
2987 }
2988
2989 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
2990 {
2991 1 int64_t pos = avio_tell(pb);
2992 1 avio_wb32(pb, 0); /* size */
2993 1 ffio_wfourcc(pb, "gpmd");
2994 1 avio_wb32(pb, 0); /* Reserved */
2995 1 avio_wb16(pb, 0); /* Reserved */
2996 1 avio_wb16(pb, 1); /* Data-reference index */
2997 1 avio_wb32(pb, 0); /* Reserved */
2998 1 return update_size(pb, pos);
2999 }
3000
3001 339 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3002 {
3003 339 int64_t pos = avio_tell(pb);
3004 339 int ret = 0;
3005 339 avio_wb32(pb, 0); /* size */
3006 339 ffio_wfourcc(pb, "stsd");
3007 339 avio_wb32(pb, 0); /* version & flags */
3008 339 avio_wb32(pb, 1); /* entry count */
3009
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 130 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3010 209 ret = mov_write_video_tag(s, pb, mov, track);
3011
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 20 times.
130 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3012 110 ret = mov_write_audio_tag(s, pb, mov, track);
3013
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3014 4 ret = mov_write_subtitle_tag(s, pb, track);
3015
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3016 2 ret = mov_write_rtp_tag(pb, track);
3017
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3018 13 ret = mov_write_tmcd_tag(pb, track);
3019
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3020 1 ret = mov_write_gpmd_tag(pb, track);
3021
3022
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
339 if (ret < 0)
3023 return ret;
3024
3025 339 return update_size(pb, pos);
3026 }
3027
3028 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3029 {
3030 9 MOVMuxContext *mov = s->priv_data;
3031 MOVCtts *ctts_entries;
3032 9 uint32_t entries = 0;
3033 uint32_t atom_size;
3034 int i;
3035
3036 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3038 return AVERROR(ENOMEM);
3039 9 ctts_entries[0].count = 1;
3040 9 ctts_entries[0].offset = track->cluster[0].cts;
3041
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3042
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3043 130 ctts_entries[entries].count++; /* compress */
3044 } else {
3045 421 entries++;
3046 421 ctts_entries[entries].offset = track->cluster[i].cts;
3047 421 ctts_entries[entries].count = 1;
3048 }
3049 }
3050 9 entries++; /* last one */
3051 9 atom_size = 16 + (entries * 8);
3052 9 avio_wb32(pb, atom_size); /* size */
3053 9 ffio_wfourcc(pb, "ctts");
3054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3055 avio_w8(pb, 1); /* version */
3056 else
3057 9 avio_w8(pb, 0); /* version */
3058 9 avio_wb24(pb, 0); /* flags */
3059 9 avio_wb32(pb, entries); /* entry count */
3060
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3061 430 avio_wb32(pb, ctts_entries[i].count);
3062 430 avio_wb32(pb, ctts_entries[i].offset);
3063 }
3064 9 av_free(ctts_entries);
3065 9 return atom_size;
3066 }
3067
3068 /* Time to sample atom */
3069 339 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3070 {
3071 339 MOVStts *stts_entries = NULL;
3072 339 uint32_t entries = -1;
3073 uint32_t atom_size;
3074 int i;
3075
3076
4/4
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 229 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 75 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3077 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3079 return AVERROR(ENOMEM);
3080 35 stts_entries[0].count = track->sample_count;
3081 35 stts_entries[0].duration = 1;
3082 35 entries = 1;
3083 } else {
3084
2/2
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 91 times.
304 if (track->entry) {
3085 213 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 213 times.
213 if (!stts_entries)
3087 return AVERROR(ENOMEM);
3088 }
3089
2/2
✓ Branch 0 taken 12209 times.
✓ Branch 1 taken 304 times.
12513 for (i = 0; i < track->entry; i++) {
3090 12209 int duration = get_cluster_duration(track, i);
3091 #if CONFIG_IAMFENC
3092
3/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 12159 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
12209 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3093 duration = av_rescale(duration, 48000, track->par->sample_rate);
3094 #endif
3095
4/4
✓ Branch 0 taken 11996 times.
✓ Branch 1 taken 213 times.
✓ Branch 2 taken 11593 times.
✓ Branch 3 taken 403 times.
12209 if (i && duration == stts_entries[entries].duration) {
3096 11593 stts_entries[entries].count++; /* compress */
3097 } else {
3098 616 entries++;
3099 616 stts_entries[entries].duration = duration;
3100 616 stts_entries[entries].count = 1;
3101 }
3102 }
3103 304 entries++; /* last one */
3104 }
3105 339 atom_size = 16 + (entries * 8);
3106 339 avio_wb32(pb, atom_size); /* size */
3107 339 ffio_wfourcc(pb, "stts");
3108 339 avio_wb32(pb, 0); /* version & flags */
3109 339 avio_wb32(pb, entries); /* entry count */
3110
2/2
✓ Branch 0 taken 651 times.
✓ Branch 1 taken 339 times.
990 for (i = 0; i < entries; i++) {
3111 651 avio_wb32(pb, stts_entries[i].count);
3112 651 avio_wb32(pb, stts_entries[i].duration);
3113 }
3114 339 av_free(stts_entries);
3115 339 return atom_size;
3116 }
3117
3118 339 static int mov_write_dref_tag(AVIOContext *pb)
3119 {
3120 339 avio_wb32(pb, 28); /* size */
3121 339 ffio_wfourcc(pb, "dref");
3122 339 avio_wb32(pb, 0); /* version & flags */
3123 339 avio_wb32(pb, 1); /* entry count */
3124
3125 339 avio_wb32(pb, 0xc); /* size */
3126 //FIXME add the alis and rsrc atom
3127 339 ffio_wfourcc(pb, "url ");
3128 339 avio_wb32(pb, 1); /* version & flags */
3129
3130 339 return 28;
3131 }
3132
3133 53 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3134 {
3135 struct sgpd_entry {
3136 int count;
3137 int16_t roll_distance;
3138 int group_description_index;
3139 };
3140
3141 53 struct sgpd_entry *sgpd_entries = NULL;
3142 53 int entries = -1;
3143 53 int group = 0;
3144 int i, j;
3145
3146 53 const int OPUS_SEEK_PREROLL_MS = 80;
3147 53 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3148 53 (AVRational){1, 1000},
3149 53 (AVRational){1, 48000});
3150
3151
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 12 times.
53 if (!track->entry)
3152 41 return 0;
3153
3154 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3156 return AVERROR(ENOMEM);
3157
3158
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3159
3160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3161 for (i = 0; i < track->entry; i++) {
3162 int roll_samples_remaining = roll_samples;
3163 int distance = 0;
3164 for (j = i - 1; j >= 0; j--) {
3165 roll_samples_remaining -= get_cluster_duration(track, j);
3166 distance++;
3167 if (roll_samples_remaining <= 0)
3168 break;
3169 }
3170 /* We don't have enough preceeding samples to compute a valid
3171 roll_distance here, so this sample can't be independently
3172 decoded. */
3173 if (roll_samples_remaining > 0)
3174 distance = 0;
3175 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3176 if (distance > 32)
3177 return AVERROR_INVALIDDATA;
3178 if (i && distance == sgpd_entries[entries].roll_distance) {
3179 sgpd_entries[entries].count++;
3180 } else {
3181 entries++;
3182 sgpd_entries[entries].count = 1;
3183 sgpd_entries[entries].roll_distance = distance;
3184 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3185 }
3186 }
3187 } else {
3188 12 entries++;
3189 12 sgpd_entries[entries].count = track->sample_count;
3190 12 sgpd_entries[entries].roll_distance = 1;
3191 12 sgpd_entries[entries].group_description_index = ++group;
3192 }
3193 12 entries++;
3194
3195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3196 av_free(sgpd_entries);
3197 return 0;
3198 }
3199
3200 /* Write sgpd tag */
3201 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3202 12 ffio_wfourcc(pb, "sgpd");
3203 12 avio_wb32(pb, 1 << 24); /* fullbox */
3204 12 ffio_wfourcc(pb, "roll");
3205 12 avio_wb32(pb, 2); /* default_length */
3206 12 avio_wb32(pb, group); /* entry_count */
3207
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3208
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3209 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3210 }
3211 }
3212
3213 /* Write sbgp tag */
3214 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3215 12 ffio_wfourcc(pb, "sbgp");
3216 12 avio_wb32(pb, 0); /* fullbox */
3217 12 ffio_wfourcc(pb, "roll");
3218 12 avio_wb32(pb, entries); /* entry_count */
3219
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3220 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3221 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3222 }
3223
3224 12 av_free(sgpd_entries);
3225 12 return 0;
3226 }
3227
3228 339 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3229 {
3230 339 int64_t pos = avio_tell(pb);
3231 339 int ret = 0;
3232
3233 339 avio_wb32(pb, 0); /* size */
3234 339 ffio_wfourcc(pb, "stbl");
3235
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
339 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3236 return ret;
3237 339 mov_write_stts_tag(pb, track);
3238
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 209 times.
339 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3239
1/2
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
130 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3240
1/2
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
130 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3241
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
130 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3242
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 128 times.
130 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3243
4/4
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 103 times.
211 track->has_keyframes && track->has_keyframes < track->entry)
3244 58 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3245
4/4
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 206 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable)
3246 3 mov_write_sdtp_tag(pb, track);
3247
3/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 189 times.
339 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3248 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3249
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 130 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3250
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 178 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 22 times.
209 track->flags & MOV_TRACK_CTTS && track->entry) {
3251
3252
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3253 return ret;
3254 }
3255 339 mov_write_stsc_tag(pb, track);
3256 339 mov_write_stsz_tag(pb, track);
3257 339 mov_write_stco_tag(pb, track);
3258
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
339 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3259 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3260 }
3261
3/4
✓ Branch 0 taken 339 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 286 times.
339 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3262 53 mov_preroll_write_stbl_atoms(pb, track);
3263 }
3264 339 return update_size(pb, pos);
3265 }
3266
3267 339 static int mov_write_dinf_tag(AVIOContext *pb)
3268 {
3269 339 int64_t pos = avio_tell(pb);
3270 339 avio_wb32(pb, 0); /* size */
3271 339 ffio_wfourcc(pb, "dinf");
3272 339 mov_write_dref_tag(pb);
3273 339 return update_size(pb, pos);
3274 }
3275
3276 6 static int mov_write_nmhd_tag(AVIOContext *pb)
3277 {
3278 6 avio_wb32(pb, 12);
3279 6 ffio_wfourcc(pb, "nmhd");
3280 6 avio_wb32(pb, 0);
3281 6 return 12;
3282 }
3283
3284 1 static int mov_write_sthd_tag(AVIOContext *pb)
3285 {
3286 1 avio_wb32(pb, 12);
3287 1 ffio_wfourcc(pb, "sthd");
3288 1 avio_wb32(pb, 0);
3289 1 return 12;
3290 }
3291
3292 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3293 {
3294 9 int64_t pos = avio_tell(pb);
3295 9 const char *font = "Lucida Grande";
3296 9 avio_wb32(pb, 0); /* size */
3297 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3298 9 avio_wb32(pb, 0); /* version & flags */
3299 9 avio_wb16(pb, 0); /* text font */
3300 9 avio_wb16(pb, 0); /* text face */
3301 9 avio_wb16(pb, 12); /* text size */
3302 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3303 9 avio_wb16(pb, 0x0000); /* text color (red) */
3304 9 avio_wb16(pb, 0x0000); /* text color (green) */
3305 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3306 9 avio_wb16(pb, 0xffff); /* background color (red) */
3307 9 avio_wb16(pb, 0xffff); /* background color (green) */
3308 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3309 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3310 9 avio_write(pb, font, strlen(font)); /* font name */
3311 9 return update_size(pb, pos);
3312 }
3313
3314 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3315 {
3316 11 int64_t pos = avio_tell(pb);
3317 11 avio_wb32(pb, 0); /* size */
3318 11 ffio_wfourcc(pb, "gmhd");
3319 11 avio_wb32(pb, 0x18); /* gmin size */
3320 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3321 11 avio_wb32(pb, 0); /* version & flags */
3322 11 avio_wb16(pb, 0x40); /* graphics mode = */
3323 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3324 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3325 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3326 11 avio_wb16(pb, 0); /* balance */
3327 11 avio_wb16(pb, 0); /* reserved */
3328
3329 /*
3330 * This special text atom is required for
3331 * Apple Quicktime chapters. The contents
3332 * don't appear to be documented, so the
3333 * bytes are copied verbatim.
3334 */
3335
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3336 11 avio_wb32(pb, 0x2C); /* size */
3337 11 ffio_wfourcc(pb, "text");
3338 11 avio_wb16(pb, 0x01);
3339 11 avio_wb32(pb, 0x00);
3340 11 avio_wb32(pb, 0x00);
3341 11 avio_wb32(pb, 0x00);
3342 11 avio_wb32(pb, 0x01);
3343 11 avio_wb32(pb, 0x00);
3344 11 avio_wb32(pb, 0x00);
3345 11 avio_wb32(pb, 0x00);
3346 11 avio_wb32(pb, 0x00004000);
3347 11 avio_wb16(pb, 0x0000);
3348 }
3349
3350
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3351 9 int64_t tmcd_pos = avio_tell(pb);
3352 9 avio_wb32(pb, 0); /* size */
3353 9 ffio_wfourcc(pb, "tmcd");
3354 9 mov_write_tcmi_tag(pb, track);
3355 9 update_size(pb, tmcd_pos);
3356
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3357 1 int64_t gpmd_pos = avio_tell(pb);
3358 1 avio_wb32(pb, 0); /* size */
3359 1 ffio_wfourcc(pb, "gpmd");
3360 1 avio_wb32(pb, 0); /* version */
3361 1 update_size(pb, gpmd_pos);
3362 }
3363 11 return update_size(pb, pos);
3364 }
3365
3366 110 static int mov_write_smhd_tag(AVIOContext *pb)
3367 {
3368 110 avio_wb32(pb, 16); /* size */
3369 110 ffio_wfourcc(pb, "smhd");
3370 110 avio_wb32(pb, 0); /* version & flags */
3371 110 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3372 110 avio_wb16(pb, 0); /* reserved */
3373 110 return 16;
3374 }
3375
3376 209 static int mov_write_vmhd_tag(AVIOContext *pb)
3377 {
3378 209 avio_wb32(pb, 0x14); /* size (always 0x14) */
3379 209 ffio_wfourcc(pb, "vmhd");
3380 209 avio_wb32(pb, 0x01); /* version & flags */
3381 209 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3382 209 return 0x14;
3383 }
3384
3385 222 static int is_clcp_track(MOVTrack *track)
3386 {
3387
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
444 return track->tag == MKTAG('c','7','0','8') ||
3388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
222 track->tag == MKTAG('c','6','0','8');
3389 }
3390
3391 528 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3392 {
3393 528 MOVMuxContext *mov = s->priv_data;
3394 528 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3395 528 int64_t pos = avio_tell(pb);
3396 size_t descr_len;
3397
3398 528 hdlr = "dhlr";
3399 528 hdlr_type = "url ";
3400 528 descr = "DataHandler";
3401
3402
2/2
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 189 times.
528 if (track) {
3403
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 150 times.
339 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3404
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 130 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (track->mode == MODE_AVIF) {
3406 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3407 descr = "PictureHandler";
3408 } else {
3409 209 hdlr_type = "vide";
3410 209 descr = "VideoHandler";
3411 }
3412
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 20 times.
130 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3413 110 hdlr_type = "soun";
3414 110 descr = "SoundHandler";
3415
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3416
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3417 hdlr_type = "clcp";
3418 descr = "ClosedCaptionHandler";
3419 } else {
3420
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3421 1 hdlr_type = "sbtl";
3422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3423 hdlr_type = "subp";
3424
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3425 1 hdlr_type = "subt";
3426 } else {
3427 2 hdlr_type = "text";
3428 }
3429 4 descr = "SubtitleHandler";
3430 }
3431
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3432 2 hdlr_type = "hint";
3433 2 descr = "HintHandler";
3434
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3435 13 hdlr_type = "tmcd";
3436 13 descr = "TimeCodeHandler";
3437
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3438 1 hdlr_type = "meta";
3439 1 descr = "GoPro MET"; // GoPro Metadata
3440 } else {
3441 av_log(s, AV_LOG_WARNING,
3442 "Unknown hdlr_type for %s, writing dummy values\n",
3443 av_fourcc2str(track->par->codec_tag));
3444 }
3445
2/2
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 3 times.
339 if (track->st) {
3446 // hdlr.name is used by some players to identify the content title
3447 // of the track. So if an alternate handler description is
3448 // specified, use it.
3449 AVDictionaryEntry *t;
3450 336 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3451
3/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 313 times.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
336 if (t && utf8len(t->value))
3452 23 descr = t->value;
3453 }
3454 }
3455
3456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 528 times.
528 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3457 descr = "";
3458
3459 528 avio_wb32(pb, 0); /* size */
3460 528 ffio_wfourcc(pb, "hdlr");
3461 528 avio_wb32(pb, 0); /* Version & flags */
3462 528 avio_write(pb, hdlr, 4); /* handler */
3463 528 ffio_wfourcc(pb, hdlr_type); /* handler type */
3464 528 avio_wb32(pb, 0); /* reserved */
3465 528 avio_wb32(pb, 0); /* reserved */
3466 528 avio_wb32(pb, 0); /* reserved */
3467 528 descr_len = strlen(descr);
3468
4/4
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 150 times.
528 if (!track || track->mode == MODE_MOV)
3469 378 avio_w8(pb, descr_len); /* pascal string */
3470 528 avio_write(pb, descr, descr_len); /* handler description */
3471
4/4
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 150 times.
✓ Branch 3 taken 189 times.
528 if (track && track->mode != MODE_MOV)
3472 150 avio_w8(pb, 0); /* c string */
3473 528 return update_size(pb, pos);
3474 }
3475
3476 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3477 {
3478 int64_t pos = avio_tell(pb);
3479 avio_wb32(pb, 0); /* size */
3480 ffio_wfourcc(pb, "pitm");
3481 avio_wb32(pb, 0); /* Version & flags */
3482 avio_wb16(pb, item_id); /* item_id */
3483 return update_size(pb, pos);
3484 }
3485
3486 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3487 {
3488 int64_t pos = avio_tell(pb);
3489 avio_wb32(pb, 0); /* size */
3490 ffio_wfourcc(pb, "iloc");
3491 avio_wb32(pb, 0); /* Version & flags */
3492 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3493 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3494 avio_wb16(pb, mov->nb_streams); /* item_count */
3495
3496 for (int i = 0; i < mov->nb_streams; i++) {
3497 avio_wb16(pb, i + 1); /* item_id */
3498 avio_wb16(pb, 0); /* data_reference_index */
3499 avio_wb16(pb, 1); /* extent_count */
3500 mov->avif_extent_pos[i] = avio_tell(pb);
3501 avio_wb32(pb, 0); /* extent_offset (written later) */
3502 // For animated AVIF, we simply write the first packet's size.
3503 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3504 }
3505
3506 return update_size(pb, pos);
3507 }
3508
3509 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3510 {
3511 int64_t iinf_pos = avio_tell(pb);
3512 avio_wb32(pb, 0); /* size */
3513 ffio_wfourcc(pb, "iinf");
3514 avio_wb32(pb, 0); /* Version & flags */
3515 avio_wb16(pb, mov->nb_streams); /* entry_count */
3516
3517 for (int i = 0; i < mov->nb_streams; i++) {
3518 int64_t infe_pos = avio_tell(pb);
3519 avio_wb32(pb, 0); /* size */
3520 ffio_wfourcc(pb, "infe");
3521 avio_w8(pb, 0x2); /* Version */
3522 avio_wb24(pb, 0); /* flags */
3523 avio_wb16(pb, i + 1); /* item_id */
3524 avio_wb16(pb, 0); /* item_protection_index */
3525 avio_write(pb, "av01", 4); /* item_type */
3526 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3527 update_size(pb, infe_pos);
3528 }
3529
3530 return update_size(pb, iinf_pos);
3531 }
3532
3533
3534 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3535 {
3536 int64_t auxl_pos;
3537 int64_t iref_pos = avio_tell(pb);
3538 avio_wb32(pb, 0); /* size */
3539 ffio_wfourcc(pb, "iref");
3540 avio_wb32(pb, 0); /* Version & flags */
3541
3542 auxl_pos = avio_tell(pb);
3543 avio_wb32(pb, 0); /* size */
3544 ffio_wfourcc(pb, "auxl");
3545 avio_wb16(pb, 2); /* from_item_ID */
3546 avio_wb16(pb, 1); /* reference_count */
3547 avio_wb16(pb, 1); /* to_item_ID */
3548 update_size(pb, auxl_pos);
3549
3550 return update_size(pb, iref_pos);
3551 }
3552
3553 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3554 int stream_index)
3555 {
3556 int64_t pos = avio_tell(pb);
3557 avio_wb32(pb, 0); /* size */
3558 ffio_wfourcc(pb, "ispe");
3559 avio_wb32(pb, 0); /* Version & flags */
3560 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3561 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3562 return update_size(pb, pos);
3563 }
3564
3565 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3566 int stream_index)
3567 {
3568 int64_t pos = avio_tell(pb);
3569 const AVPixFmtDescriptor *pixdesc =
3570 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3571 avio_wb32(pb, 0); /* size */
3572 ffio_wfourcc(pb, "pixi");
3573 avio_wb32(pb, 0); /* Version & flags */
3574 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3575 for (int i = 0; i < pixdesc->nb_components; ++i) {
3576 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3577 }
3578 return update_size(pb, pos);
3579 }
3580
3581 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3582 {
3583 int64_t pos = avio_tell(pb);
3584 avio_wb32(pb, 0); /* size */
3585 ffio_wfourcc(pb, "ipco");
3586 for (int i = 0; i < mov->nb_streams; i++) {
3587 mov_write_ispe_tag(pb, mov, s, i);
3588 mov_write_pixi_tag(pb, mov, s, i);
3589 mov_write_av1c_tag(pb, &mov->tracks[i]);
3590 if (!i)
3591 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3592 else
3593 mov_write_aux_tag(pb, "auxC");
3594 }
3595 return update_size(pb, pos);
3596 }
3597
3598 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3599 {
3600 int64_t pos = avio_tell(pb);
3601 avio_wb32(pb, 0); /* size */
3602 ffio_wfourcc(pb, "ipma");
3603 avio_wb32(pb, 0); /* Version & flags */
3604 avio_wb32(pb, mov->nb_streams); /* entry_count */
3605
3606 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3607 avio_wb16(pb, i + 1); /* item_ID */
3608 avio_w8(pb, 4); /* association_count */
3609
3610 // ispe association.
3611 avio_w8(pb, index++); /* essential and property_index */
3612 // pixi association.
3613 avio_w8(pb, index++); /* essential and property_index */
3614 // av1C association.
3615 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3616 // colr/auxC association.
3617 avio_w8(pb, index++); /* essential and property_index */
3618 }
3619 return update_size(pb, pos);
3620 }
3621
3622 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3623 {
3624 int64_t pos = avio_tell(pb);
3625 avio_wb32(pb, 0); /* size */
3626 ffio_wfourcc(pb, "iprp");
3627 mov_write_ipco_tag(pb, mov, s);
3628 mov_write_ipma_tag(pb, mov, s);
3629 return update_size(pb, pos);
3630 }
3631
3632 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3633 {
3634 /* This atom must be present, but leaving the values at zero
3635 * seems harmless. */
3636 2 avio_wb32(pb, 28); /* size */
3637 2 ffio_wfourcc(pb, "hmhd");
3638 2 avio_wb32(pb, 0); /* version, flags */
3639 2 avio_wb16(pb, 0); /* maxPDUsize */
3640 2 avio_wb16(pb, 0); /* avgPDUsize */
3641 2 avio_wb32(pb, 0); /* maxbitrate */
3642 2 avio_wb32(pb, 0); /* avgbitrate */
3643 2 avio_wb32(pb, 0); /* reserved */
3644 2 return 28;
3645 }
3646
3647 339 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3648 {
3649 339 int64_t pos = avio_tell(pb);
3650 int ret;
3651
3652 339 avio_wb32(pb, 0); /* size */
3653 339 ffio_wfourcc(pb, "minf");
3654
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 130 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3655 209 mov_write_vmhd_tag(pb);
3656
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 20 times.
130 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3657 110 mov_write_smhd_tag(pb);
3658
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3659
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
4 if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
3660 1 mov_write_gmhd_tag(pb, track);
3661
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3662 1 mov_write_sthd_tag(pb);
3663 } else {
3664 2 mov_write_nmhd_tag(pb);
3665 }
3666
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3667 2 mov_write_hmhd_tag(pb);
3668
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3669
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3670 4 mov_write_nmhd_tag(pb);
3671 else
3672 9 mov_write_gmhd_tag(pb, track);
3673
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3674 1 mov_write_gmhd_tag(pb, track);
3675 }
3676
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 150 times.
339 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3677 189 mov_write_hdlr_tag(s, pb, NULL);
3678 339 mov_write_dinf_tag(pb);
3679
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
339 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3680 return ret;
3681 339 return update_size(pb, pos);
3682 }
3683
3684 1312 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3685 int64_t *start, int64_t *end)
3686 {
3687
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1262 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1312 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3688 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3689 // another track's duration, while the end_pts may be left at zero.
3690 // Calculate the pts duration for that track instead.
3691 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3692 38 *start = av_rescale(*start, track->timescale,
3693 38 mov->tracks[track->src_track].timescale);
3694 38 *end = av_rescale(*end, track->timescale,
3695 38 mov->tracks[track->src_track].timescale);
3696 38 return;
3697 }
3698
2/2
✓ Branch 0 taken 1212 times.
✓ Branch 1 taken 62 times.
1274 if (track->end_pts != AV_NOPTS_VALUE &&
3699
1/2
✓ Branch 0 taken 1212 times.
✗ Branch 1 not taken.
1212 track->start_dts != AV_NOPTS_VALUE &&
3700
1/2
✓ Branch 0 taken 1212 times.
✗ Branch 1 not taken.
1212 track->start_cts != AV_NOPTS_VALUE) {
3701 1212 *start = track->start_dts + track->start_cts;
3702 1212 *end = track->end_pts;
3703 1212 return;
3704 }
3705 62 *start = 0;
3706 62 *end = track->track_duration;
3707 }
3708
3709 624 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3710 {
3711 int64_t start, end;
3712 624 get_pts_range(mov, track, &start, &end);
3713 624 return end - start;
3714 }
3715
3716 // Calculate the actual duration of the track, after edits.
3717 // If it starts with a pts < 0, that is removed by the edit list.
3718 // If it starts with a pts > 0, the edit list adds a delay before that.
3719 // Thus, with edit lists enabled, the post-edit output of the file is
3720 // starting with pts=0.
3721 650 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3722 {
3723 int64_t start, end;
3724 650 get_pts_range(mov, track, &start, &end);
3725
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 74 times.
650 if (mov->use_editlist != 0)
3726 576 start = 0;
3727 650 return end - start;
3728 }
3729
3730 918 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3731 {
3732
4/4
✓ Branch 0 taken 678 times.
✓ Branch 1 taken 240 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 664 times.
918 if (track && track->mode == MODE_ISM)
3733 14 return 1;
3734
2/2
✓ Branch 0 taken 900 times.
✓ Branch 1 taken 4 times.
904 if (duration < INT32_MAX)
3735 900 return 0;
3736 4 return 1;
3737 }
3738
3739 339 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3740 MOVTrack *track)
3741 {
3742 339 int64_t duration = calc_samples_pts_duration(mov, track);
3743 339 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3744
3745
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 328 times.
339 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3746 339 ffio_wfourcc(pb, "mdhd");
3747 339 avio_w8(pb, version);
3748 339 avio_wb24(pb, 0); /* flags */
3749
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 328 times.
339 if (version == 1) {
3750 11 avio_wb64(pb, track->time);
3751 11 avio_wb64(pb, track->time);
3752 } else {
3753 328 avio_wb32(pb, track->time); /* creation time */
3754 328 avio_wb32(pb, track->time); /* modification time */
3755 }
3756 339 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3757
4/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 85 times.
339 if (!track->entry && mov->mode == MODE_ISM)
3758
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3759
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 247 times.
332 else if (!track->entry)
3760
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 81 times.
85 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3761 else
3762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3763 339 avio_wb16(pb, track->language); /* language */
3764 339 avio_wb16(pb, 0); /* reserved (quality) */
3765
3766
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 328 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
339 if (version != 0 && track->mode == MODE_MOV) {
3767 av_log(NULL, AV_LOG_ERROR,
3768 "FATAL error, file duration too long for timebase, this file will not be\n"
3769 "playable with QuickTime. Choose a different timebase with "
3770 "-video_track_timescale or a different container format\n");
3771 }
3772
3773 339 return 32;
3774 }
3775
3776 339 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3777 MOVMuxContext *mov, MOVTrack *track)
3778 {
3779 339 int64_t pos = avio_tell(pb);
3780 int ret;
3781
3782 339 avio_wb32(pb, 0); /* size */
3783 339 ffio_wfourcc(pb, "mdia");
3784 339 mov_write_mdhd_tag(pb, mov, track);
3785 339 mov_write_hdlr_tag(s, pb, track);
3786
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
339 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3787 return ret;
3788 339 return update_size(pb, pos);
3789 }
3790
3791 /* transformation matrix
3792 |a b u|
3793 |c d v|
3794 |tx ty w| */
3795 578 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3796 int16_t d, int16_t tx, int16_t ty)
3797 {
3798 578 avio_wb32(pb, a << 16); /* 16.16 format */
3799 578 avio_wb32(pb, b << 16); /* 16.16 format */
3800 578 avio_wb32(pb, 0); /* u in 2.30 format */
3801 578 avio_wb32(pb, c << 16); /* 16.16 format */
3802 578 avio_wb32(pb, d << 16); /* 16.16 format */
3803 578 avio_wb32(pb, 0); /* v in 2.30 format */
3804 578 avio_wb32(pb, tx << 16); /* 16.16 format */
3805 578 avio_wb32(pb, ty << 16); /* 16.16 format */
3806 578 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3807 578 }
3808
3809 339 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3810 MOVTrack *track, AVStream *st)
3811 {
3812 678 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3813 339 mov->movie_timescale, track->timescale,
3814 AV_ROUND_UP);
3815 int version;
3816 339 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3817 339 int group = 0;
3818
3819 339 uint32_t *display_matrix = NULL;
3820 int i;
3821
3822
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
339 if (mov->mode == MODE_AVIF)
3823 if (!mov->avif_loop_count)
3824 duration = INT64_MAX;
3825 else
3826 duration *= mov->avif_loop_count;
3827
3828
2/2
✓ Branch 0 taken 326 times.
✓ Branch 1 taken 13 times.
339 if (st) {
3829 const AVPacketSideData *sd;
3830
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 324 times.
326 if (mov->per_stream_grouping)
3831 2 group = st->index;
3832 else
3833 324 group = st->codecpar->codec_type;
3834
3835 326 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3836 326 st->codecpar->nb_coded_side_data,
3837 AV_PKT_DATA_DISPLAYMATRIX);
3838
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 325 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
326 if (sd && sd->size == 9 * sizeof(*display_matrix))
3839 1 display_matrix = (uint32_t *)sd->data;
3840 }
3841
3842
2/2
✓ Branch 0 taken 314 times.
✓ Branch 1 taken 25 times.
339 if (track->flags & MOV_TRACK_ENABLED)
3843 314 flags |= MOV_TKHD_FLAG_ENABLED;
3844
3845 339 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3846
3847
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 332 times.
339 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3848 339 ffio_wfourcc(pb, "tkhd");
3849 339 avio_w8(pb, version);
3850 339 avio_wb24(pb, flags);
3851
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 332 times.
339 if (version == 1) {
3852 7 avio_wb64(pb, track->time);
3853 7 avio_wb64(pb, track->time);
3854 } else {
3855 332 avio_wb32(pb, track->time); /* creation time */
3856 332 avio_wb32(pb, track->time); /* modification time */
3857 }
3858 339 avio_wb32(pb, track->track_id); /* track-id */
3859 339 avio_wb32(pb, 0); /* reserved */
3860
4/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 85 times.
339 if (!track->entry && mov->mode == MODE_ISM)
3861
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3862
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 247 times.
332 else if (!track->entry)
3863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3864 else
3865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3866
3867 339 avio_wb32(pb, 0); /* reserved */
3868 339 avio_wb32(pb, 0); /* reserved */
3869 339 avio_wb16(pb, 0); /* layer */
3870 339 avio_wb16(pb, group); /* alternate group) */
3871 /* Volume, only for audio */
3872
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 229 times.
339 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3873 110 avio_wb16(pb, 0x0100);
3874 else
3875 229 avio_wb16(pb, 0);
3876 339 avio_wb16(pb, 0); /* reserved */
3877
3878 /* Matrix structure */
3879
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 338 times.
339 if (display_matrix) {
3880
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3881 9 avio_wb32(pb, display_matrix[i]);
3882 } else {
3883 338 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3884 }
3885 /* Track width and height, for visual only */
3886
4/4
✓ Branch 0 taken 326 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 209 times.
339 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3887
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 114 times.
329 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3888 int64_t track_width_1616;
3889
3/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 72 times.
212 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
3890 140 track_width_1616 = track->par->width * 0x10000ULL;
3891 } else {
3892 72 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3893 72 track->par->width * 0x10000LL,
3894 72 st->sample_aspect_ratio.den);
3895
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 68 times.
72 if (!track_width_1616 ||
3896
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 track->height != track->par->height ||
3897 track_width_1616 > UINT32_MAX)
3898 68 track_width_1616 = track->par->width * 0x10000ULL;
3899 }
3900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (track_width_1616 > UINT32_MAX) {
3901 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3902 track_width_1616 = 0;
3903 }
3904 212 avio_wb32(pb, track_width_1616);
3905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (track->height > 0xFFFF) {
3906 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3907 avio_wb32(pb, 0);
3908 } else
3909 212 avio_wb32(pb, track->height * 0x10000U);
3910 } else {
3911 127 avio_wb32(pb, 0);
3912 127 avio_wb32(pb, 0);
3913 }
3914 339 return 0x5c;
3915 }
3916
3917 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3918 {
3919 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3920 1 track->par->sample_aspect_ratio.den);
3921
3922 1 int64_t pos = avio_tell(pb);
3923
3924 1 avio_wb32(pb, 0); /* size */
3925 1 ffio_wfourcc(pb, "tapt");
3926
3927 1 avio_wb32(pb, 20);
3928 1 ffio_wfourcc(pb, "clef");
3929 1 avio_wb32(pb, 0);
3930 1 avio_wb32(pb, width << 16);
3931 1 avio_wb32(pb, track->par->height << 16);
3932
3933 1 avio_wb32(pb, 20);
3934 1 ffio_wfourcc(pb, "prof");
3935 1 avio_wb32(pb, 0);
3936 1 avio_wb32(pb, width << 16);
3937 1 avio_wb32(pb, track->par->height << 16);
3938
3939 1 avio_wb32(pb, 20);
3940 1 ffio_wfourcc(pb, "enof");
3941 1 avio_wb32(pb, 0);
3942 1 avio_wb32(pb, track->par->width << 16);
3943 1 avio_wb32(pb, track->par->height << 16);
3944
3945 1 return update_size(pb, pos);
3946 }
3947
3948 // This box is written in the following cases:
3949 // * Seems important for the psp playback. Without it the movie seems to hang.
3950 // * Used for specifying the looping behavior of animated AVIF (as specified
3951 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
3952 285 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
3953 MOVTrack *track)
3954 {
3955 570 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
3956 285 mov->movie_timescale, track->timescale,
3957 AV_ROUND_UP);
3958 285 int version = duration < INT32_MAX ? 0 : 1;
3959 int entry_size, entry_count, size;
3960 285 int64_t delay, start_ct = track->start_cts;
3961 285 int64_t start_dts = track->start_dts;
3962 285 int flags = 0;
3963
3964
2/2
✓ Branch 0 taken 231 times.
✓ Branch 1 taken 54 times.
285 if (track->entry) {
3965
2/6
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 231 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
231 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
3966
3967 av_log(mov->fc, AV_LOG_DEBUG,
3968 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
3969 track->cluster[0].dts, track->cluster[0].cts,
3970 start_dts, start_ct, track->track_id);
3971 start_dts = track->cluster[0].dts;
3972 start_ct = track->cluster[0].cts;
3973 }
3974 }
3975
3976 285 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
3977 285 track->timescale, AV_ROUND_DOWN);
3978
3979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 if (mov->mode == MODE_AVIF) {
3980 delay = 0;
3981 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
3982 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
3983 // list is not repeated, while (flags & 1) equal to 1 specifies that the
3984 // edit list is repeated.
3985 flags = mov->avif_loop_count != 1;
3986 start_ct = 0;
3987 }
3988
3989 285 version |= delay < INT32_MAX ? 0 : 1;
3990
3991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 entry_size = (version == 1) ? 20 : 12;
3992
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 283 times.
285 entry_count = 1 + (delay > 0);
3993 285 size = 24 + entry_count * entry_size;
3994
3995 /* write the atom data */
3996 285 avio_wb32(pb, size);
3997 285 ffio_wfourcc(pb, "edts");
3998 285 avio_wb32(pb, size - 8);
3999 285 ffio_wfourcc(pb, "elst");
4000 285 avio_w8(pb, version);
4001 285 avio_wb24(pb, flags); /* flags */
4002
4003 285 avio_wb32(pb, entry_count);
4004
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 283 times.
285 if (delay > 0) { /* add an empty edit to delay presentation */
4005 /* In the positive delay case, the delay includes the cts
4006 * offset, and the second edit list entry below trims out
4007 * the same amount from the actual content. This makes sure
4008 * that the offset last sample is included in the edit
4009 * list duration as well. */
4010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
4011 avio_wb64(pb, delay);
4012 avio_wb64(pb, -1);
4013 } else {
4014 2 avio_wb32(pb, delay);
4015 2 avio_wb32(pb, -1);
4016 }
4017 2 avio_wb32(pb, 0x00010000);
4018
1/2
✓ Branch 0 taken 283 times.
✗ Branch 1 not taken.
283 } else if (mov->mode != MODE_AVIF) {
4019 /* Avoid accidentally ending up with start_ct = -1 which has got a
4020 * special meaning. Normally start_ct should end up positive or zero
4021 * here, but use FFMIN in case dts is a small positive integer
4022 * rounded to 0 when represented in movie timescale units. */
4023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4024 283 start_ct = -FFMIN(start_dts, 0);
4025
4026 #if CONFIG_IAMFENC
4027
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
283 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4028 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4029 #endif
4030 /* Note, this delay is calculated from the pts of the first sample,
4031 * ensuring that we don't reduce the duration for cases with
4032 * dts<0 pts=0. */
4033 283 duration += delay;
4034 }
4035
4036 /* For fragmented files, we don't know the full length yet. Setting
4037 * duration to 0 allows us to only specify the offset, including
4038 * the rest of the content (from all future fragments) without specifying
4039 * an explicit duration.
4040 *
4041 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4042 * don't reset duration to zero.
4043 */
4044
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 227 times.
285 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4045
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
58 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4046 58 duration = 0;
4047
4048 /* duration */
4049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 if (version == 1) {
4050 avio_wb64(pb, duration);
4051 avio_wb64(pb, start_ct);
4052 } else {
4053 285 avio_wb32(pb, duration);
4054 285 avio_wb32(pb, start_ct);
4055 }
4056 285 avio_wb32(pb, 0x00010000);
4057 285 return size;
4058 }
4059
4060 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4061 {
4062 14 avio_wb32(pb, 20); // size
4063 14 ffio_wfourcc(pb, "tref");
4064 14 avio_wb32(pb, 12); // size (subatom)
4065 14 avio_wl32(pb, track->tref_tag);
4066 14 avio_wb32(pb, track->tref_id);
4067 14 return 20;
4068 }
4069
4070 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4071 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4072 {
4073 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4074 2 ffio_wfourcc(pb, "uuid");
4075 2 ffio_wfourcc(pb, "USMT");
4076 2 avio_wb32(pb, 0x21d24fce);
4077 2 avio_wb32(pb, 0xbb88695c);
4078 2 avio_wb32(pb, 0xfac9c740);
4079 2 avio_wb32(pb, 0x1c); // another size here!
4080 2 ffio_wfourcc(pb, "MTDT");
4081 2 avio_wb32(pb, 0x00010012);
4082 2 avio_wb32(pb, 0x0a);
4083 2 avio_wb32(pb, 0x55c40000);
4084 2 avio_wb32(pb, 0x1);
4085 2 avio_wb32(pb, 0x0);
4086 2 return 0x34;
4087 }
4088
4089 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4090 {
4091 2 AVFormatContext *ctx = track->rtp_ctx;
4092 2 char buf[1000] = "";
4093 int len;
4094
4095 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4096 NULL, NULL, 0, 0, ctx);
4097 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4098 2 len = strlen(buf);
4099
4100 2 avio_wb32(pb, len + 24);
4101 2 ffio_wfourcc(pb, "udta");
4102 2 avio_wb32(pb, len + 16);
4103 2 ffio_wfourcc(pb, "hnti");
4104 2 avio_wb32(pb, len + 8);
4105 2 ffio_wfourcc(pb, "sdp ");
4106 2 avio_write(pb, buf, len);
4107 2 return len + 24;
4108 }
4109
4110 318 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4111 const char *tag, const char *str)
4112 {
4113 318 int64_t pos = avio_tell(pb);
4114 318 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4115
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 317 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
318 if (!t || !utf8len(t->value))
4116 317 return 0;
4117
4118 1 avio_wb32(pb, 0); /* size */
4119 1 ffio_wfourcc(pb, tag); /* type */
4120 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4121 1 return update_size(pb, pos);
4122 }
4123
4124 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4125 const char *value)
4126 {
4127 2 int64_t pos = avio_tell(pb);
4128
4129 /* Box|FullBox basics */
4130 2 avio_wb32(pb, 0); /* size placeholder */
4131 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4132 2 avio_w8(pb, 0); /* version = 0 */
4133 2 avio_wb24(pb, 0); /* flags = 0 */
4134
4135 /* Required null-terminated scheme URI */
4136 2 avio_write(pb, (const unsigned char *)scheme_uri,
4137 2 strlen(scheme_uri));
4138 2 avio_w8(pb, 0);
4139
4140 /* Optional value string */
4141
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (value && value[0])
4142 2 avio_write(pb, (const unsigned char *)value,
4143 2 strlen(value));
4144
4145 2 avio_w8(pb, 0);
4146
4147 2 return update_size(pb, pos);
4148 }
4149
4150 135 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4151 {
4152 135 int ret = AVERROR_BUG;
4153
4154
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 135 times.
270 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4155 135 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4156
4157
2/2
✓ Branch 0 taken 675 times.
✓ Branch 1 taken 135 times.
810 for (int j = 0; map.value_maps[j].disposition; j++) {
4158 675 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4159
2/2
✓ Branch 0 taken 673 times.
✓ Branch 1 taken 2 times.
675 if (!(st->disposition & value_map.disposition))
4160 673 continue;
4161
4162
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_track_kind(pb, map.scheme_uri, value_map.value)) < 0)
4163 return ret;
4164 }
4165 }
4166
4167 135 return 0;
4168 }
4169
4170 339 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4171 AVStream *st)
4172 {
4173 AVIOContext *pb_buf;
4174 int ret, size;
4175 uint8_t *buf;
4176
4177
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 326 times.
339 if (!st)
4178 13 return 0;
4179
4180 326 ret = avio_open_dyn_buf(&pb_buf);
4181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 326 times.
326 if (ret < 0)
4182 return ret;
4183
4184
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 8 times.
326 if (mov->mode & (MODE_MP4|MODE_MOV))
4185 318 mov_write_track_metadata(pb_buf, st, "name", "title");
4186
4187
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 191 times.
326 if (mov->mode & MODE_MP4) {
4188
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
135 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4189 return ret;
4190 }
4191
4192
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 323 times.
326 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4193 3 avio_wb32(pb, size + 8);
4194 3 ffio_wfourcc(pb, "udta");
4195 3 avio_write(pb, buf, size);
4196 }
4197 326 ffio_free_dyn_buf(&pb_buf);
4198
4199 326 return 0;
4200 }
4201
4202 339 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4203 MOVTrack *track, AVStream *st)
4204 {
4205 339 int64_t pos = avio_tell(pb);
4206 339 int entry_backup = track->entry;
4207 339 int chunk_backup = track->chunkCount;
4208 int ret;
4209
4210 /* If we want to have an empty moov, but some samples already have been
4211 * buffered (delay_moov), pretend that no samples have been written yet. */
4212
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 247 times.
339 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4213 92 track->chunkCount = track->entry = 0;
4214
4215 339 avio_wb32(pb, 0); /* size */
4216 339 ffio_wfourcc(pb, "trak");
4217 339 mov_write_tkhd_tag(pb, mov, track, st);
4218
4219 av_assert2(mov->use_editlist >= 0);
4220
4221
2/2
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 28 times.
339 if (track->start_dts != AV_NOPTS_VALUE) {
4222
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 26 times.
311 if (mov->use_editlist)
4223 285 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4224
5/8
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 26 times.
26 else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
4225 av_log(mov->fc, AV_LOG_WARNING,
4226 "Not writing any edit list even though one would have been required\n");
4227 }
4228
4229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
339 if (mov->is_animated_avif)
4230 mov_write_edts_tag(pb, mov, track);
4231
4232
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 325 times.
339 if (track->tref_tag)
4233 14 mov_write_tref_tag(pb, track);
4234
4235
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
339 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4236 return ret;
4237
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 337 times.
339 if (track->mode == MODE_PSP)
4238 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4239
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 337 times.
339 if (track->tag == MKTAG('r','t','p',' '))
4240 2 mov_write_udta_sdp(pb, track);
4241
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 150 times.
339 if (track->mode == MODE_MOV) {
4242
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 49 times.
189 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4243 140 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4244
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
140 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4245 1 mov_write_tapt_tag(pb, track);
4246 }
4247 }
4248
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 189 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
189 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4249 mov_write_tapt_tag(pb, track);
4250 }
4251 }
4252 339 mov_write_track_udta_tag(pb, mov, st);
4253 339 track->entry = entry_backup;
4254 339 track->chunkCount = chunk_backup;
4255 339 return update_size(pb, pos);
4256 }
4257
4258 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4259 {
4260 int i, has_audio = 0, has_video = 0;
4261 int64_t pos = avio_tell(pb);
4262 int audio_profile = mov->iods_audio_profile;
4263 int video_profile = mov->iods_video_profile;
4264 for (i = 0; i < mov->nb_tracks; i++) {
4265 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4266 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4267 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4268 }
4269 }
4270 if (audio_profile < 0)
4271 audio_profile = 0xFF - has_audio;
4272 if (video_profile < 0)
4273 video_profile = 0xFF - has_video;
4274 avio_wb32(pb, 0x0); /* size */
4275 ffio_wfourcc(pb, "iods");
4276 avio_wb32(pb, 0); /* version & flags */
4277 put_descr(pb, 0x10, 7);
4278 avio_wb16(pb, 0x004f);
4279 avio_w8(pb, 0xff);
4280 avio_w8(pb, 0xff);
4281 avio_w8(pb, audio_profile);
4282 avio_w8(pb, video_profile);
4283 avio_w8(pb, 0xff);
4284 return update_size(pb, pos);
4285 }
4286
4287 112 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4288 {
4289 112 avio_wb32(pb, 0x20); /* size */
4290 112 ffio_wfourcc(pb, "trex");
4291 112 avio_wb32(pb, 0); /* version & flags */
4292 112 avio_wb32(pb, track->track_id); /* track ID */
4293 112 avio_wb32(pb, 1); /* default sample description index */
4294 112 avio_wb32(pb, 0); /* default sample duration */
4295 112 avio_wb32(pb, 0); /* default sample size */
4296 112 avio_wb32(pb, 0); /* default sample flags */
4297 112 return 0;
4298 }
4299
4300 58 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4301 {
4302 58 int64_t pos = avio_tell(pb);
4303 int i;
4304 58 avio_wb32(pb, 0x0); /* size */
4305 58 ffio_wfourcc(pb, "mvex");
4306
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 58 times.
170 for (i = 0; i < mov->nb_tracks; i++)
4307 112 mov_write_trex_tag(pb, &mov->tracks[i]);
4308 58 return update_size(pb, pos);
4309 }
4310
4311 240 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4312 {
4313 240 int max_track_id = 1, i;
4314 240 int64_t max_track_len = 0;
4315 int version;
4316 int timescale;
4317
4318
2/2
✓ Branch 0 taken 341 times.
✓ Branch 1 taken 240 times.
581 for (i = 0; i < mov->nb_tracks; i++) {
4319
3/4
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 311 times.
✗ Branch 3 not taken.
341 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4320 622 int64_t max_track_len_temp = av_rescale_rnd(
4321 311 calc_pts_duration(mov, &mov->tracks[i]),
4322 311 mov->movie_timescale,
4323 311 mov->tracks[i].timescale,
4324 AV_ROUND_UP);
4325
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 70 times.
311 if (max_track_len < max_track_len_temp)
4326 241 max_track_len = max_track_len_temp;
4327
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 226 times.
311 if (max_track_id < mov->tracks[i].track_id)
4328 85 max_track_id = mov->tracks[i].track_id;
4329 }
4330 }
4331 /* If using delay_moov, make sure the output is the same as if no
4332 * samples had been written yet. */
4333
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 192 times.
240 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4334 48 max_track_len = 0;
4335 48 max_track_id = 1;
4336 }
4337
4338 240 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4340
4341 240 ffio_wfourcc(pb, "mvhd");
4342 240 avio_w8(pb, version);
4343 240 avio_wb24(pb, 0); /* flags */
4344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (version == 1) {
4345 avio_wb64(pb, mov->time);
4346 avio_wb64(pb, mov->time);
4347 } else {
4348 240 avio_wb32(pb, mov->time); /* creation time */
4349 240 avio_wb32(pb, mov->time); /* modification time */
4350 }
4351
4352 240 timescale = mov->movie_timescale;
4353
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
240 if (mov->mode == MODE_AVIF && !timescale)
4354 timescale = mov->tracks[0].timescale;
4355
4356 240 avio_wb32(pb, timescale);
4357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4358
4359 240 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4360 240 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4361 240 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4362
4363 /* Matrix structure */
4364 240 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4365
4366 240 avio_wb32(pb, 0); /* reserved (preview time) */
4367 240 avio_wb32(pb, 0); /* reserved (preview duration) */
4368 240 avio_wb32(pb, 0); /* reserved (poster time) */
4369 240 avio_wb32(pb, 0); /* reserved (selection time) */
4370 240 avio_wb32(pb, 0); /* reserved (selection duration) */
4371 240 avio_wb32(pb, 0); /* reserved (current time) */
4372 240 avio_wb32(pb, max_track_id + 1); /* Next track id */
4373 240 return 0x6c;
4374 }
4375
4376 84 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4377 AVFormatContext *s)
4378 {
4379 84 avio_wb32(pb, 33); /* size */
4380 84 ffio_wfourcc(pb, "hdlr");
4381 84 avio_wb32(pb, 0);
4382 84 avio_wb32(pb, 0);
4383 84 ffio_wfourcc(pb, "mdir");
4384 84 ffio_wfourcc(pb, "appl");
4385 84 avio_wb32(pb, 0);
4386 84 avio_wb32(pb, 0);
4387 84 avio_w8(pb, 0);
4388 84 return 33;
4389 }
4390
4391 /* helper function to write a data tag with the specified string as data */
4392 54 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4393 {
4394 54 size_t data_len = strlen(data);
4395
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 34 times.
54 if (long_style) {
4396 20 int size = 16 + data_len;
4397 20 avio_wb32(pb, size); /* size */
4398 20 ffio_wfourcc(pb, "data");
4399 20 avio_wb32(pb, 1);
4400 20 avio_wb32(pb, 0);
4401 20 avio_write(pb, data, data_len);
4402 20 return size;
4403 } else {
4404 34 avio_wb16(pb, data_len); /* string length */
4405
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4406 26 lang = ff_mov_iso639_to_lang("und", 1);
4407 34 avio_wb16(pb, lang);
4408 34 avio_write(pb, data, data_len);
4409 34 return data_len + 4;
4410 }
4411 }
4412
4413 54 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4414 const char *value, int lang, int long_style)
4415 {
4416 54 int size = 0;
4417
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
54 if (value && value[0]) {
4418 54 int64_t pos = avio_tell(pb);
4419 54 avio_wb32(pb, 0); /* size */
4420 54 ffio_wfourcc(pb, name);
4421 54 mov_write_string_data_tag(pb, value, lang, long_style);
4422 54 size = update_size(pb, pos);
4423 }
4424 54 return size;
4425 }
4426
4427 3766 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4428 const char *tag, int *lang)
4429 {
4430 int l, len, len2;
4431 3766 AVDictionaryEntry *t, *t2 = NULL;
4432 char tag2[16];
4433
4434 3766 *lang = 0;
4435
4436
2/2
✓ Branch 1 taken 3714 times.
✓ Branch 2 taken 52 times.
3766 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4437 3714 return NULL;
4438
4439 52 len = strlen(t->key);
4440 52 snprintf(tag2, sizeof(tag2), "%s-", tag);
4441
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 44 times.
52 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4442 8 len2 = strlen(t2->key);
4443
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (len2 == len + 4 && !strcmp(t->value, t2->value)
4444
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4445 8 *lang = l;
4446 8 return t;
4447 }
4448 }
4449 44 return t;
4450 }
4451
4452 3682 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4453 const char *name, const char *tag,
4454 int long_style)
4455 {
4456 int lang;
4457 3682 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4458
2/2
✓ Branch 0 taken 3630 times.
✓ Branch 1 taken 52 times.
3682 if (!t)
4459 3630 return 0;
4460 52 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4461 }
4462
4463 /* iTunes bpm number */
4464 84 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4465 {
4466 84 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 int size = 0, tmpo = t ? atoi(t->value) : 0;
4468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (tmpo) {
4469 size = 26;
4470 avio_wb32(pb, size);
4471 ffio_wfourcc(pb, "tmpo");
4472 avio_wb32(pb, size-8); /* size */
4473 ffio_wfourcc(pb, "data");
4474 avio_wb32(pb, 0x15); //type specifier
4475 avio_wb32(pb, 0);
4476 avio_wb16(pb, tmpo); // data
4477 }
4478 84 return size;
4479 }
4480
4481 /* 3GPP TS 26.244 */
4482 84 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4483 {
4484 int lang;
4485 84 int64_t pos = avio_tell(pb);
4486 double latitude, longitude, altitude;
4487 int32_t latitude_fix, longitude_fix, altitude_fix;
4488 84 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4489 84 const char *ptr, *place = "";
4490 char *end;
4491 static const char *astronomical_body = "earth";
4492
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (!t)
4493 84 return 0;
4494
4495 ptr = t->value;
4496 latitude = strtod(ptr, &end);
4497 if (end == ptr) {
4498 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4499 return 0;
4500 }
4501 ptr = end;
4502 longitude = strtod(ptr, &end);
4503 if (end == ptr) {
4504 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4505 return 0;
4506 }
4507 ptr = end;
4508 altitude = strtod(ptr, &end);
4509 /* If no altitude was present, the default 0 should be fine */
4510 if (*end == '/')
4511 place = end + 1;
4512
4513 latitude_fix = (int32_t) ((1 << 16) * latitude);
4514 longitude_fix = (int32_t) ((1 << 16) * longitude);
4515 altitude_fix = (int32_t) ((1 << 16) * altitude);
4516
4517 avio_wb32(pb, 0); /* size */
4518 ffio_wfourcc(pb, "loci"); /* type */
4519 avio_wb32(pb, 0); /* version + flags */
4520 avio_wb16(pb, lang);
4521 avio_write(pb, place, strlen(place) + 1);
4522 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4523 avio_wb32(pb, longitude_fix);
4524 avio_wb32(pb, latitude_fix);
4525 avio_wb32(pb, altitude_fix);
4526 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4527 avio_w8(pb, 0); /* additional notes, null terminated string */
4528
4529 return update_size(pb, pos);
4530 }
4531
4532 /* iTunes track or disc number */
4533 168 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4534 AVFormatContext *s, int disc)
4535 {
4536
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 84 times.
168 AVDictionaryEntry *t = av_dict_get(s->metadata,
4537 disc ? "disc" : "track",
4538 NULL, 0);
4539
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 166 times.
168 int size = 0, track = t ? atoi(t->value) : 0;
4540
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 166 times.
168 if (track) {
4541 2 int tracks = 0;
4542 2 char *slash = strchr(t->value, '/');
4543
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4544 2 tracks = atoi(slash + 1);
4545 2 avio_wb32(pb, 32); /* size */
4546
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4547 2 avio_wb32(pb, 24); /* size */
4548 2 ffio_wfourcc(pb, "data");
4549 2 avio_wb32(pb, 0); // 8 bytes empty
4550 2 avio_wb32(pb, 0);
4551 2 avio_wb16(pb, 0); // empty
4552 2 avio_wb16(pb, track); // track / disc number
4553 2 avio_wb16(pb, tracks); // total track / disc number
4554 2 avio_wb16(pb, 0); // empty
4555 2 size = 32;
4556 }
4557 168 return size;
4558 }
4559
4560 504 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4561 const char *name, const char *tag,
4562 int len)
4563 {
4564 504 AVDictionaryEntry *t = NULL;
4565 uint8_t num;
4566 504 int size = 24 + len;
4567
4568
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 168 times.
504 if (len != 1 && len != 4)
4569 return -1;
4570
4571
2/2
✓ Branch 1 taken 502 times.
✓ Branch 2 taken 2 times.
504 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4572 502 return 0;
4573 2 num = atoi(t->value);
4574
4575 2 avio_wb32(pb, size);
4576 2 ffio_wfourcc(pb, name);
4577 2 avio_wb32(pb, size - 8);
4578 2 ffio_wfourcc(pb, "data");
4579 2 avio_wb32(pb, 0x15);
4580 2 avio_wb32(pb, 0);
4581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4582 2 else avio_w8 (pb, num);
4583
4584 2 return size;
4585 }
4586
4587 84 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4588 {
4589 84 MOVMuxContext *mov = s->priv_data;
4590 84 int64_t pos = 0;
4591
4592
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 84 times.
227 for (int i = 0; i < mov->nb_streams; i++) {
4593 143 MOVTrack *trk = &mov->tracks[i];
4594
4595
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
143 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4596 141 continue;
4597
4598
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4599 1 pos = avio_tell(pb);
4600 1 avio_wb32(pb, 0);
4601 1 ffio_wfourcc(pb, "covr");
4602 }
4603 2 avio_wb32(pb, 16 + trk->cover_image->size);
4604 2 ffio_wfourcc(pb, "data");
4605 2 avio_wb32(pb, trk->tag);
4606 2 avio_wb32(pb , 0);
4607 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4608 }
4609
4610
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 83 times.
84 return pos ? update_size(pb, pos) : 0;
4611 }
4612
4613 /* iTunes meta data list */
4614 84 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4615 AVFormatContext *s)
4616 {
4617 84 int64_t pos = avio_tell(pb);
4618 84 avio_wb32(pb, 0); /* size */
4619 84 ffio_wfourcc(pb, "ilst");
4620 84 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4621 84 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4622 84 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4623 84 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4624 84 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4625 84 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4626
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4627
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 82 times.
84 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4628 2 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4629 }
4630 84 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4631 84 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4632 84 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4633 84 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4634 84 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4635 84 mov_write_string_metadata(s, pb, "desc", "description",1);
4636 84 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4637 84 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4638 84 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4639 84 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4640 84 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4641 84 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4642 84 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4643 84 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4644 84 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4645 84 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4646 84 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4647 84 mov_write_covr(pb, s);
4648 84 mov_write_trkn_tag(pb, mov, s, 0); // track number
4649 84 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4650 84 mov_write_tmpo_tag(pb, s);
4651 84 return update_size(pb, pos);
4652 }
4653
4654 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4655 AVFormatContext *s)
4656 {
4657 avio_wb32(pb, 33); /* size */
4658 ffio_wfourcc(pb, "hdlr");
4659 avio_wb32(pb, 0);
4660 avio_wb32(pb, 0);
4661 ffio_wfourcc(pb, "mdta");
4662 avio_wb32(pb, 0);
4663 avio_wb32(pb, 0);
4664 avio_wb32(pb, 0);
4665 avio_w8(pb, 0);
4666 return 33;
4667 }
4668
4669 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4670 AVFormatContext *s)
4671 {
4672 const AVDictionaryEntry *t = NULL;
4673 int64_t pos = avio_tell(pb);
4674 int64_t curpos, entry_pos;
4675 int count = 0;
4676
4677 avio_wb32(pb, 0); /* size */
4678 ffio_wfourcc(pb, "keys");
4679 avio_wb32(pb, 0);
4680 entry_pos = avio_tell(pb);
4681 avio_wb32(pb, 0); /* entry count */
4682
4683 while (t = av_dict_iterate(s->metadata, t)) {
4684 size_t key_len = strlen(t->key);
4685 avio_wb32(pb, key_len + 8);
4686 ffio_wfourcc(pb, "mdta");
4687 avio_write(pb, t->key, key_len);
4688 count += 1;
4689 }
4690 curpos = avio_tell(pb);
4691 avio_seek(pb, entry_pos, SEEK_SET);
4692 avio_wb32(pb, count); // rewrite entry count
4693 avio_seek(pb, curpos, SEEK_SET);
4694
4695 return update_size(pb, pos);
4696 }
4697
4698 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4699 AVFormatContext *s)
4700 {
4701 const AVDictionaryEntry *t = NULL;
4702 int64_t pos = avio_tell(pb);
4703 int count = 1; /* keys are 1-index based */
4704
4705 avio_wb32(pb, 0); /* size */
4706 ffio_wfourcc(pb, "ilst");
4707
4708 while (t = av_dict_iterate(s->metadata, t)) {
4709 int64_t entry_pos = avio_tell(pb);
4710 avio_wb32(pb, 0); /* size */
4711 avio_wb32(pb, count); /* key */
4712 mov_write_string_data_tag(pb, t->value, 0, 1);
4713 update_size(pb, entry_pos);
4714 count += 1;
4715 }
4716 return update_size(pb, pos);
4717 }
4718
4719 /* meta data tags */
4720 84 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4721 AVFormatContext *s)
4722 {
4723 84 int size = 0;
4724 84 int64_t pos = avio_tell(pb);
4725 84 avio_wb32(pb, 0); /* size */
4726 84 ffio_wfourcc(pb, "meta");
4727 84 avio_wb32(pb, 0);
4728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4729 mov_write_mdta_hdlr_tag(pb, mov, s);
4730 mov_write_mdta_keys_tag(pb, mov, s);
4731 mov_write_mdta_ilst_tag(pb, mov, s);
4732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 } else if (mov->mode == MODE_AVIF) {
4733 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4734 // We always write the primary item id as 1 since only one track is
4735 // supported for AVIF.
4736 mov_write_pitm_tag(pb, 1);
4737 mov_write_iloc_tag(pb, mov, s);
4738 mov_write_iinf_tag(pb, mov, s);
4739 if (mov->nb_streams > 1)
4740 mov_write_iref_tag(pb, mov, s);
4741 mov_write_iprp_tag(pb, mov, s);
4742 } else {
4743 /* iTunes metadata tag */
4744 84 mov_write_itunes_hdlr_tag(pb, mov, s);
4745 84 mov_write_ilst_tag(pb, mov, s);
4746 }
4747 84 size = update_size(pb, pos);
4748 84 return size;
4749 }
4750
4751 155 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4752 const char *name, const char *key)
4753 {
4754 int len;
4755 AVDictionaryEntry *t;
4756
4757
1/2
✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
155 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4758 155 return 0;
4759
4760 len = strlen(t->value);
4761 if (len > 0) {
4762 int size = len + 8;
4763 avio_wb32(pb, size);
4764 ffio_wfourcc(pb, name);
4765 avio_write(pb, t->value, len);
4766 return size;
4767 }
4768 return 0;
4769 }
4770
4771 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4772 {
4773 int val;
4774 while (*b) {
4775 GET_UTF8(val, *b++, return -1;)
4776 avio_wb16(pb, val);
4777 }
4778 avio_wb16(pb, 0x00);
4779 return 0;
4780 }
4781
4782 static uint16_t language_code(const char *str)
4783 {
4784 return (((str[0] - 0x60) & 0x1F) << 10) +
4785 (((str[1] - 0x60) & 0x1F) << 5) +
4786 (( str[2] - 0x60) & 0x1F);
4787 }
4788
4789 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4790 const char *tag, const char *str)
4791 {
4792 int64_t pos = avio_tell(pb);
4793 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4794 if (!t || !utf8len(t->value))
4795 return 0;
4796 avio_wb32(pb, 0); /* size */
4797 ffio_wfourcc(pb, tag); /* type */
4798 avio_wb32(pb, 0); /* version + flags */
4799 if (!strcmp(tag, "yrrc"))
4800 avio_wb16(pb, atoi(t->value));
4801 else {
4802 avio_wb16(pb, language_code("eng")); /* language */
4803 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4804 if (!strcmp(tag, "albm") &&
4805 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4806 avio_w8(pb, atoi(t->value));
4807 }
4808 return update_size(pb, pos);
4809 }
4810
4811 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4812 {
4813 1 int64_t pos = avio_tell(pb);
4814 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4815
4816 1 avio_wb32(pb, 0); // size
4817 1 ffio_wfourcc(pb, "chpl");
4818 1 avio_wb32(pb, 0x01000000); // version + flags
4819 1 avio_wb32(pb, 0); // unknown
4820 1 avio_w8(pb, nb_chapters);
4821
4822
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4823 4 AVChapter *c = s->chapters[i];
4824 AVDictionaryEntry *t;
4825 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4826
4827
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4828
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4829 4 avio_w8(pb, len);
4830 4 avio_write(pb, t->value, len);
4831 } else
4832 avio_w8(pb, 0);
4833 }
4834 1 return update_size(pb, pos);
4835 }
4836
4837 239 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4838 AVFormatContext *s)
4839 {
4840 AVIOContext *pb_buf;
4841 int ret, size;
4842 uint8_t *buf;
4843
4844 239 ret = avio_open_dyn_buf(&pb_buf);
4845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
239 if (ret < 0)
4846 return ret;
4847
4848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
239 if (mov->mode & MODE_3GP) {
4849 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4850 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4851 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4852 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4853 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4854 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4855 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4856 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4857 mov_write_loci_tag(s, pb_buf);
4858
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
239 } 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
4859 155 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4860 155 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4861 155 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4862 155 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4863 155 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4864 155 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4865 // currently ignored by mov.c
4866 155 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4867 // add support for libquicktime, this atom is also actually read by mov.c
4868 155 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4869 155 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4870 155 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4871 155 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4872 155 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4873 155 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4874 155 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4875 155 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4876 } else {
4877 /* iTunes meta data */
4878 84 mov_write_meta_tag(pb_buf, mov, s);
4879 84 mov_write_loci_tag(s, pb_buf);
4880 }
4881
4882
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 238 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
239 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
4883 1 mov_write_chpl_tag(pb_buf, s);
4884
4885
2/2
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 127 times.
239 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4886 112 avio_wb32(pb, size + 8);
4887 112 ffio_wfourcc(pb, "udta");
4888 112 avio_write(pb, buf, size);
4889 }
4890 239 ffio_free_dyn_buf(&pb_buf);
4891
4892 239 return 0;
4893 }
4894
4895 static void mov_write_psp_udta_tag(AVIOContext *pb,
4896 const char *str, const char *lang, int type)
4897 {
4898 int len = utf8len(str) + 1;
4899 if (len <= 0)
4900 return;
4901 avio_wb16(pb, len * 2 + 10); /* size */
4902 avio_wb32(pb, type); /* type */
4903 avio_wb16(pb, language_code(lang)); /* language */
4904 avio_wb16(pb, 0x01); /* ? */
4905 ascii_to_wc(pb, str);
4906 }
4907
4908 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4909 {
4910 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4911 int64_t pos, pos2;
4912
4913
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4914 pos = avio_tell(pb);
4915 avio_wb32(pb, 0); /* size placeholder*/
4916 ffio_wfourcc(pb, "uuid");
4917 ffio_wfourcc(pb, "USMT");
4918 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4919 avio_wb32(pb, 0xbb88695c);
4920 avio_wb32(pb, 0xfac9c740);
4921
4922 pos2 = avio_tell(pb);
4923 avio_wb32(pb, 0); /* size placeholder*/
4924 ffio_wfourcc(pb, "MTDT");
4925 avio_wb16(pb, 4);
4926
4927 // ?
4928 avio_wb16(pb, 0x0C); /* size */
4929 avio_wb32(pb, 0x0B); /* type */
4930 avio_wb16(pb, language_code("und")); /* language */
4931 avio_wb16(pb, 0x0); /* ? */
4932 avio_wb16(pb, 0x021C); /* data */
4933
4934 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4935 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4936 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4937 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
4938
4939 update_size(pb, pos2);
4940 return update_size(pb, pos);
4941 }
4942
4943 1 return 0;
4944 }
4945
4946 328 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
4947 {
4948 AVEncryptionInitInfo *info;
4949 328 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4950 328 st->codecpar->nb_coded_side_data,
4951 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
4952
1/2
✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
328 if (!sd)
4953 328 return 0;
4954
4955 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
4956 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
4957 int64_t pos;
4958
4959 if (!copy->data_size && !copy->num_key_ids)
4960 continue;
4961
4962 pos = avio_tell(pb);
4963 avio_wb32(pb, 0); /* size placeholder */
4964 ffio_wfourcc(pb, "pssh");
4965 avio_w8(pb, 1); /* version */
4966 avio_wb24(pb, 0);
4967 for (int i = 0; i < copy->system_id_size; i++)
4968 avio_w8(pb, copy->system_id[i]);
4969 avio_wb32(pb, copy->num_key_ids);
4970 for (int i = 0; i < copy->num_key_ids; i++)
4971 for (int j = 0; j < copy->key_id_size; j++)
4972 avio_w8(pb, copy->key_ids[i][j]);
4973 avio_wb32(pb, copy->data_size);
4974 avio_write(pb, copy->data, copy->data_size);
4975 update_size(pb, pos);
4976 }
4977
4978 av_encryption_init_info_free(info);
4979
4980 return 0;
4981 }
4982
4983 311 static void build_chunks(MOVTrack *trk)
4984 {
4985 int i;
4986 311 MOVIentry *chunk = &trk->cluster[0];
4987 311 uint64_t chunkSize = chunk->size;
4988 311 chunk->chunkNum = 1;
4989
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 256 times.
311 if (trk->chunkCount)
4990 55 return;
4991 256 trk->chunkCount = 1;
4992
2/2
✓ Branch 0 taken 14839 times.
✓ Branch 1 taken 256 times.
15095 for (i = 1; i<trk->entry; i++){
4993
2/2
✓ Branch 0 taken 12936 times.
✓ Branch 1 taken 1903 times.
14839 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
4994
2/2
✓ Branch 0 taken 12291 times.
✓ Branch 1 taken 645 times.
12936 chunkSize + trk->cluster[i].size < (1<<20)){
4995 12291 chunkSize += trk->cluster[i].size;
4996 12291 chunk->samples_in_chunk += trk->cluster[i].entries;
4997 } else {
4998 2548 trk->cluster[i].chunkNum = chunk->chunkNum+1;
4999 2548 chunk=&trk->cluster[i];
5000 2548 chunkSize = chunk->size;
5001 2548 trk->chunkCount++;
5002 }
5003 }
5004 }
5005
5006 /**
5007 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5008 * the stream ids are used as track ids.
5009 *
5010 * This assumes mov->tracks and s->streams are in the same order and
5011 * there are no gaps in either of them (so mov->tracks[n] refers to
5012 * s->streams[n]).
5013 *
5014 * As an exception, there can be more entries in
5015 * s->streams than in mov->tracks, in which case new track ids are
5016 * generated (starting after the largest found stream id).
5017 */
5018 240 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5019 {
5020 int i;
5021
5022
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 211 times.
240 if (mov->track_ids_ok)
5023 29 return 0;
5024
5025
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->use_stream_ids_as_track_ids) {
5026 1 int next_generated_track_id = 0;
5027
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5028 2 AVStream *st = mov->tracks[i].st;
5029
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5030 2 next_generated_track_id = st->id;
5031 }
5032
5033
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5034
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5035 continue;
5036
5037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->tracks[i].track_id = i >= mov->nb_streams ? ++next_generated_track_id : mov->tracks[i].st->id;
5038 }
5039 } else {
5040 210 int last_track_id = 0;
5041
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 210 times.
488 for (i = 0; i < mov->nb_tracks; i++) {
5042
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26 times.
278 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5043 2 continue;
5044
5045 276 last_track_id =
5046 276 mov->tracks[i].track_id = (mov->tracks[i].st
5047 273 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5048
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 3 times.
276 : FFMAX(i, last_track_id)) + 1;
5049 }
5050 }
5051
5052 211 mov->track_ids_ok = 1;
5053
5054 211 return 0;
5055 }
5056
5057 240 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5058 AVFormatContext *s)
5059 {
5060 int i;
5061 240 int64_t pos = avio_tell(pb);
5062 240 avio_wb32(pb, 0); /* size placeholder*/
5063 240 ffio_wfourcc(pb, "moov");
5064
5065 240 mov_setup_track_ids(mov, s);
5066
5067
2/2
✓ Branch 0 taken 341 times.
✓ Branch 1 taken 240 times.
581 for (i = 0; i < mov->nb_tracks; i++) {
5068
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 311 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 28 times.
341 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5069 2 continue;
5070
5071 339 mov->tracks[i].time = mov->time;
5072
5073
2/2
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 28 times.
339 if (mov->tracks[i].entry)
5074 311 build_chunks(&mov->tracks[i]);
5075 }
5076
5077
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 239 times.
240 if (mov->chapter_track)
5078
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5079 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5080 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5081 }
5082
2/2
✓ Branch 0 taken 341 times.
✓ Branch 1 taken 240 times.
581 for (i = 0; i < mov->nb_tracks; i++) {
5083 341 MOVTrack *track = &mov->tracks[i];
5084
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 339 times.
341 if (track->tag == MKTAG('r','t','p',' ')) {
5085 2 track->tref_tag = MKTAG('h','i','n','t');
5086 2 track->tref_id = mov->tracks[track->src_track].track_id;
5087
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 229 times.
339 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5088 110 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5089 110 track->st->codecpar->nb_coded_side_data,
5090 AV_PKT_DATA_FALLBACK_TRACK );
5091
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
110 if (sd && sd->size == sizeof(int)) {
5092 int *fallback = (int *)sd->data;
5093 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5094 track->tref_tag = MKTAG('f','a','l','l');
5095 track->tref_id = mov->tracks[*fallback].track_id;
5096 }
5097 }
5098 }
5099 }
5100
2/2
✓ Branch 0 taken 341 times.
✓ Branch 1 taken 240 times.
581 for (i = 0; i < mov->nb_tracks; i++) {
5101
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 328 times.
341 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5102 13 int src_trk = mov->tracks[i].src_track;
5103 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5104 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5105 //src_trk may have a different timescale than the tmcd track
5106 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5107 13 mov->tracks[i].timescale,
5108 13 mov->tracks[src_trk].timescale);
5109 }
5110 }
5111
5112 240 mov_write_mvhd_tag(pb, mov);
5113
4/6
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 85 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 85 times.
240 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5114 mov_write_iods_tag(pb, mov);
5115
2/2
✓ Branch 0 taken 341 times.
✓ Branch 1 taken 240 times.
581 for (i = 0; i < mov->nb_tracks; i++) {
5116
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 311 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 28 times.
341 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5118
2/2
✓ Branch 0 taken 326 times.
✓ Branch 1 taken 13 times.
339 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 339 times.
339 if (ret < 0)
5120 return ret;
5121 }
5122 }
5123
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 182 times.
240 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5124 58 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5125
5126
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 239 times.
240 if (mov->mode == MODE_PSP)
5127 1 mov_write_uuidusmt_tag(pb, s);
5128
1/2
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
239 else if (mov->mode != MODE_AVIF)
5129 239 mov_write_udta_tag(pb, mov, s);
5130
2/2
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 240 times.
568 for (i = 0; i < mov->nb_streams; i++)
5131 328 mov_write_pssh_tag(pb, mov->tracks[i].st);
5132
5133 240 return update_size(pb, pos);
5134 }
5135
5136 static void param_write_int(AVIOContext *pb, const char *name, int value)
5137 {
5138 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5139 }
5140
5141 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5142 {
5143 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5144 }
5145
5146 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5147 {
5148 char buf[150];
5149 len = FFMIN(sizeof(buf) / 2 - 1, len);
5150 ff_data_to_hex(buf, value, len, 0);
5151 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5152 }
5153
5154 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5155 {
5156 int64_t pos = avio_tell(pb);
5157 int i;
5158
5159 static const AVUUID uuid = {
5160 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5161 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5162 };
5163
5164 avio_wb32(pb, 0);
5165 ffio_wfourcc(pb, "uuid");
5166 avio_write(pb, uuid, AV_UUID_LEN);
5167 avio_wb32(pb, 0);
5168
5169 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5170 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5171 avio_printf(pb, "<head>\n");
5172 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5173 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5174 LIBAVFORMAT_IDENT);
5175 avio_printf(pb, "</head>\n");
5176 avio_printf(pb, "<body>\n");
5177 avio_printf(pb, "<switch>\n");
5178
5179 mov_setup_track_ids(mov, s);
5180
5181 for (i = 0; i < mov->nb_tracks; i++) {
5182 MOVTrack *track = &mov->tracks[i];
5183 struct mpeg4_bit_rate_values bit_rates =
5184 calculate_mpeg4_bit_rates(track);
5185 const char *type;
5186 int track_id = track->track_id;
5187 char track_name_buf[32] = { 0 };
5188
5189 AVStream *st = track->st;
5190 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5191
5192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5193 type = "video";
5194 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5195 type = "audio";
5196 } else {
5197 continue;
5198 }
5199
5200 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5201 bit_rates.avg_bit_rate);
5202 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5203 param_write_int(pb, "trackID", track_id);
5204 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5205
5206 /* Build track name piece by piece: */
5207 /* 1. track type */
5208 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5209 /* 2. track language, if available */
5210 if (lang)
5211 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5212 "_%s", lang->value);
5213 /* 3. special type suffix */
5214 /* "_cc" = closed captions, "_ad" = audio_description */
5215 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5216 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5217 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5218 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5219
5220 param_write_string(pb, "trackName", track_name_buf);
5221
5222 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5223 if (track->par->codec_id == AV_CODEC_ID_H264) {
5224 uint8_t *ptr;
5225 int size = track->par->extradata_size;
5226 if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr,
5227 &size)) {
5228 param_write_hex(pb, "CodecPrivateData",
5229 ptr ? ptr : track->par->extradata,
5230 size);
5231 av_free(ptr);
5232 }
5233 param_write_string(pb, "FourCC", "H264");
5234 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5235 param_write_string(pb, "FourCC", "WVC1");
5236 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5237 track->par->extradata_size);
5238 }
5239 param_write_int(pb, "MaxWidth", track->par->width);
5240 param_write_int(pb, "MaxHeight", track->par->height);
5241 param_write_int(pb, "DisplayWidth", track->par->width);
5242 param_write_int(pb, "DisplayHeight", track->par->height);
5243 } else {
5244 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5245 switch (track->par->profile) {
5246 case AV_PROFILE_AAC_HE_V2:
5247 param_write_string(pb, "FourCC", "AACP");
5248 break;
5249 case AV_PROFILE_AAC_HE:
5250 param_write_string(pb, "FourCC", "AACH");
5251 break;
5252 default:
5253 param_write_string(pb, "FourCC", "AACL");
5254 }
5255 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5256 param_write_string(pb, "FourCC", "WMAP");
5257 }
5258 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5259 track->par->extradata_size);
5260 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5261 track->par->codec_id));
5262 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5263 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5264 0 : track->par->sample_rate);
5265 param_write_int(pb, "BitsPerSample", 16);
5266 param_write_int(pb, "PacketSize", track->par->block_align ?
5267 track->par->block_align : 4);
5268 }
5269 avio_printf(pb, "</%s>\n", type);
5270 }
5271 avio_printf(pb, "</switch>\n");
5272 avio_printf(pb, "</body>\n");
5273 avio_printf(pb, "</smil>\n");
5274
5275 return update_size(pb, pos);
5276 }
5277
5278 146 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5279 {
5280 146 avio_wb32(pb, 16);
5281 146 ffio_wfourcc(pb, "mfhd");
5282 146 avio_wb32(pb, 0);
5283 146 avio_wb32(pb, mov->fragments);
5284 146 return 0;
5285 }
5286
5287 10924 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5288 {
5289
2/2
✓ Branch 0 taken 7382 times.
✓ Branch 1 taken 3542 times.
10924 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5290 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5291 }
5292
5293 240 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5294 MOVTrack *track, int64_t moof_offset)
5295 {
5296 240 int64_t pos = avio_tell(pb);
5297 240 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5298 MOV_TFHD_BASE_DATA_OFFSET;
5299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (!track->entry) {
5300 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5301 } else {
5302 240 flags |= MOV_TFHD_DEFAULT_FLAGS;
5303 }
5304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5305 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5306
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 162 times.
240 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5307 78 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5308 78 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5309 }
5310 /* CMAF requires all values to be explicit in tfhd atoms */
5311
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 232 times.
240 if (mov->flags & FF_MOV_FLAG_CMAF)
5312 8 flags |= MOV_TFHD_STSD_ID;
5313
5314 /* Don't set a default sample size, the silverlight player refuses
5315 * to play files with that set. Don't set a default sample duration,
5316 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5317 * file format says it MUST NOT be set. */
5318
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 210 times.
240 if (track->mode == MODE_ISM)
5319 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5320 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5321
5322 240 avio_wb32(pb, 0); /* size placeholder */
5323 240 ffio_wfourcc(pb, "tfhd");
5324 240 avio_w8(pb, 0); /* version */
5325 240 avio_wb24(pb, flags);
5326
5327 240 avio_wb32(pb, track->track_id); /* track-id */
5328
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 108 times.
240 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5329 132 avio_wb64(pb, moof_offset);
5330
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 232 times.
240 if (flags & MOV_TFHD_STSD_ID) {
5331 8 avio_wb32(pb, 1);
5332 }
5333
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 30 times.
240 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5334 210 track->default_duration = get_cluster_duration(track, 0);
5335 210 avio_wb32(pb, track->default_duration);
5336 }
5337
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 30 times.
240 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5338
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 track->default_size = track->entry ? track->cluster[0].size : 1;
5339 210 avio_wb32(pb, track->default_size);
5340 } else
5341 30 track->default_size = -1;
5342
5343
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5344 /* Set the default flags based on the second sample, if available.
5345 * If the first sample is different, that can be signaled via a separate field. */
5346
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 12 times.
240 if (track->entry > 1)
5347 228 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5348 else
5349 12 track->default_sample_flags =
5350 12 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5351
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5352 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5353 240 avio_wb32(pb, track->default_sample_flags);
5354 }
5355
5356 240 return update_size(pb, pos);
5357 }
5358
5359 242 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5360 MOVTrack *track, int moof_size,
5361 int first, int end)
5362 {
5363 242 int64_t pos = avio_tell(pb);
5364 242 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5365 int i;
5366
5367
2/2
✓ Branch 0 taken 10220 times.
✓ Branch 1 taken 242 times.
10462 for (i = first; i < end; i++) {
5368
2/2
✓ Branch 1 taken 620 times.
✓ Branch 2 taken 9600 times.
10220 if (get_cluster_duration(track, i) != track->default_duration)
5369 620 flags |= MOV_TRUN_SAMPLE_DURATION;
5370
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 9718 times.
10220 if (track->cluster[i].size != track->default_size)
5371 502 flags |= MOV_TRUN_SAMPLE_SIZE;
5372
4/4
✓ Branch 0 taken 9978 times.
✓ Branch 1 taken 242 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 9968 times.
10220 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5373 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5374 }
5375
3/4
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 234 times.
✗ Branch 3 not taken.
242 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5376
2/2
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 122 times.
234 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5377 112 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5378
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 174 times.
242 if (track->flags & MOV_TRACK_CTTS)
5379 68 flags |= MOV_TRUN_SAMPLE_CTS;
5380
5381 242 avio_wb32(pb, 0); /* size placeholder */
5382 242 ffio_wfourcc(pb, "trun");
5383
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 188 times.
242 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5384 54 avio_w8(pb, 1); /* version */
5385 else
5386 188 avio_w8(pb, 0); /* version */
5387 242 avio_wb24(pb, flags);
5388
5389 242 avio_wb32(pb, end - first); /* sample count */
5390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5391 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5392 !mov->first_trun)
5393 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5394 else
5395 242 avio_wb32(pb, moof_size + 8 + track->data_offset +
5396 242 track->cluster[first].pos); /* data offset */
5397
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 130 times.
242 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5398 112 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5399
5400
2/2
✓ Branch 0 taken 10220 times.
✓ Branch 1 taken 242 times.
10462 for (i = first; i < end; i++) {
5401
2/2
✓ Branch 0 taken 808 times.
✓ Branch 1 taken 9412 times.
10220 if (flags & MOV_TRUN_SAMPLE_DURATION)
5402 808 avio_wb32(pb, get_cluster_duration(track, i));
5403
2/2
✓ Branch 0 taken 1150 times.
✓ Branch 1 taken 9070 times.
10220 if (flags & MOV_TRUN_SAMPLE_SIZE)
5404 1150 avio_wb32(pb, track->cluster[i].size);
5405
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 9848 times.
10220 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5406 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5407
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 8240 times.
10220 if (flags & MOV_TRUN_SAMPLE_CTS)
5408 1980 avio_wb32(pb, track->cluster[i].cts);
5409 }
5410
5411 242 mov->first_trun = 0;
5412 242 return update_size(pb, pos);
5413 }
5414
5415 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5416 {
5417 30 int64_t pos = avio_tell(pb);
5418 static const uint8_t uuid[] = {
5419 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5420 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5421 };
5422
5423 30 avio_wb32(pb, 0); /* size placeholder */
5424 30 ffio_wfourcc(pb, "uuid");
5425 30 avio_write(pb, uuid, AV_UUID_LEN);
5426 30 avio_w8(pb, 1);
5427 30 avio_wb24(pb, 0);
5428 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5429 30 avio_wb64(pb, track->end_pts -
5430 30 (track->cluster[0].dts + track->cluster[0].cts));
5431
5432 30 return update_size(pb, pos);
5433 }
5434
5435 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5436 MOVTrack *track, int entry)
5437 {
5438 int n = track->nb_frag_info - 1 - entry, i;
5439 int size = 8 + 16 + 4 + 1 + 16*n;
5440 static const uint8_t uuid[] = {
5441 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5442 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5443 };
5444
5445 if (entry < 0)
5446 return 0;
5447
5448 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5449 avio_wb32(pb, size);
5450 ffio_wfourcc(pb, "uuid");
5451 avio_write(pb, uuid, AV_UUID_LEN);
5452 avio_w8(pb, 1);
5453 avio_wb24(pb, 0);
5454 avio_w8(pb, n);
5455 for (i = 0; i < n; i++) {
5456 int index = entry + 1 + i;
5457 avio_wb64(pb, track->frag_info[index].time);
5458 avio_wb64(pb, track->frag_info[index].duration);
5459 }
5460 if (n < mov->ism_lookahead) {
5461 int free_size = 16 * (mov->ism_lookahead - n);
5462 avio_wb32(pb, free_size);
5463 ffio_wfourcc(pb, "free");
5464 ffio_fill(pb, 0, free_size - 8);
5465 }
5466
5467 return 0;
5468 }
5469
5470 120 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5471 MOVTrack *track)
5472 {
5473 120 int64_t pos = avio_tell(pb);
5474 int i;
5475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 for (i = 0; i < mov->ism_lookahead; i++) {
5476 /* Update the tfrf tag for the last ism_lookahead fragments,
5477 * nb_frag_info - 1 is the next fragment to be written. */
5478 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5479 }
5480 120 avio_seek(pb, pos, SEEK_SET);
5481 120 return 0;
5482 }
5483
5484 73 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5485 int size)
5486 {
5487 int i;
5488
2/2
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 73 times.
210 for (i = 0; i < mov->nb_tracks; i++) {
5489 137 MOVTrack *track = &mov->tracks[i];
5490 MOVFragmentInfo *info;
5491
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 120 times.
137 if ((tracks >= 0 && i != tracks) || !track->entry)
5492 17 continue;
5493 120 track->nb_frag_info++;
5494
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 55 times.
120 if (track->nb_frag_info >= track->frag_info_capacity) {
5495 65 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5496
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 if (av_reallocp_array(&track->frag_info,
5497 new_capacity,
5498 sizeof(*track->frag_info)))
5499 return AVERROR(ENOMEM);
5500 65 track->frag_info_capacity = new_capacity;
5501 }
5502 120 info = &track->frag_info[track->nb_frag_info - 1];
5503 120 info->offset = avio_tell(pb);
5504 120 info->size = size;
5505 // Try to recreate the original pts for the first packet
5506 // from the fields we have stored
5507 120 info->time = track->cluster[0].dts + track->cluster[0].cts;
5508 120 info->duration = track->end_pts -
5509 120 (track->cluster[0].dts + track->cluster[0].cts);
5510 // If the pts is less than zero, we will have trimmed
5511 // away parts of the media track using an edit list,
5512 // and the corresponding start presentation time is zero.
5513
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 112 times.
120 if (info->time < 0) {
5514 8 info->duration += info->time;
5515 8 info->time = 0;
5516 }
5517 120 info->tfrf_offset = 0;
5518 120 mov_write_tfrf_tags(pb, mov, track);
5519 }
5520 73 return 0;
5521 }
5522
5523 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5524 {
5525 int i;
5526 for (i = 0; i < mov->nb_tracks; i++) {
5527 MOVTrack *track = &mov->tracks[i];
5528 if ((tracks >= 0 && i != tracks) || !track->entry)
5529 continue;
5530 if (track->nb_frag_info > max) {
5531 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5532 track->nb_frag_info = max;
5533 }
5534 }
5535 }
5536
5537 210 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5538 {
5539 210 int64_t pos = avio_tell(pb);
5540
5541 210 avio_wb32(pb, 0); /* size */
5542 210 ffio_wfourcc(pb, "tfdt");
5543 210 avio_w8(pb, 1); /* version */
5544 210 avio_wb24(pb, 0);
5545 210 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5546 210 return update_size(pb, pos);
5547 }
5548
5549 240 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5550 MOVTrack *track, int64_t moof_offset,
5551 int moof_size)
5552 {
5553 240 int64_t pos = avio_tell(pb);
5554 240 int i, start = 0;
5555 240 avio_wb32(pb, 0); /* size placeholder */
5556 240 ffio_wfourcc(pb, "traf");
5557
5558 240 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5559
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 30 times.
240 if (mov->mode != MODE_ISM)
5560 210 mov_write_tfdt_tag(pb, track);
5561
2/2
✓ Branch 0 taken 9980 times.
✓ Branch 1 taken 240 times.
10220 for (i = 1; i < track->entry; i++) {
5562
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9978 times.
9980 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5563 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5564 2 start = i;
5565 }
5566 }
5567 240 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5568
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 210 times.
240 if (mov->mode == MODE_ISM) {
5569 30 mov_write_tfxd_tag(pb, track);
5570
5571
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5572 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5573
5574 if (track->nb_frag_info > 0) {
5575 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5576 if (!info->tfrf_offset)
5577 info->tfrf_offset = avio_tell(pb);
5578 }
5579 avio_wb32(pb, 8 + size);
5580 ffio_wfourcc(pb, "free");
5581 ffio_fill(pb, 0, size);
5582 }
5583 }
5584
5585
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
240 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5586 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5587
5588 240 return update_size(pb, pos);
5589 }
5590
5591 146 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5592 int tracks, int moof_size)
5593 {
5594 146 int64_t pos = avio_tell(pb);
5595 int i;
5596
5597 146 avio_wb32(pb, 0); /* size placeholder */
5598 146 ffio_wfourcc(pb, "moof");
5599 146 mov->first_trun = 1;
5600
5601 146 mov_write_mfhd_tag(pb, mov);
5602
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 146 times.
420 for (i = 0; i < mov->nb_tracks; i++) {
5603 274 MOVTrack *track = &mov->tracks[i];
5604
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 30 times.
274 if (tracks >= 0 && i != tracks)
5605 24 continue;
5606
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 240 times.
250 if (!track->entry)
5607 10 continue;
5608
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
240 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5609 mov_write_pssh_tag(pb, track->st);
5610 240 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5611 }
5612
5613 146 return update_size(pb, pos);
5614 }
5615
5616 70 static int mov_write_sidx_tag(AVIOContext *pb,
5617 MOVTrack *track, int ref_size, int total_sidx_size)
5618 {
5619 70 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5620 int64_t presentation_time, duration, offset;
5621 unsigned starts_with_SAP;
5622 int i, entries;
5623
5624
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (track->entry) {
5625 70 entries = 1;
5626 70 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5627 70 track->start_dts - track->start_cts;
5628 70 duration = track->end_pts -
5629 70 (track->cluster[0].dts + track->cluster[0].cts);
5630 70 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5631
5632 // pts<0 should be cut away using edts
5633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (presentation_time < 0) {
5634 duration += presentation_time;
5635 presentation_time = 0;
5636 }
5637 } else {
5638 entries = track->nb_frag_info;
5639 if (entries <= 0)
5640 return 0;
5641 presentation_time = track->frag_info[0].time;
5642 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5643 if (presentation_time > 0)
5644 presentation_time -= track->start_dts + track->start_cts;
5645 }
5646
5647 70 avio_wb32(pb, 0); /* size */
5648 70 ffio_wfourcc(pb, "sidx");
5649 70 avio_w8(pb, 1); /* version */
5650 70 avio_wb24(pb, 0);
5651 70 avio_wb32(pb, track->track_id); /* reference_ID */
5652 70 avio_wb32(pb, track->timescale); /* timescale */
5653 70 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5654 70 offset_pos = avio_tell(pb);
5655 70 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5656 70 avio_wb16(pb, 0); /* reserved */
5657
5658 70 avio_wb16(pb, entries); /* reference_count */
5659
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 70 times.
140 for (i = 0; i < entries; i++) {
5660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!track->entry) {
5661 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5662 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5663 }
5664 duration = track->frag_info[i].duration;
5665 ref_size = track->frag_info[i].size;
5666 starts_with_SAP = 1;
5667 }
5668 70 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5669 70 avio_wb32(pb, duration); /* subsegment_duration */
5670 70 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5671 }
5672
5673 70 end_pos = avio_tell(pb);
5674 70 offset = pos + total_sidx_size - end_pos;
5675 70 avio_seek(pb, offset_pos, SEEK_SET);
5676 70 avio_wb64(pb, offset);
5677 70 avio_seek(pb, end_pos, SEEK_SET);
5678 70 return update_size(pb, pos);
5679 }
5680
5681 20 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5682 int tracks, int ref_size)
5683 {
5684 int i, round, ret;
5685 AVIOContext *avio_buf;
5686 20 int total_size = 0;
5687
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (round = 0; round < 2; round++) {
5688 // First run one round to calculate the total size of all
5689 // sidx atoms.
5690 // This would be much simpler if we'd only write one sidx
5691 // atom, for the first track in the moof.
5692
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0) {
5693
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5694 return ret;
5695 } else {
5696 20 avio_buf = pb;
5697 }
5698
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
110 for (i = 0; i < mov->nb_tracks; i++) {
5699 70 MOVTrack *track = &mov->tracks[i];
5700
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 if (tracks >= 0 && i != tracks)
5701 continue;
5702 // When writing a sidx for the full file, entry is 0, but
5703 // we want to include all tracks. ref_size is 0 in this case,
5704 // since we read it from frag_info instead.
5705
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 if (!track->entry && ref_size > 0)
5706 continue;
5707 70 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5708 total_size);
5709 }
5710
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0)
5711 20 total_size = ffio_close_null_buf(avio_buf);
5712 }
5713 20 return 0;
5714 }
5715
5716 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5717 {
5718 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5719 MOVTrack *first_track;
5720 int flags = 24;
5721
5722 /* PRFT should be associated with at most one track. So, choosing only the
5723 * first track. */
5724 if (tracks > 0)
5725 return 0;
5726 first_track = &(mov->tracks[0]);
5727
5728 if (!first_track->entry) {
5729 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5730 return 0;
5731 }
5732
5733 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5734 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5735 return 0;
5736 }
5737
5738 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5739 if (first_track->cluster[0].prft.wallclock) {
5740 /* Round the NTP time to whole milliseconds. */
5741 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5742 NTP_OFFSET_US);
5743 flags = first_track->cluster[0].prft.flags;
5744 } else
5745 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5746 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5747 pts_us = av_rescale_q(first_track->cluster[0].pts,
5748 first_track->st->time_base, AV_TIME_BASE_Q);
5749 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5750 } else {
5751 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5752 mov->write_prft);
5753 return 0;
5754 }
5755
5756 avio_wb32(pb, 0); // Size place holder
5757 ffio_wfourcc(pb, "prft"); // Type
5758 avio_w8(pb, 1); // Version
5759 avio_wb24(pb, flags); // Flags
5760 avio_wb32(pb, first_track->track_id); // reference track ID
5761 avio_wb64(pb, ntp_ts); // NTP time stamp
5762 avio_wb64(pb, first_track->cluster[0].pts); //media time
5763 return update_size(pb, pos);
5764 }
5765
5766 73 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5767 int64_t mdat_size)
5768 {
5769 AVIOContext *avio_buf;
5770 int ret, moof_size;
5771
5772
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
73 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5773 return ret;
5774 73 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5775 73 moof_size = ffio_close_null_buf(avio_buf);
5776
5777
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 53 times.
73 if (mov->flags & FF_MOV_FLAG_DASH &&
5778
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5779 20 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5780
5781
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
73 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
5782 mov_write_prft_tag(pb, mov, tracks);
5783
5784
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5786 mov->ism_lookahead) {
5787
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
73 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
5788 return ret;
5789
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5791 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5792 }
5793 }
5794
5795 73 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5796 }
5797
5798 61 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5799 {
5800 61 int64_t pos = avio_tell(pb);
5801 int i;
5802
5803 61 avio_wb32(pb, 0); /* size placeholder */
5804 61 ffio_wfourcc(pb, "tfra");
5805 61 avio_w8(pb, 1); /* version */
5806 61 avio_wb24(pb, 0);
5807
5808 61 avio_wb32(pb, track->track_id);
5809 61 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5810 61 avio_wb32(pb, track->nb_frag_info);
5811
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 61 times.
175 for (i = 0; i < track->nb_frag_info; i++) {
5812 114 avio_wb64(pb, track->frag_info[i].time);
5813 114 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5814 114 avio_w8(pb, 1); /* traf number */
5815 114 avio_w8(pb, 1); /* trun number */
5816 114 avio_w8(pb, 1); /* sample number */
5817 }
5818
5819 61 return update_size(pb, pos);
5820 }
5821
5822 33 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5823 {
5824 AVIOContext *mfra_pb;
5825 int i, ret, sz;
5826 uint8_t *buf;
5827
5828 33 ret = avio_open_dyn_buf(&mfra_pb);
5829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret < 0)
5830 return ret;
5831
5832 33 avio_wb32(mfra_pb, 0); /* size placeholder */
5833 33 ffio_wfourcc(mfra_pb, "mfra");
5834 /* An empty mfra atom is enough to indicate to the publishing point that
5835 * the stream has ended. */
5836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_ISML)
5837 goto done_mfra;
5838
5839
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++) {
5840 63 MOVTrack *track = &mov->tracks[i];
5841
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (track->nb_frag_info)
5842 61 mov_write_tfra_tag(mfra_pb, track);
5843 }
5844
5845 33 avio_wb32(mfra_pb, 16);
5846 33 ffio_wfourcc(mfra_pb, "mfro");
5847 33 avio_wb32(mfra_pb, 0); /* version + flags */
5848 33 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5849
5850 33 done_mfra:
5851
5852 33 sz = update_size(mfra_pb, 0);
5853 33 ret = avio_get_dyn_buf(mfra_pb, &buf);
5854 33 avio_write(pb, buf, ret);
5855 33 ffio_free_dyn_buf(&mfra_pb);
5856
5857 33 return sz;
5858 }
5859
5860 176 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5861 {
5862 176 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5863
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 30 times.
176 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5864
5865 176 mov->mdat_pos = avio_tell(pb);
5866 176 avio_wb32(pb, 0); /* size placeholder*/
5867 176 ffio_wfourcc(pb, "mdat");
5868 176 return 0;
5869 }
5870
5871 422 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5872 int has_h264, int has_video, int write_minor)
5873 {
5874 422 MOVMuxContext *mov = s->priv_data;
5875 422 int minor = 0x200;
5876
5877
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
422 if (mov->major_brand && strlen(mov->major_brand) >= 4)
5878 ffio_wfourcc(pb, mov->major_brand);
5879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
422 else if (mov->mode == MODE_3GP) {
5880 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5881 minor = has_h264 ? 0x100 : 0x200;
5882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
422 } else if (mov->mode == MODE_AVIF) {
5883 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5884 minor = 0;
5885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
422 } else if (mov->mode & MODE_3G2) {
5886 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5887 minor = has_h264 ? 0x20000 : 0x10000;
5888
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 420 times.
422 } else if (mov->mode == MODE_PSP)
5889 2 ffio_wfourcc(pb, "MSNV");
5890
4/4
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 304 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 56 times.
420 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
5891
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 54 times.
60 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5892 6 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5893
4/4
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 304 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 88 times.
414 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5894 22 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5895
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 304 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
392 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5896 ffio_wfourcc(pb, "iso4");
5897
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 304 times.
392 else if (mov->mode == MODE_MP4)
5898 88 ffio_wfourcc(pb, "isom");
5899
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 302 times.
304 else if (mov->mode == MODE_IPOD)
5900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5901
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 294 times.
302 else if (mov->mode == MODE_ISM)
5902 8 ffio_wfourcc(pb, "isml");
5903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
294 else if (mov->mode == MODE_F4V)
5904 ffio_wfourcc(pb, "f4v ");
5905 else
5906 294 ffio_wfourcc(pb, "qt ");
5907
5908
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 211 times.
422 if (write_minor)
5909 211 avio_wb32(pb, minor);
5910 422 }
5911
5912 211 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5913 {
5914 211 MOVMuxContext *mov = s->priv_data;
5915 211 int64_t pos = avio_tell(pb);
5916 211 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
5917 211 int has_iamf = 0;
5918
5919 #if CONFIG_IAMFENC
5920
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 206 times.
211 for (int i = 0; i < s->nb_stream_groups; i++) {
5921 5 const AVStreamGroup *stg = s->stream_groups[i];
5922
5923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5924 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5925 5 has_iamf = 1;
5926 5 break;
5927 }
5928 }
5929 #endif
5930
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 211 times.
482 for (int i = 0; i < mov->nb_streams; i++) {
5931 271 AVStream *st = mov->tracks[i].st;
5932
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 269 times.
271 if (is_cover_image(st))
5933 2 continue;
5934
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 88 times.
269 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5935 181 has_video = 1;
5936
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 235 times.
269 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
5937 34 has_h264 = 1;
5938
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 268 times.
269 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
5939 1 has_av1 = 1;
5940
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 4 times.
269 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
5941
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 1 times.
265 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
5942
2/4
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 264 times.
528 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
5943 264 av_packet_side_data_get(st->codecpar->coded_side_data,
5944 264 st->codecpar->nb_coded_side_data,
5945 AV_PKT_DATA_DOVI_CONF))
5946 5 has_dolby = 1;
5947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
5948 has_id3 = 1;
5949 }
5950
5951 211 avio_wb32(pb, 0); /* size */
5952 211 ffio_wfourcc(pb, "ftyp");
5953
5954 // Write major brand
5955 211 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
5956 // Write the major brand as the first compatible brand as well
5957 211 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
5958
5959 // Write compatible brands, ensuring that we don't write the major brand as a
5960 // compatible brand a second time.
5961
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 207 times.
211 if (mov->mode == MODE_ISM) {
5962 4 ffio_wfourcc(pb, "piff");
5963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 } else if (mov->mode == MODE_AVIF) {
5964 const AVPixFmtDescriptor *pix_fmt_desc =
5965 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
5966 const int depth = pix_fmt_desc->comp[0].depth;
5967 if (mov->is_animated_avif) {
5968 // For animated AVIF, major brand is "avis". Add "avif" as a
5969 // compatible brand.
5970 ffio_wfourcc(pb, "avif");
5971 ffio_wfourcc(pb, "msf1");
5972 ffio_wfourcc(pb, "iso8");
5973 }
5974 ffio_wfourcc(pb, "mif1");
5975 ffio_wfourcc(pb, "miaf");
5976 if (depth == 8 || depth == 10) {
5977 // MA1B and MA1A brands are based on AV1 profile. Short hand for
5978 // computing that is based on chroma subsampling type. 420 chroma
5979 // subsampling is MA1B. 444 chroma subsampling is MA1A.
5980 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
5981 // 444 chroma subsampling.
5982 ffio_wfourcc(pb, "MA1A");
5983 } else {
5984 // 420 chroma subsampling.
5985 ffio_wfourcc(pb, "MA1B");
5986 }
5987 }
5988
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 147 times.
207 } else if (mov->mode != MODE_MOV) {
5989 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
5990 // brand, if not already the major brand. This is compatible with users that
5991 // don't understand tfdt.
5992
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 2 times.
60 if (mov->mode == MODE_MP4) {
5993
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
58 if (mov->flags & FF_MOV_FLAG_CMAF)
5994 1 ffio_wfourcc(pb, "cmfc");
5995
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 3 times.
58 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
5996 27 ffio_wfourcc(pb, "iso6");
5997
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
58 if (has_av1)
5998 1 ffio_wfourcc(pb, "av01");
5999
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 55 times.
58 if (has_dolby)
6000 3 ffio_wfourcc(pb, "dby1");
6001
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 53 times.
58 if (has_iamf)
6002 5 ffio_wfourcc(pb, "iamf");
6003 } else {
6004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6005 ffio_wfourcc(pb, "iso6");
6006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6007 ffio_wfourcc(pb, "iso5");
6008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6009 ffio_wfourcc(pb, "iso4");
6010 }
6011 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6012
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
60 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6013 // write isom for mp4 only if it it's not the major brand already.
6014
4/4
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 44 times.
48 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6015 4 ffio_wfourcc(pb, "isom");
6016 48 ffio_wfourcc(pb, "iso2");
6017
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 28 times.
48 if (has_h264)
6018 20 ffio_wfourcc(pb, "avc1");
6019 }
6020 }
6021
6022
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 153 times.
211 if (mov->mode == MODE_MP4)
6023 58 ffio_wfourcc(pb, "mp41");
6024
6025
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
211 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6026 ffio_wfourcc(pb, "dash");
6027
6028
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (has_id3)
6029 ffio_wfourcc(pb, "aid3");
6030
6031 211 return update_size(pb, pos);
6032 }
6033
6034 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6035 {
6036 1 AVStream *video_st = s->streams[0];
6037 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6038 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6039 1 int audio_rate = audio_par->sample_rate;
6040 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6041
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (video_st->avg_frame_rate.num * 0x10000LL) / video_st->avg_frame_rate.den :
6042 0;
6043 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6044 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6045
6046
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (frame_rate < 0 || frame_rate > INT32_MAX) {
6047 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6048 return AVERROR(EINVAL);
6049 }
6050
6051 1 avio_wb32(pb, 0x94); /* size */
6052 1 ffio_wfourcc(pb, "uuid");
6053 1 ffio_wfourcc(pb, "PROF");
6054
6055 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6056 1 avio_wb32(pb, 0xbb88695c);
6057 1 avio_wb32(pb, 0xfac9c740);
6058
6059 1 avio_wb32(pb, 0x0); /* ? */
6060 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6061
6062 1 avio_wb32(pb, 0x14); /* size */
6063 1 ffio_wfourcc(pb, "FPRF");
6064 1 avio_wb32(pb, 0x0); /* ? */
6065 1 avio_wb32(pb, 0x0); /* ? */
6066 1 avio_wb32(pb, 0x0); /* ? */
6067
6068 1 avio_wb32(pb, 0x2c); /* size */
6069 1 ffio_wfourcc(pb, "APRF"); /* audio */
6070 1 avio_wb32(pb, 0x0);
6071 1 avio_wb32(pb, 0x2); /* TrackID */
6072 1 ffio_wfourcc(pb, "mp4a");
6073 1 avio_wb32(pb, 0x20f);
6074 1 avio_wb32(pb, 0x0);
6075 1 avio_wb32(pb, audio_kbitrate);
6076 1 avio_wb32(pb, audio_kbitrate);
6077 1 avio_wb32(pb, audio_rate);
6078 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6079
6080 1 avio_wb32(pb, 0x34); /* size */
6081 1 ffio_wfourcc(pb, "VPRF"); /* video */
6082 1 avio_wb32(pb, 0x0);
6083 1 avio_wb32(pb, 0x1); /* TrackID */
6084
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6085 1 ffio_wfourcc(pb, "avc1");
6086 1 avio_wb16(pb, 0x014D);
6087 1 avio_wb16(pb, 0x0015);
6088 } else {
6089 ffio_wfourcc(pb, "mp4v");
6090 avio_wb16(pb, 0x0000);
6091 avio_wb16(pb, 0x0103);
6092 }
6093 1 avio_wb32(pb, 0x0);
6094 1 avio_wb32(pb, video_kbitrate);
6095 1 avio_wb32(pb, video_kbitrate);
6096 1 avio_wb32(pb, frame_rate);
6097 1 avio_wb32(pb, frame_rate);
6098 1 avio_wb16(pb, video_par->width);
6099 1 avio_wb16(pb, video_par->height);
6100 1 avio_wb32(pb, 0x010001); /* ? */
6101
6102 1 return 0;
6103 }
6104
6105 211 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6106 {
6107 211 MOVMuxContext *mov = s->priv_data;
6108 int i;
6109
6110 211 mov_write_ftyp_tag(pb,s);
6111
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->mode == MODE_PSP) {
6112 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6113
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6114 2 AVStream *st = mov->tracks[i].st;
6115
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6116 continue;
6117
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6118 1 video_streams_nb++;
6119
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6120 1 audio_streams_nb++;
6121 else
6122 other_streams_nb++;
6123 }
6124
6125
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if (video_streams_nb != 1 || audio_streams_nb != 1 || other_streams_nb) {
6126 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6127 return AVERROR(EINVAL);
6128 }
6129 1 return mov_write_uuidprof_tag(pb, s);
6130 }
6131 210 return 0;
6132 }
6133
6134 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6135 {
6136 8 uint32_t c = -1;
6137 8 int i, closed_gop = 0;
6138
6139
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6140 368 c = (c << 8) + pkt->data[i];
6141
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6142 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6143
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6144 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6145
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8 if (!temp_ref || closed_gop) // I picture is not reordered
6146 8 *flags = MOV_SYNC_SAMPLE;
6147 else
6148 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6149 8 break;
6150 }
6151 }
6152 8 return 0;
6153 }
6154
6155 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6156 {
6157 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6158 int seq = 0, entry = 0;
6159 int key = pkt->flags & AV_PKT_FLAG_KEY;
6160 start = find_next_marker(pkt->data, end);
6161 for (next = start; next < end; start = next) {
6162 next = find_next_marker(start + 4, end);
6163 switch (AV_RB32(start)) {
6164 case VC1_CODE_SEQHDR:
6165 seq = 1;
6166 break;
6167 case VC1_CODE_ENTRYPOINT:
6168 entry = 1;
6169 break;
6170 case VC1_CODE_SLICE:
6171 trk->vc1_info.slices = 1;
6172 break;
6173 }
6174 }
6175 if (!trk->entry && trk->vc1_info.first_packet_seen)
6176 trk->vc1_info.first_frag_written = 1;
6177 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6178 /* First packet in first fragment */
6179 trk->vc1_info.first_packet_seq = seq;
6180 trk->vc1_info.first_packet_entry = entry;
6181 trk->vc1_info.first_packet_seen = 1;
6182 } else if ((seq && !trk->vc1_info.packet_seq) ||
6183 (entry && !trk->vc1_info.packet_entry)) {
6184 int i;
6185 for (i = 0; i < trk->entry; i++)
6186 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6187 trk->has_keyframes = 0;
6188 if (seq)
6189 trk->vc1_info.packet_seq = 1;
6190 if (entry)
6191 trk->vc1_info.packet_entry = 1;
6192 if (!trk->vc1_info.first_frag_written) {
6193 /* First fragment */
6194 if ((!seq || trk->vc1_info.first_packet_seq) &&
6195 (!entry || trk->vc1_info.first_packet_entry)) {
6196 /* First packet had the same headers as this one, readd the
6197 * sync sample flag. */
6198 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6199 trk->has_keyframes = 1;
6200 }
6201 }
6202 }
6203 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6204 key = seq && entry;
6205 else if (trk->vc1_info.packet_seq)
6206 key = seq;
6207 else if (trk->vc1_info.packet_entry)
6208 key = entry;
6209 if (key) {
6210 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6211 trk->has_keyframes++;
6212 }
6213 }
6214
6215 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6216 {
6217 int length;
6218
6219 if (pkt->size < 8)
6220 return;
6221
6222 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6223 if (length < 8 || length > pkt->size)
6224 return;
6225
6226 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6227 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6228 trk->has_keyframes++;
6229 }
6230
6231 return;
6232 }
6233
6234 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6235 {
6236 89 MOVMuxContext *mov = s->priv_data;
6237 int ret, buf_size;
6238 uint8_t *buf;
6239 int i, offset;
6240
6241
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!track->mdat_buf)
6242 1 return 0;
6243
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 86 times.
88 if (!mov->mdat_buf) {
6244
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6245 return ret;
6246 }
6247 88 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6248
6249 88 offset = avio_tell(mov->mdat_buf);
6250 88 avio_write(mov->mdat_buf, buf, buf_size);
6251 88 ffio_free_dyn_buf(&track->mdat_buf);
6252
6253
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 88 times.
176 for (i = track->entries_flushed; i < track->entry; i++)
6254 88 track->cluster[i].pos += offset;
6255 88 track->entries_flushed = track->entry;
6256 88 return 0;
6257 }
6258
6259 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6260 {
6261 2 MOVMuxContext *mov = s->priv_data;
6262 2 AVPacket *squashed_packet = mov->pkt;
6263 2 int ret = AVERROR_BUG;
6264
6265
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
6266 2 case AV_CODEC_ID_TTML: {
6267 2 int had_packets = !!track->squashed_packet_queue.head;
6268
6269
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_generate_squashed_ttml_packet(s, track, squashed_packet)) < 0) {
6270 goto finish_squash;
6271 }
6272
6273 // We have generated a padding packet (no actual input packets in
6274 // queue) and its duration is zero. Skipping writing it.
6275
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (!had_packets && squashed_packet->duration == 0) {
6276 goto finish_squash;
6277 }
6278
6279 2 track->end_reliable = 1;
6280 2 break;
6281 }
6282 default:
6283 ret = AVERROR(EINVAL);
6284 goto finish_squash;
6285 }
6286
6287 2 squashed_packet->stream_index = track->st->index;
6288
6289 2 ret = mov_write_single_packet(s, squashed_packet);
6290
6291 2 finish_squash:
6292 2 av_packet_unref(squashed_packet);
6293
6294 2 return ret;
6295 }
6296
6297 319 static int mov_write_squashed_packets(AVFormatContext *s)
6298 {
6299 319 MOVMuxContext *mov = s->priv_data;
6300
6301
2/2
✓ Branch 0 taken 467 times.
✓ Branch 1 taken 319 times.
786 for (int i = 0; i < mov->nb_streams; i++) {
6302 467 MOVTrack *track = &mov->tracks[i];
6303 467 int ret = AVERROR_BUG;
6304
6305
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 465 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
467 if (track->squash_fragment_samples_to_one && !track->entry) {
6306
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6307 av_log(s, AV_LOG_ERROR,
6308 "Failed to write squashed packet for %s stream with "
6309 "index %d and track id %d. Error: %s\n",
6310 avcodec_get_name(track->st->codecpar->codec_id),
6311 track->st->index, track->track_id,
6312 av_err2str(ret));
6313 return ret;
6314 }
6315 }
6316 }
6317
6318 319 return 0;
6319 }
6320
6321 128 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6322 int64_t ref_pos)
6323 {
6324 int i;
6325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (!track->entry)
6326 return 0;
6327
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 120 times.
128 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6328
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6329 124 track->cluster[i].pos += ref_pos + track->data_offset;
6330
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
8 if (track->cluster_written == 0 && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) {
6331 // First flush. If this was a case of not using empty moov, reset chunking.
6332
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < track->entry; i++) {
6333 18 track->cluster[i].chunkNum = 0;
6334 18 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6335 }
6336 }
6337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6338 8 track->entry_written + track->entry,
6339 sizeof(*track->cluster)))
6340 return AVERROR(ENOMEM);
6341 8 memcpy(&track->cluster_written[track->entry_written],
6342 8 track->cluster, track->entry * sizeof(*track->cluster));
6343 8 track->entry_written += track->entry;
6344 }
6345 128 track->entry = 0;
6346 128 track->entries_flushed = 0;
6347 128 track->end_reliable = 0;
6348 128 return 0;
6349 }
6350
6351 108 static int mov_flush_fragment(AVFormatContext *s, int force)
6352 {
6353 108 MOVMuxContext *mov = s->priv_data;
6354 108 int i, first_track = -1;
6355 108 int64_t mdat_size = 0, mdat_start = 0;
6356 int ret;
6357 108 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6358
6359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6360 return 0;
6361
6362 // Check if we have any tracks that require squashing.
6363 // In that case, we'll have to write the packet here.
6364
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
108 if ((ret = mov_write_squashed_packets(s)) < 0)
6365 return ret;
6366
6367 // Try to fill in the duration of the last packet in each stream
6368 // from queued packets in the interleave queues. If the flushing
6369 // of fragments was triggered automatically by an AVPacket, we
6370 // already have reliable info for the end of that track, but other
6371 // tracks may need to be filled in.
6372
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 108 times.
304 for (i = 0; i < mov->nb_streams; i++) {
6373 196 MOVTrack *track = &mov->tracks[i];
6374
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 39 times.
196 if (!track->end_reliable) {
6375 157 const AVPacket *pkt = ff_interleaved_peek(s, i);
6376
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 151 times.
157 if (pkt) {
6377 int64_t offset, dts, pts;
6378 6 ff_get_muxer_ts_offset(s, i, &offset);
6379 6 pts = pkt->pts + offset;
6380 6 dts = pkt->dts + offset;
6381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6382 dts += track->dts_shift;
6383 6 track->track_duration = dts - track->start_dts;
6384
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6385 6 track->end_pts = pts;
6386 else
6387 track->end_pts = dts;
6388 }
6389 }
6390 }
6391
6392
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 108 times.
310 for (i = 0; i < mov->nb_tracks; i++) {
6393 202 MOVTrack *track = &mov->tracks[i];
6394
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 155 times.
202 if (track->entry <= 1)
6395 47 continue;
6396 // Sample durations are calculated as the diff of dts values,
6397 // but for the last sample in a fragment, we don't know the dts
6398 // of the first sample in the next fragment, so we have to rely
6399 // on what was set as duration in the AVPacket. Not all callers
6400 // set this though, so we might want to replace it with an
6401 // estimate if it currently is zero.
6402
2/2
✓ Branch 1 taken 153 times.
✓ Branch 2 taken 2 times.
155 if (get_cluster_duration(track, track->entry - 1) != 0)
6403 153 continue;
6404 // Use the duration (i.e. dts diff) of the second last sample for
6405 // the last one. This is a wild guess (and fatal if it turns out
6406 // to be too long), but probably the best we can do - having a zero
6407 // duration is bad as well.
6408 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6409 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6410
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6411 2 av_log(s, AV_LOG_WARNING,
6412 "Estimating the duration of the last packet in a "
6413 "fragment, consider setting the duration field in "
6414 "AVPacket instead.\n");
6415 2 mov->missing_duration_warned = 1;
6416 }
6417 }
6418
6419
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 85 times.
108 if (!mov->moov_written) {
6420 23 int64_t pos = avio_tell(s->pb);
6421 uint8_t *buf;
6422 int buf_size, moov_size;
6423
6424
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 19 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6425
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 41 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
45 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6426 4 break;
6427 /* Don't write the initial moov unless all tracks have data */
6428
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
23 if (i < mov->nb_tracks && !force)
6429 2 return 0;
6430
6431 21 moov_size = get_moov_size(s);
6432
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 21 times.
62 for (i = 0; i < mov->nb_tracks; i++)
6433 41 mov->tracks[i].data_offset = pos + moov_size + 8;
6434
6435 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6436
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6437 17 mov_write_identification(s->pb, s);
6438
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6439 return ret;
6440
6441
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6443 mov->reserved_header_pos = avio_tell(s->pb);
6444 17 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6445 17 mov->moov_written = 1;
6446 17 return 0;
6447 }
6448
6449 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6450 4 avio_wb32(s->pb, buf_size + 8);
6451 4 ffio_wfourcc(s->pb, "mdat");
6452 4 avio_write(s->pb, buf, buf_size);
6453 4 ffio_free_dyn_buf(&mov->mdat_buf);
6454
6455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6456 mov->reserved_header_pos = avio_tell(s->pb);
6457
6458 4 mov->moov_written = 1;
6459 4 mov->mdat_size = 0;
6460
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6461 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6462 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6463 4 return 0;
6464 }
6465
6466
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 83 times.
85 if (mov->frag_interleave) {
6467
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6468 4 MOVTrack *track = &mov->tracks[i];
6469 int ret;
6470
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6471 return ret;
6472 }
6473
6474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6475 return 0;
6476 2 mdat_size = avio_tell(mov->mdat_buf);
6477 }
6478
6479
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 85 times.
242 for (i = 0; i < mov->nb_tracks; i++) {
6480 157 MOVTrack *track = &mov->tracks[i];
6481
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 134 times.
157 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6482 23 track->data_offset = 0;
6483 else
6484 134 track->data_offset = mdat_size;
6485
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 82 times.
157 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6486 75 has_video = 1;
6487
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 if (first_video_track) {
6488
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 13 times.
75 if (track->entry)
6489 62 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6490 75 first_video_track = 0;
6491 }
6492 }
6493
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 120 times.
157 if (!track->entry)
6494 37 continue;
6495
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 3 times.
120 if (track->mdat_buf)
6496 117 mdat_size += avio_tell(track->mdat_buf);
6497
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 51 times.
120 if (first_track < 0)
6498 69 first_track = i;
6499 }
6500
6501
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 69 times.
85 if (!mdat_size)
6502 16 return 0;
6503
6504
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 4 times.
69 avio_write_marker(s->pb,
6505 69 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6506
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 6 times.
69 (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);
6507
6508
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 69 times.
197 for (i = first_track; i < mov->nb_tracks; i++) {
6509 128 MOVTrack *track = &mov->tracks[i];
6510 128 int buf_size, write_moof = 1, moof_tracks = -1;
6511 uint8_t *buf;
6512
6513
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 120 times.
128 if (!track->entry)
6514 9 continue;
6515
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 105 times.
120 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6516 15 mdat_size = avio_tell(track->mdat_buf);
6517 15 moof_tracks = i;
6518 } else {
6519 105 write_moof = i == first_track;
6520 }
6521
6522
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 47 times.
120 if (write_moof) {
6523 73 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6524
6525 73 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6526 73 mov->fragments++;
6527
6528 73 avio_wb32(s->pb, mdat_size + 8);
6529 73 ffio_wfourcc(s->pb, "mdat");
6530 73 mdat_start = avio_tell(s->pb);
6531 }
6532
6533 120 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6534
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 3 times.
120 if (!mov->frag_interleave) {
6535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!track->mdat_buf)
6536 continue;
6537 117 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6538 117 track->mdat_buf = NULL;
6539 } else {
6540
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (!mov->mdat_buf)
6541 1 continue;
6542 2 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6543 2 mov->mdat_buf = NULL;
6544 }
6545
6546 119 avio_write(s->pb, buf, buf_size);
6547 119 av_free(buf);
6548 }
6549
6550 69 mov->mdat_size = 0;
6551
6552 69 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6553 69 return 0;
6554 }
6555
6556 62 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6557 {
6558 62 MOVMuxContext *mov = s->priv_data;
6559 62 int had_moov = mov->moov_written;
6560 62 int ret = mov_flush_fragment(s, force);
6561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 if (ret < 0)
6562 return ret;
6563 // If using delay_moov, the first flush only wrote the moov,
6564 // not the actual moof+mdat pair, thus flush once again.
6565
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4 times.
62 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6566 9 ret = mov_flush_fragment(s, force);
6567 62 return ret;
6568 }
6569
6570 36343 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6571 {
6572 int64_t ref;
6573 uint64_t duration;
6574
6575
2/2
✓ Branch 0 taken 35696 times.
✓ Branch 1 taken 647 times.
36343 if (trk->entry) {
6576 35696 ref = trk->cluster[trk->entry - 1].dts;
6577
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 532 times.
647 } else if ( trk->start_dts != AV_NOPTS_VALUE
6578
2/2
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 8 times.
115 && !trk->frag_discont) {
6579 107 ref = trk->start_dts + trk->track_duration;
6580 } else
6581 540 ref = pkt->dts; // Skip tests for the first packet
6582
6583
2/2
✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 34688 times.
36343 if (trk->dts_shift != AV_NOPTS_VALUE) {
6584 /* With negative CTS offsets we have set an offset to the DTS,
6585 * reverse this for the check. */
6586 1655 ref -= trk->dts_shift;
6587 }
6588
6589 36343 duration = pkt->dts - ref;
6590
2/4
✓ Branch 0 taken 36343 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36343 times.
36343 if (pkt->dts < ref || duration >= INT_MAX) {
6591 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6592 duration, pkt->dts, pkt->stream_index);
6593
6594 pkt->dts = ref + 1;
6595 pkt->pts = AV_NOPTS_VALUE;
6596 }
6597
6598
2/4
✓ Branch 0 taken 36343 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36343 times.
36343 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6599 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6600 return AVERROR(EINVAL);
6601 }
6602 36343 return 0;
6603 }
6604
6605 18190 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6606 {
6607 18190 MOVMuxContext *mov = s->priv_data;
6608 18190 AVIOContext *pb = s->pb;
6609 MOVTrack *trk;
6610 AVCodecParameters *par;
6611 AVProducerReferenceTime *prft;
6612 18190 unsigned int samples_in_chunk = 0;
6613 18190 int size = pkt->size, ret = 0, offset = 0;
6614 size_t prft_size;
6615 18190 uint8_t *reformatted_data = NULL;
6616
6617
2/2
✓ Branch 0 taken 18144 times.
✓ Branch 1 taken 46 times.
18190 if (pkt->stream_index < s->nb_streams)
6618 18144 trk = s->streams[pkt->stream_index]->priv_data;
6619 else // Timecode or chapter
6620 46 trk = &mov->tracks[pkt->stream_index];
6621 18190 par = trk->par;
6622
6623 18190 ret = check_pkt(s, trk, pkt);
6624
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18190 times.
18190 if (ret < 0)
6625 return ret;
6626
6627
2/2
✓ Branch 0 taken 17588 times.
✓ Branch 1 taken 602 times.
18190 if (pkt->pts != AV_NOPTS_VALUE &&
6628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17588 times.
17588 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
6629 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6630 return AVERROR_PATCHWELCOME;
6631 }
6632
6633
3/4
✓ Branch 0 taken 12842 times.
✓ Branch 1 taken 5348 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12842 times.
18190 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6634 int ret;
6635
4/4
✓ Branch 0 taken 2130 times.
✓ Branch 1 taken 3218 times.
✓ Branch 2 taken 1892 times.
✓ Branch 3 taken 238 times.
5348 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
6636
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 5022 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
5110 if (mov->frag_interleave && mov->fragments > 0) {
6637
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6638
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6639 return ret;
6640 }
6641 }
6642
6643
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 4905 times.
5110 if (!trk->mdat_buf) {
6644
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 205 times.
205 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6645 return ret;
6646 }
6647 5110 pb = trk->mdat_buf;
6648 } else {
6649
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6650
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6651 return ret;
6652 }
6653 238 pb = mov->mdat_buf;
6654 }
6655 }
6656
6657
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18190 times.
18190 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6658 /* We must find out how many AMR blocks there are in one packet */
6659 static const uint16_t packed_size[16] =
6660 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6661 int len = 0;
6662
6663 while (len < size && samples_in_chunk < 100) {
6664 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6665 samples_in_chunk++;
6666 }
6667 if (samples_in_chunk > 1) {
6668 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6669 return -1;
6670 }
6671
1/2
✓ Branch 0 taken 18190 times.
✗ Branch 1 not taken.
18190 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18190 times.
18190 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6673 samples_in_chunk = trk->par->frame_size;
6674
2/2
✓ Branch 0 taken 1384 times.
✓ Branch 1 taken 16806 times.
18190 } else if (trk->sample_size)
6675 1384 samples_in_chunk = size / trk->sample_size;
6676 else
6677 16806 samples_in_chunk = 1;
6678
6679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18190 times.
18190 if (samples_in_chunk < 1) {
6680 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6681 return AVERROR_PATCHWELCOME;
6682 }
6683
6684 /* copy extradata if it exists */
6685
4/4
✓ Branch 0 taken 5465 times.
✓ Branch 1 taken 12725 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5463 times.
18190 if (trk->vos_len == 0 && par->extradata_size > 0 &&
6686
14/28
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 2 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 2 times.
✗ Branch 27 not taken.
2 !TAG_IS_AVCI(trk->tag) &&
6687
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6688 2 trk->vos_len = par->extradata_size;
6689 2 trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
6690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->vos_data) {
6691 ret = AVERROR(ENOMEM);
6692 goto err;
6693 }
6694 2 memcpy(trk->vos_data, par->extradata, trk->vos_len);
6695 2 memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6696 }
6697
6698
2/2
✓ Branch 0 taken 18075 times.
✓ Branch 1 taken 115 times.
18190 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6699
2/2
✓ Branch 0 taken 15487 times.
✓ Branch 1 taken 2588 times.
18075 par->codec_id == AV_CODEC_ID_H264 ||
6700
2/2
✓ Branch 0 taken 15332 times.
✓ Branch 1 taken 155 times.
15487 par->codec_id == AV_CODEC_ID_HEVC ||
6701
2/2
✓ Branch 0 taken 15322 times.
✓ Branch 1 taken 10 times.
15332 par->codec_id == AV_CODEC_ID_VVC ||
6702
1/2
✓ Branch 0 taken 15322 times.
✗ Branch 1 not taken.
15322 par->codec_id == AV_CODEC_ID_VP9 ||
6703
2/2
✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 300 times.
15322 par->codec_id == AV_CODEC_ID_EVC ||
6704
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 15022 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3144 times.
18190 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->vos_len &&
6705
14/28
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 24 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 24 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 24 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 24 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 24 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 24 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 24 times.
✗ Branch 27 not taken.
24 !TAG_IS_AVCI(trk->tag)) {
6706 /* copy frame to create needed atoms */
6707 24 trk->vos_len = size;
6708 24 trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->vos_data) {
6710 ret = AVERROR(ENOMEM);
6711 goto err;
6712 }
6713 24 memcpy(trk->vos_data, pkt->data, size);
6714 24 memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6715 }
6716
6717
3/4
✓ Branch 0 taken 5540 times.
✓ Branch 1 taken 12650 times.
✓ Branch 2 taken 5540 times.
✗ Branch 3 not taken.
18190 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5540 times.
5540 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6719 if (!trk->st->nb_frames) {
6720 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6721 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6722 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6723 return -1;
6724 }
6725 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6726 }
6727
19/34
✓ Branch 0 taken 2588 times.
✓ Branch 1 taken 15602 times.
✓ Branch 2 taken 2588 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 498 times.
✓ Branch 5 taken 2090 times.
✓ Branch 6 taken 498 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 498 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 498 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 498 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 498 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 498 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 498 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 498 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 498 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 498 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 498 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 498 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 498 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 498 times.
✗ Branch 33 not taken.
18190 if (par->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1 && !TAG_IS_AVCI(trk->tag)) {
6728 /* from x264 or from bytestream H.264 */
6729 /* NAL reformatting needed */
6730
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6731 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6732 &size);
6733 if (ret < 0)
6734 return ret;
6735 avio_write(pb, reformatted_data, size);
6736 } else {
6737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6738 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6739 if (size < 0) {
6740 ret = size;
6741 goto err;
6742 }
6743 } else {
6744 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6745 }
6746 }
6747
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 17537 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
17692 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 &&
6748
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
299 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6749 /* extradata is Annex B, assume the bitstream is too and convert it */
6750 144 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6751
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
144 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6752 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6753 &size, filter_ps, NULL);
6754 if (ret < 0)
6755 return ret;
6756 avio_write(pb, reformatted_data, size);
6757 } else {
6758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6759 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6760 if (size < 0) {
6761 ret = size;
6762 goto err;
6763 }
6764 } else {
6765 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6766 }
6767 }
6768
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 17538 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
17548 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->vos_len > 6 &&
6769
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6770 /* extradata is Annex B, assume the bitstream is too and convert it */
6771
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6772 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6773 &size, 0, NULL);
6774 if (ret < 0)
6775 return ret;
6776 avio_write(pb, reformatted_data, size);
6777 } else {
6778 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6779 }
6780
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17534 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
17538 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
6781
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6782 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6783 &size, &offset);
6784 if (ret < 0)
6785 return ret;
6786 avio_write(pb, reformatted_data, size);
6787 } else {
6788 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6789
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 if (trk->mode == MODE_AVIF && !mov->avif_extent_length[pkt->stream_index]) {
6790 mov->avif_extent_length[pkt->stream_index] = size;
6791 }
6792 }
6793
6794
2/2
✓ Branch 0 taken 17147 times.
✓ Branch 1 taken 387 times.
17534 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6795
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 16495 times.
17147 par->codec_id == AV_CODEC_ID_EAC3) {
6796 1039 size = handle_eac3(mov, pkt, trk);
6797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6798 return size;
6799
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6800 1 goto end;
6801 1038 avio_write(pb, pkt->data, size);
6802
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16495 times.
16495 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6803 size = 8;
6804
6805 for (int i = 0; i < pkt->size; i += 3) {
6806 if (pkt->data[i] == 0xFC) {
6807 size += 2;
6808 }
6809 }
6810 avio_wb32(pb, size);
6811 ffio_wfourcc(pb, "cdat");
6812 for (int i = 0; i < pkt->size; i += 3) {
6813 if (pkt->data[i] == 0xFC) {
6814 avio_w8(pb, pkt->data[i + 1]);
6815 avio_w8(pb, pkt->data[i + 2]);
6816 }
6817 }
6818 } else {
6819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16495 times.
16495 if (trk->cenc.aes_ctr) {
6820 if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) {
6821 int nal_size_length = (par->extradata[4] & 0x3) + 1;
6822 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6823 } else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) {
6824 int nal_size_length = (par->extradata[21] & 0x3) + 1;
6825 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6826 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6827 ret = AVERROR_PATCHWELCOME;
6828 } else if(par->codec_id == AV_CODEC_ID_AV1) {
6829 av_assert0(size == pkt->size);
6830 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
6831 if (ret > 0) {
6832 size = ret;
6833 ret = 0;
6834 }
6835 } else {
6836 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6837 }
6838
6839 if (ret) {
6840 goto err;
6841 }
6842 } else {
6843 16495 avio_write(pb, pkt->data, size);
6844 }
6845 }
6846
6847
2/2
✓ Branch 0 taken 277 times.
✓ Branch 1 taken 17912 times.
18189 if (trk->entry >= trk->cluster_capacity) {
6848 277 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6849 277 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 277 times.
277 if (!cluster) {
6851 ret = AVERROR(ENOMEM);
6852 goto err;
6853 }
6854 277 trk->cluster = cluster;
6855 277 trk->cluster_capacity = new_capacity;
6856 }
6857
6858 18189 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6859 18189 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6860 18189 trk->cluster[trk->entry].chunkNum = 0;
6861 18189 trk->cluster[trk->entry].size = size;
6862 18189 trk->cluster[trk->entry].entries = samples_in_chunk;
6863 18189 trk->cluster[trk->entry].dts = pkt->dts;
6864 18189 trk->cluster[trk->entry].pts = pkt->pts;
6865
2/2
✓ Branch 0 taken 18187 times.
✓ Branch 1 taken 2 times.
18189 if (!trk->squash_fragment_samples_to_one &&
6866
4/4
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 17850 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 261 times.
18187 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
6867
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 4 times.
76 if (!trk->frag_discont) {
6868 /* First packet of a new fragment. We already wrote the duration
6869 * of the last packet of the previous fragment based on track_duration,
6870 * which might not exactly match our dts. Therefore adjust the dts
6871 * of this packet to be what the previous packets duration implies. */
6872 72 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6873 /* We also may have written the pts and the corresponding duration
6874 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6875 * the next fragment. This means the cts of the first sample must
6876 * be the same in all fragments, unless end_pts was updated by
6877 * the packet causing the fragment to be written. */
6878
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 58 times.
72 if ((mov->flags & FF_MOV_FLAG_DASH &&
6879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6880
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 48 times.
58 mov->mode == MODE_ISM)
6881 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6882 } else {
6883 /* New fragment, but discontinuous from previous fragments.
6884 * Pretend the duration sum of the earlier fragments is
6885 * pkt->dts - trk->start_dts. */
6886 4 trk->end_pts = AV_NOPTS_VALUE;
6887 4 trk->frag_discont = 0;
6888 }
6889 }
6890
6891
6/6
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 17850 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 76 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 231 times.
18189 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
6892
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 11 times.
32 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
6893 /* Not using edit lists and shifting the first track to start from zero.
6894 * If the other streams start from a later timestamp, we won't be able
6895 * to signal the difference in starting time without an edit list.
6896 * Thus move the timestamp for this first sample to 0, increasing
6897 * its duration instead. */
6898 21 trk->cluster[trk->entry].dts = trk->start_dts = 0;
6899 }
6900
2/2
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 17947 times.
18189 if (trk->start_dts == AV_NOPTS_VALUE) {
6901 242 trk->start_dts = pkt->dts;
6902
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 236 times.
242 if (trk->frag_discont) {
6903
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
6904 /* Pretend the whole stream started at pts=0, with earlier fragments
6905 * already written. If the stream started at pts=0, the duration sum
6906 * of earlier fragments would have been pkt->pts. */
6907 4 trk->start_dts = pkt->dts - pkt->pts;
6908 } else {
6909 /* Pretend the whole stream started at dts=0, with earlier fragments
6910 * already written, with a duration summing up to pkt->dts. */
6911 2 trk->start_dts = 0;
6912 }
6913 6 trk->frag_discont = 0;
6914
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 203 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 31 times.
236 } else if (pkt->dts && mov->moov_written)
6915 2 av_log(s, AV_LOG_WARNING,
6916 "Track %d starts with a nonzero dts %"PRId64", while the moov "
6917 "already has been written. Set the delay_moov flag to handle "
6918 "this case.\n",
6919 pkt->stream_index, pkt->dts);
6920 }
6921 18189 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
6922 18189 trk->last_sample_is_subtitle_end = 0;
6923
6924
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 17587 times.
18189 if (pkt->pts == AV_NOPTS_VALUE) {
6925 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
6926 602 pkt->pts = pkt->dts;
6927 }
6928
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 17171 times.
18189 if (pkt->dts != pkt->pts)
6929 1018 trk->flags |= MOV_TRACK_CTTS;
6930 18189 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
6931 18189 trk->cluster[trk->entry].flags = 0;
6932
5/6
✓ Branch 0 taken 17926 times.
✓ Branch 1 taken 263 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 17877 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 49 times.
18189 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
6933 263 trk->start_cts = pkt->pts - pkt->dts;
6934
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 17922 times.
18189 if (trk->end_pts == AV_NOPTS_VALUE)
6935 267 trk->end_pts = trk->cluster[trk->entry].dts +
6936 267 trk->cluster[trk->entry].cts + pkt->duration;
6937 else
6938 17922 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
6939 trk->cluster[trk->entry].cts +
6940 pkt->duration);
6941
6942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18189 times.
18189 if (par->codec_id == AV_CODEC_ID_VC1) {
6943 mov_parse_vc1_frame(pkt, trk);
6944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18189 times.
18189 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
6945 mov_parse_truehd_frame(pkt, trk);
6946
2/2
✓ Branch 0 taken 13549 times.
✓ Branch 1 taken 4640 times.
18189 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
6947
4/4
✓ Branch 0 taken 6358 times.
✓ Branch 1 taken 7191 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6349 times.
13549 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
6948
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
6949 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
6950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
6951 trk->flags |= MOV_TRACK_STPS;
6952 } else {
6953 13541 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
6954 }
6955
1/2
✓ Branch 0 taken 13549 times.
✗ Branch 1 not taken.
13549 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
6956 13549 trk->has_keyframes++;
6957 }
6958
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18182 times.
18189 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
6959 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
6960 7 trk->has_disposable++;
6961 }
6962
6963 18189 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
6964
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18189 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18189 if (prft && prft_size == sizeof(AVProducerReferenceTime))
6965 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
6966 else
6967 18189 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
6968
6969 18189 trk->entry++;
6970 18189 trk->sample_count += samples_in_chunk;
6971 18189 mov->mdat_size += size;
6972
6973
3/4
✓ Branch 0 taken 18107 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
18189 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
6974 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
6975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
6976 : NULL, size);
6977
6978 18190 end:
6979 18190 err:
6980
6981
1/2
✓ Branch 0 taken 18190 times.
✗ Branch 1 not taken.
18190 if (pkt->data != reformatted_data)
6982 18190 av_free(reformatted_data);
6983 18190 return ret;
6984 }
6985
6986 18153 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
6987 {
6988 18153 MOVMuxContext *mov = s->priv_data;
6989 18153 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
6990 18153 AVCodecParameters *par = trk->par;
6991 18153 int64_t frag_duration = 0;
6992 18153 int size = pkt->size;
6993
6994 18153 int ret = check_pkt(s, trk, pkt);
6995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18153 times.
18153 if (ret < 0)
6996 return ret;
6997
6998
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18148 times.
18153 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
6999
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7000 10 mov->tracks[i].frag_discont = 1;
7001 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7002 }
7003
7004
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 17343 times.
18153 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7005
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 799 times.
810 if (trk->dts_shift == AV_NOPTS_VALUE)
7006 11 trk->dts_shift = pkt->pts - pkt->dts;
7007 810 pkt->dts += trk->dts_shift;
7008 }
7009
7010
1/2
✓ Branch 0 taken 18153 times.
✗ Branch 1 not taken.
18153 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7011
2/2
✓ Branch 0 taken 12611 times.
✓ Branch 1 taken 5542 times.
18153 trk->par->codec_id == AV_CODEC_ID_AAC ||
7012
2/2
✓ Branch 0 taken 12607 times.
✓ Branch 1 taken 4 times.
12611 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7013
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12552 times.
12607 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7014 size_t side_size;
7015 5601 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7016
6/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5595 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5601 if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
7017 6 void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7019 return AVERROR(ENOMEM);
7020 6 av_free(par->extradata);
7021 6 par->extradata = newextra;
7022 6 memcpy(par->extradata, side, side_size);
7023 6 par->extradata_size = side_size;
7024
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (!pkt->size) // Flush packet
7025 5 mov->need_rewrite_extradata = 1;
7026 }
7027 }
7028
7029
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18144 times.
18153 if (!pkt->size) {
7030
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
9 if (trk->start_dts == AV_NOPTS_VALUE && trk->frag_discont) {
7031 4 trk->start_dts = pkt->dts;
7032
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7033 4 trk->start_cts = pkt->pts - pkt->dts;
7034 else
7035 trk->start_cts = 0;
7036 }
7037
7038 9 return 0; /* Discard 0 sized packets */
7039 }
7040
7041
4/4
✓ Branch 0 taken 17841 times.
✓ Branch 1 taken 303 times.
✓ Branch 2 taken 17817 times.
✓ Branch 3 taken 24 times.
18144 if (trk->entry && pkt->stream_index < mov->nb_streams)
7042 17817 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7043 17817 s->streams[pkt->stream_index]->time_base,
7044 17817 AV_TIME_BASE_Q);
7045
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 17883 times.
18144 if ((mov->max_fragment_duration &&
7046
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7047
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18140 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18140 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7048
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 14467 times.
18140 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7049
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 2548 times.
3673 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7050
4/4
✓ Branch 0 taken 1101 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 1076 times.
✓ Branch 3 taken 25 times.
1125 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18115 times.
18115 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7052
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (frag_duration >= mov->min_fragment_duration) {
7053
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (trk->entry) {
7054 // Set the duration of this track to line up with the next
7055 // sample in this track. This avoids relying on AVPacket
7056 // duration, but only helps for this particular track, not
7057 // for the other ones that are flushed at the same time.
7058 //
7059 // If we have trk->entry == 0, no fragment will be written
7060 // for this track, and we can't adjust the track end here.
7061 29 trk->track_duration = pkt->dts - trk->start_dts;
7062
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (pkt->pts != AV_NOPTS_VALUE)
7063 29 trk->end_pts = pkt->pts;
7064 else
7065 trk->end_pts = pkt->dts;
7066 29 trk->end_reliable = 1;
7067 }
7068 29 mov_auto_flush_fragment(s, 0);
7069 }
7070 }
7071
7072 18144 return ff_mov_write_packet(s, pkt);
7073 }
7074
7075 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7076 int stream_index,
7077 int64_t dts) {
7078 3 MOVMuxContext *mov = s->priv_data;
7079 3 AVPacket *end = mov->pkt;
7080 3 uint8_t data[2] = {0};
7081 int ret;
7082
7083 3 end->size = sizeof(data);
7084 3 end->data = data;
7085 3 end->pts = dts;
7086 3 end->dts = dts;
7087 3 end->duration = 0;
7088 3 end->stream_index = stream_index;
7089
7090 3 ret = mov_write_single_packet(s, end);
7091 3 av_packet_unref(end);
7092
7093 3 return ret;
7094 }
7095
7096 #if CONFIG_IAMFENC
7097 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7098 {
7099 uint8_t *data;
7100 int ret;
7101
7102
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7103 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7105 return ret;
7106 }
7107
7108 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7109 275 s->streams[pkt->stream_index]->id, pkt);
7110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7111 return ret;
7112
7113
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7114 220 return AVERROR(EAGAIN);
7115
7116 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7117 55 trk->iamf_buf = NULL;
7118
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7120 // Either all or none of the packets for a single
7121 // IA Sample may be empty.
7122 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7123 "stream #%d\n", pkt->stream_index);
7124 ret = AVERROR_INVALIDDATA;
7125 }
7126 5 av_free(data);
7127 5 return ret;
7128 }
7129
7130 50 av_buffer_unref(&pkt->buf);
7131 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7133 av_free(data);
7134 return AVERROR(ENOMEM);
7135 }
7136 50 pkt->data = data;
7137 50 pkt->size = ret;
7138 50 pkt->stream_index = trk->first_iamf_idx;
7139
7140 50 return avio_open_dyn_buf(&trk->iamf_buf);
7141 }
7142 #endif
7143
7144 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7145 {
7146 2 int64_t pos = avio_tell(pb);
7147 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7148 2 const char *value = "";
7149
7150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7151
7152 2 avio_write_marker(pb,
7153 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7154 AVIO_DATA_MARKER_BOUNDARY_POINT);
7155
7156 2 avio_wb32(pb, 0); /* size */
7157 2 ffio_wfourcc(pb, "emsg");
7158 2 avio_w8(pb, 1); /* version */
7159 2 avio_wb24(pb, 0);
7160 2 avio_wb32(pb, st->time_base.den); /* timescale */
7161 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7162 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7163 2 avio_wb32(pb, 0); /* id */
7164 /* null terminated UTF8 strings */
7165 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7166 2 avio_write(pb, value, strlen(value) + 1);
7167 2 avio_write(pb, pkt->data, pkt->size);
7168
7169 2 return update_size(pb, pos);
7170 }
7171
7172 18481 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7173 {
7174 18481 MOVMuxContext *mov = s->priv_data;
7175 MOVTrack *trk;
7176
7177
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 18446 times.
18481 if (!pkt) {
7178 35 mov_flush_fragment(s, 1);
7179 35 return 1;
7180 }
7181
7182
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18444 times.
18446 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7183 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7184 2 return 0;
7185 }
7186
7187 18444 trk = s->streams[pkt->stream_index]->priv_data;
7188
7189 #if CONFIG_IAMFENC
7190
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 18169 times.
18444 if (trk->iamf) {
7191 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7192
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7193
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7194 220 return 0;
7195 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7196 "for stream #%d\n", trk->st->index);
7197 return ret;
7198 }
7199 }
7200 #endif
7201
7202
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18222 times.
18224 if (is_cover_image(trk->st)) {
7203 int ret;
7204
7205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7206 if (trk->st->nb_frames == 1)
7207 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7208 " ignoring.\n", pkt->stream_index);
7209 return 0;
7210 }
7211
7212
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7213 return ret;
7214
7215 2 return 0;
7216 } else {
7217 int i;
7218
7219
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18213 times.
18222 if (!pkt->size)
7220 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7221
7222 /*
7223 * Subtitles require special handling.
7224 *
7225 * 1) For full complaince, every track must have a sample at
7226 * dts == 0, which is rarely true for subtitles. So, as soon
7227 * as we see any packet with dts > 0, write an empty subtitle
7228 * at dts == 0 for any subtitle track with no samples in it.
7229 *
7230 * 2) For each subtitle track, check if the current packet's
7231 * dts is past the duration of the last subtitle sample. If
7232 * so, we now need to write an end sample for that subtitle.
7233 *
7234 * This must be done conditionally to allow for subtitles that
7235 * immediately replace each other, in which case an end sample
7236 * is not needed, and is, in fact, actively harmful.
7237 *
7238 * 3) See mov_write_trailer for how the final end sample is
7239 * handled.
7240 */
7241
2/2
✓ Branch 0 taken 33041 times.
✓ Branch 1 taken 18213 times.
51254 for (i = 0; i < mov->nb_tracks; i++) {
7242 33041 MOVTrack *trk = &mov->tracks[i];
7243 int ret;
7244
7245
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 33038 times.
33041 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7246
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7247
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 (trk->entry == 0 || !trk->last_sample_is_subtitle_end)) {
7248 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7250 2 trk->last_sample_is_subtitle_end = 1;
7251 }
7252 }
7253
7254
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 18139 times.
18213 if (trk->squash_fragment_samples_to_one) {
7255 /*
7256 * If the track has to have its samples squashed into one sample,
7257 * we just take it into the track's queue.
7258 * This will then be utilized as the samples get written in either
7259 * mov_flush_fragment or when the mux is finalized in
7260 * mov_write_trailer.
7261 */
7262 74 int ret = AVERROR_BUG;
7263
7264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
7265 av_log(s, AV_LOG_ERROR,
7266 "Packets without a valid presentation timestamp are "
7267 "not supported with packet squashing!\n");
7268 return AVERROR(EINVAL);
7269 }
7270
7271 /* The following will reset pkt and is only allowed to be used
7272 * because we return immediately. afterwards. */
7273
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7274 pkt, NULL, 0)) < 0) {
7275 return ret;
7276 }
7277
7278 74 return 0;
7279 }
7280
7281
7282
4/4
✓ Branch 0 taken 7827 times.
✓ Branch 1 taken 10312 times.
✓ Branch 2 taken 3704 times.
✓ Branch 3 taken 4123 times.
18139 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7283 3704 AVPacket *opkt = pkt;
7284 int reshuffle_ret, ret;
7285
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3679 times.
3704 if (trk->is_unaligned_qt_rgb) {
7286
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 int64_t bpc = trk->par->bits_per_coded_sample != 15 ? trk->par->bits_per_coded_sample : 16;
7287 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7288 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7290 return reshuffle_ret;
7291 } else
7292 3679 reshuffle_ret = 0;
7293
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3466 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3704 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7294 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7296 goto fail;
7297
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7298 5 trk->pal_done++;
7299
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2874 times.
3699 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7300
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7302 ret = av_packet_make_writable(pkt);
7303 if (ret < 0)
7304 goto fail;
7305 for (i = 0; i < pkt->size; i++)
7306 pkt->data[i] = ~pkt->data[i];
7307 }
7308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3704 times.
3704 if (reshuffle_ret) {
7309 ret = mov_write_single_packet(s, pkt);
7310 fail:
7311 if (reshuffle_ret)
7312 av_packet_free(&pkt);
7313 return ret;
7314 }
7315 }
7316
7317 18139 return mov_write_single_packet(s, pkt);
7318 }
7319 }
7320
7321 // QuickTime chapters involve an additional text track with the chapter names
7322 // as samples, and a tref pointing from the other tracks to the chapter one.
7323 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7324 {
7325 static const uint8_t stub_header[] = {
7326 // TextSampleEntry
7327 0x00, 0x00, 0x00, 0x01, // displayFlags
7328 0x00, 0x00, // horizontal + vertical justification
7329 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7330 // BoxRecord
7331 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7332 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7333 // StyleRecord
7334 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7335 0x00, 0x01, // fontID
7336 0x00, 0x00, // fontStyleFlags + fontSize
7337 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7338 // FontTableBox
7339 0x00, 0x00, 0x00, 0x0D, // box size
7340 'f', 't', 'a', 'b', // box atom name
7341 0x00, 0x01, // entry count
7342 // FontRecord
7343 0x00, 0x01, // font ID
7344 0x00, // font name length
7345 };
7346 1 MOVMuxContext *mov = s->priv_data;
7347 1 MOVTrack *track = &mov->tracks[tracknum];
7348 1 AVPacket *pkt = mov->pkt;
7349 int i, len;
7350 int ret;
7351
7352 1 track->mode = mov->mode;
7353 1 track->tag = MKTAG('t','e','x','t');
7354 1 track->timescale = mov->movie_timescale;
7355 1 track->par = avcodec_parameters_alloc();
7356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7357 return AVERROR(ENOMEM);
7358 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7359 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7361 return ret;
7362 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7363
7364 1 pkt->stream_index = tracknum;
7365 1 pkt->flags = AV_PKT_FLAG_KEY;
7366
7367
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7368 4 AVChapter *c = s->chapters[i];
7369 AVDictionaryEntry *t;
7370
7371 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7372 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7373 4 pkt->duration = end - pkt->dts;
7374
7375
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7376 static const char encd[12] = {
7377 0x00, 0x00, 0x00, 0x0C,
7378 'e', 'n', 'c', 'd',
7379 0x00, 0x00, 0x01, 0x00 };
7380 4 len = strlen(t->value);
7381 4 pkt->size = len + 2 + 12;
7382 4 pkt->data = av_malloc(pkt->size);
7383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7384 av_packet_unref(pkt);
7385 return AVERROR(ENOMEM);
7386 }
7387 4 AV_WB16(pkt->data, len);
7388 4 memcpy(pkt->data + 2, t->value, len);
7389 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7390 4 ff_mov_write_packet(s, pkt);
7391 4 av_freep(&pkt->data);
7392 }
7393 }
7394
7395 1 av_packet_unref(mov->pkt);
7396
7397 1 return 0;
7398 }
7399
7400
7401 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7402 {
7403 int ret;
7404
7405 /* compute the frame number */
7406 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7407 13 return ret;
7408 }
7409
7410 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7411 {
7412 6 MOVMuxContext *mov = s->priv_data;
7413 6 MOVTrack *track = &mov->tracks[index];
7414 6 AVStream *src_st = mov->tracks[src_index].st;
7415 uint8_t data[4];
7416 6 AVPacket *pkt = mov->pkt;
7417 6 AVRational rate = src_st->avg_frame_rate;
7418 int ret;
7419
7420 /* tmcd track based on video stream */
7421 6 track->mode = mov->mode;
7422 6 track->tag = MKTAG('t','m','c','d');
7423 6 track->src_track = src_index;
7424 6 track->timescale = mov->tracks[src_index].timescale;
7425
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7426 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7427
7428 /* set st to src_st for metadata access*/
7429 6 track->st = src_st;
7430
7431 /* encode context: tmcd data stream */
7432 6 track->par = avcodec_parameters_alloc();
7433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7434 return AVERROR(ENOMEM);
7435 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7436 6 track->par->codec_tag = track->tag;
7437 6 track->st->avg_frame_rate = rate;
7438
7439 /* the tmcd track just contains one packet with the frame number */
7440 6 pkt->data = data;
7441 6 pkt->stream_index = index;
7442 6 pkt->flags = AV_PKT_FLAG_KEY;
7443 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7444 6 pkt->size = 4;
7445 6 AV_WB32(pkt->data, tc.start);
7446 6 ret = ff_mov_write_packet(s, pkt);
7447 6 av_packet_unref(pkt);
7448 6 return ret;
7449 }
7450
7451 /*
7452 * st->disposition controls the "enabled" flag in the tkhd tag.
7453 * QuickTime will not play a track if it is not enabled. So make sure
7454 * that one track of each type (audio, video, subtitle) is enabled.
7455 *
7456 * Subtitles are special. For audio and video, setting "enabled" also
7457 * makes the track "default" (i.e. it is rendered when played). For
7458 * subtitles, an "enabled" subtitle is not rendered by default, but
7459 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7460 * empty!
7461 */
7462 211 static void enable_tracks(AVFormatContext *s)
7463 {
7464 211 MOVMuxContext *mov = s->priv_data;
7465 int i;
7466 int enabled[AVMEDIA_TYPE_NB];
7467 int first[AVMEDIA_TYPE_NB];
7468
7469
2/2
✓ Branch 0 taken 1055 times.
✓ Branch 1 taken 211 times.
1266 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7470 1055 enabled[i] = 0;
7471 1055 first[i] = -1;
7472 }
7473
7474
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 211 times.
482 for (i = 0; i < mov->nb_streams; i++) {
7475 271 AVStream *st = mov->tracks[i].st;
7476
7477
1/2
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
271 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7478
3/4
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 269 times.
542 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7479 271 is_cover_image(st))
7480 2 continue;
7481
7482
2/2
✓ Branch 0 taken 254 times.
✓ Branch 1 taken 15 times.
269 if (first[st->codecpar->codec_type] < 0)
7483 254 first[st->codecpar->codec_type] = i;
7484
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 238 times.
269 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7485 31 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7486 31 enabled[st->codecpar->codec_type]++;
7487 }
7488 }
7489
7490
2/2
✓ Branch 0 taken 1055 times.
✓ Branch 1 taken 211 times.
1266 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7491
2/2
✓ Branch 0 taken 633 times.
✓ Branch 1 taken 422 times.
1055 switch (i) {
7492 633 case AVMEDIA_TYPE_VIDEO:
7493 case AVMEDIA_TYPE_AUDIO:
7494 case AVMEDIA_TYPE_SUBTITLE:
7495
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 632 times.
633 if (enabled[i] > 1)
7496 1 mov->per_stream_grouping = 1;
7497
4/4
✓ Branch 0 taken 607 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 226 times.
✓ Branch 3 taken 381 times.
633 if (!enabled[i] && first[i] >= 0)
7498 226 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7499 633 break;
7500 }
7501 }
7502 211 }
7503
7504 211 static void mov_free(AVFormatContext *s)
7505 {
7506 211 MOVMuxContext *mov = s->priv_data;
7507
7508
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 211 times.
503 for (int i = 0; i < s->nb_streams; i++)
7509 292 s->streams[i]->priv_data = NULL;
7510
7511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (!mov->tracks)
7512 return;
7513
7514
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->chapter_track) {
7515 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7516 }
7517
7518
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 211 times.
491 for (int i = 0; i < mov->nb_tracks; i++) {
7519 280 MOVTrack *const track = &mov->tracks[i];
7520
7521
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 278 times.
280 if (track->tag == MKTAG('r','t','p',' '))
7522 2 ff_mov_close_hinting(track);
7523
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 269 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
278 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7524 6 av_freep(&track->par);
7525 280 av_freep(&track->cluster);
7526 280 av_freep(&track->cluster_written);
7527 280 av_freep(&track->frag_info);
7528 280 av_packet_free(&track->cover_image);
7529
7530
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 275 times.
280 if (track->eac3_priv) {
7531 5 struct eac3_info *info = track->eac3_priv;
7532 5 av_packet_free(&info->pkt);
7533 5 av_freep(&track->eac3_priv);
7534 }
7535
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 137 times.
280 if (track->vos_len)
7536 143 av_freep(&track->vos_data);
7537
7538 280 ff_mov_cenc_free(&track->cenc);
7539 280 ffio_free_dyn_buf(&track->mdat_buf);
7540
7541 #if CONFIG_IAMFENC
7542 280 ffio_free_dyn_buf(&track->iamf_buf);
7543
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 275 times.
280 if (track->iamf)
7544 5 ff_iamf_uninit_context(track->iamf);
7545 280 av_freep(&track->iamf);
7546 #endif
7547
7548 280 avpriv_packet_list_free(&track->squashed_packet_queue);
7549 }
7550
7551 211 av_freep(&mov->tracks);
7552 211 ffio_free_dyn_buf(&mov->mdat_buf);
7553 }
7554
7555 static uint32_t rgb_to_yuv(uint32_t rgb)
7556 {
7557 uint8_t r, g, b;
7558 int y, cb, cr;
7559
7560 r = (rgb >> 16) & 0xFF;
7561 g = (rgb >> 8) & 0xFF;
7562 b = (rgb ) & 0xFF;
7563
7564 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7565 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7566 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7567
7568 return (y << 16) | (cr << 8) | cb;
7569 }
7570
7571 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7572 AVStream *st)
7573 {
7574 int i, width = 720, height = 480;
7575 int have_palette = 0, have_size = 0;
7576 uint32_t palette[16];
7577 char *cur = st->codecpar->extradata;
7578
7579 while (cur && *cur) {
7580 if (strncmp("palette:", cur, 8) == 0) {
7581 int i, count;
7582 count = sscanf(cur + 8,
7583 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7584 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7585 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7586 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7587 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7588 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7589 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7590 &palette[12], &palette[13], &palette[14], &palette[15]);
7591
7592 for (i = 0; i < count; i++) {
7593 palette[i] = rgb_to_yuv(palette[i]);
7594 }
7595 have_palette = 1;
7596 } else if (!strncmp("size:", cur, 5)) {
7597 sscanf(cur + 5, "%dx%d", &width, &height);
7598 have_size = 1;
7599 }
7600 if (have_palette && have_size)
7601 break;
7602 cur += strcspn(cur, "\n\r");
7603 cur += strspn(cur, "\n\r");
7604 }
7605 if (have_palette) {
7606 track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7607 if (!track->vos_data)
7608 return AVERROR(ENOMEM);
7609 for (i = 0; i < 16; i++) {
7610 AV_WB32(track->vos_data + i * 4, palette[i]);
7611 }
7612 memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7613 track->vos_len = 16 * 4;
7614 }
7615 st->codecpar->width = width;
7616 st->codecpar->height = track->height = height;
7617
7618 return 0;
7619 }
7620
7621 #if CONFIG_IAMFENC
7622 211 static int mov_init_iamf_track(AVFormatContext *s)
7623 {
7624 211 MOVMuxContext *mov = s->priv_data;
7625 MOVTrack *track;
7626 IAMFContext *iamf;
7627 211 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7628 211 int nb_audio_elements = 0, nb_mix_presentations = 0;
7629 int ret;
7630
7631
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 211 times.
221 for (int i = 0; i < s->nb_stream_groups; i++) {
7632 10 const AVStreamGroup *stg = s->stream_groups[i];
7633
7634
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7635 5 nb_audio_elements++;
7636
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7637 5 nb_mix_presentations++;
7638 }
7639
7640
3/4
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 206 times.
✗ Branch 3 not taken.
211 if (!nb_audio_elements && !nb_mix_presentations)
7641 206 return 0;
7642
7643
3/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 if (nb_audio_elements < 1 || nb_audio_elements > 2 || nb_mix_presentations < 1) {
7644 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7645 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7646 return AVERROR(EINVAL);
7647 }
7648
7649 5 iamf = av_mallocz(sizeof(*iamf));
7650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7651 return AVERROR(ENOMEM);
7652
7653
7654
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7655 10 const AVStreamGroup *stg = s->stream_groups[i];
7656
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7657 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7658
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7659 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7660 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7661 }
7662
7663 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7664 5 break;
7665 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7666 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7667 5 break;
7668 default:
7669 av_assert0(0);
7670 }
7671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7672 return ret;
7673 }
7674
7675 5 track = &mov->tracks[first_iamf_idx];
7676 5 track->iamf = iamf;
7677 5 track->first_iamf_idx = first_iamf_idx;
7678 5 track->last_iamf_idx = last_iamf_idx;
7679 5 track->tag = MKTAG('i','a','m','f');
7680
7681
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7682 10 AVStreamGroup *stg = s->stream_groups[i];
7683
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7684 5 continue;
7685
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7686 25 stg->streams[j]->priv_data = track;
7687 }
7688
7689 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7691 return ret;
7692
7693 5 return 0;
7694 }
7695 #endif
7696
7697 211 static int mov_init(AVFormatContext *s)
7698 {
7699 211 MOVMuxContext *mov = s->priv_data;
7700 211 int has_iamf = 0;
7701 int i, ret;
7702
7703 211 mov->fc = s;
7704 211 mov->pkt = ffformatcontext(s)->pkt;
7705
7706 /* Default mode == MP4 */
7707 211 mov->mode = MODE_MP4;
7708
7709 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7712
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 64 times.
211 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7713
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 63 times.
64 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7714
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7715
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 58 times.
62 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7718 #undef IS_MODE
7719
7720
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 194 times.
211 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7721 17 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7722
7723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (mov->mode == MODE_AVIF)
7724 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7725
7726 /* Set the FRAGMENT flag if any of the fragmentation methods are
7727 * enabled. */
7728
3/4
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 209 times.
✗ Branch 3 not taken.
211 if (mov->max_fragment_duration || mov->max_fragment_size ||
7729
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 180 times.
209 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7730 FF_MOV_FLAG_FRAG_KEYFRAME |
7731 FF_MOV_FLAG_FRAG_CUSTOM |
7732 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7733 31 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7734
7735
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 209 times.
211 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
7736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
7737 av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
7738 return AVERROR(EINVAL);
7739 }
7740
7741 /* Set other implicit flags immediately */
7742
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 209 times.
211 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7743 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7744
7745
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 207 times.
211 if (mov->mode == MODE_ISM)
7746 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7747 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7748
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 200 times.
211 if (mov->flags & FF_MOV_FLAG_DASH)
7749 11 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7750 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7751
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->flags & FF_MOV_FLAG_CMAF)
7752 1 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7753 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7754
7755
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 1 times.
211 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
7756 30 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7757 30 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7758 }
7759
7760
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
211 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
7761 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7762 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7763 }
7764
7765
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 208 times.
211 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7766 3 mov->reserved_moov_size = -1;
7767 }
7768
7769
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 7 times.
211 if (mov->use_editlist < 0) {
7770 204 mov->use_editlist = 1;
7771
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 176 times.
204 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7772
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 15 times.
28 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7773 // If we can avoid needing an edit list by shifting the
7774 // tracks, prefer that over (trying to) write edit lists
7775 // in fragmented output.
7776
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
13 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7777
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7778 12 mov->use_editlist = 0;
7779 }
7780 }
7781
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 180 times.
211 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7782
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
31 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
7783 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7784
7785
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 1 times.
211 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
7786
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7787 11 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7788
7789 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7790 * if the latter is set that's enough and omit_tfhd_offset doesn't
7791 * add anything extra on top of that. */
7792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7793 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7794 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7795
7796
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->frag_interleave &&
7797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
7798 av_log(s, AV_LOG_ERROR,
7799 "Sample interleaving in fragments is mutually exclusive with "
7800 "omit_tfhd_offset and separate_moof\n");
7801 return AVERROR(EINVAL);
7802 }
7803
7804 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7805 * is enabled, we don't support non-seekable output at all. */
7806
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 183 times.
211 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7807
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
7808
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7809 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7810 return AVERROR(EINVAL);
7811 }
7812
7813 /* AVIF output must have at most two video streams (one for YUV and one for
7814 * alpha). */
7815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (mov->mode == MODE_AVIF) {
7816 if (s->nb_streams > 2) {
7817 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7818 return AVERROR(EINVAL);
7819 }
7820 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7821 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7822 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7823 return AVERROR(EINVAL);
7824 }
7825 if (s->nb_streams > 1) {
7826 const AVPixFmtDescriptor *pixdesc =
7827 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7828 if (pixdesc->nb_components != 1) {
7829 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7830 return AVERROR(EINVAL);
7831 }
7832 }
7833 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7834 }
7835
7836 #if CONFIG_IAMFENC
7837
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 211 times.
221 for (i = 0; i < s->nb_stream_groups; i++) {
7838 10 AVStreamGroup *stg = s->stream_groups[i];
7839
7840
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7841 5 continue;
7842
7843
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7844 25 AVStream *st = stg->streams[j];
7845
7846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
7847 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7848 "IAMF Audio Element\n", j);
7849 return AVERROR(EINVAL);
7850 }
7851 25 st->priv_data = st;
7852 }
7853 5 has_iamf = 1;
7854
7855
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (!mov->nb_tracks) // We support one track for the entire IAMF structure
7856 5 mov->nb_tracks++;
7857 }
7858 #endif
7859
7860
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 211 times.
503 for (i = 0; i < s->nb_streams; i++) {
7861 292 AVStream *st = s->streams[i];
7862
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 267 times.
292 if (st->priv_data)
7863 25 continue;
7864 // Don't produce a track in the output file for timed ID3 streams.
7865
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 266 times.
267 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7866 // Leave priv_data set to NULL for these AVStreams that don't
7867 // have a corresponding track.
7868 1 continue;
7869 }
7870 266 st->priv_data = st;
7871 266 mov->nb_tracks++;
7872 }
7873
7874 211 mov->nb_streams = mov->nb_tracks;
7875
7876
4/4
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 205 times.
211 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
7877 1 mov->chapter_track = mov->nb_tracks++;
7878
7879
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7880
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
7881
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
7882 2 mov->nb_tracks++;
7883 }
7884
7885
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 if (mov->write_btrt < 0) {
7886 211 mov->write_btrt = mov->mode == MODE_MP4;
7887 }
7888
7889
6/6
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 147 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 58 times.
211 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
7890
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
7891 208 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
7892 NULL, 0);
7893
7894 /* +1 tmcd track for each video stream with a timecode */
7895
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 208 times.
495 for (i = 0; i < s->nb_streams; i++) {
7896 287 AVStream *st = s->streams[i];
7897 287 AVDictionaryEntry *t = global_tcr;
7898
4/4
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 7 times.
287 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
7899
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
7900 AVTimecode tc;
7901 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
7902
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
7903 7 mov->nb_meta_tmcd++;
7904 }
7905 }
7906
7907 /* check if there is already a tmcd track to remux */
7908
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 201 times.
208 if (mov->nb_meta_tmcd) {
7909
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
7910 13 AVStream *st = s->streams[i];
7911
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
7912 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
7913 "so timecode metadata are now ignored\n");
7914 3 mov->nb_meta_tmcd = 0;
7915 }
7916 }
7917 }
7918
7919 208 mov->nb_tracks += mov->nb_meta_tmcd;
7920 }
7921
7922 // Reserve an extra stream for chapters for the case where chapters
7923 // are written in the trailer
7924 211 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
7925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (!mov->tracks)
7926 return AVERROR(ENOMEM);
7927
7928
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
211 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
7929 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
7930 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
7931
7932 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
7933 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
7934 mov->encryption_key_len, AES_CTR_KEY_SIZE);
7935 return AVERROR(EINVAL);
7936 }
7937
7938 if (mov->encryption_kid_len != CENC_KID_SIZE) {
7939 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
7940 mov->encryption_kid_len, CENC_KID_SIZE);
7941 return AVERROR(EINVAL);
7942 }
7943 } else {
7944 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
7945 mov->encryption_scheme_str);
7946 return AVERROR(EINVAL);
7947 }
7948 }
7949
7950 #if CONFIG_IAMFENC
7951 211 ret = mov_init_iamf_track(s);
7952
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (ret < 0)
7953 return ret;
7954 #endif
7955
7956
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 211 times.
503 for (int j = 0, i = 0; j < s->nb_streams; j++) {
7957 292 AVStream *st = s->streams[j];
7958
7959
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 266 times.
292 if (st != st->priv_data) {
7960
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
7961 5 i += has_iamf--;
7962 26 continue;
7963 }
7964 266 st->priv_data = &mov->tracks[i++];
7965 }
7966
7967
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 211 times.
503 for (i = 0; i < s->nb_streams; i++) {
7968 292 AVStream *st= s->streams[i];
7969 292 MOVTrack *track = st->priv_data;
7970 292 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
7971
7972
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 291 times.
292 if (!track)
7973 1 continue;
7974
7975
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 20 times.
291 if (!track->st) {
7976 271 track->st = st;
7977 271 track->par = st->codecpar;
7978 }
7979
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 265 times.
291 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
7980
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 136 times.
291 if (track->language < 0)
7981 155 track->language = 32767; // Unspecified Macintosh language code
7982 291 track->mode = mov->mode;
7983
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 25 times.
291 if (!track->tag)
7984 266 track->tag = mov_find_codec_tag(s, track);
7985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 291 times.
291 if (!track->tag) {
7986 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
7987 "codec not currently supported in container\n",
7988 avcodec_get_name(st->codecpar->codec_id), i);
7989 return AVERROR(EINVAL);
7990 }
7991 /* If hinting of this track is enabled by a later hint track,
7992 * this is updated. */
7993 291 track->hint_track = -1;
7994 291 track->start_dts = AV_NOPTS_VALUE;
7995 291 track->start_cts = AV_NOPTS_VALUE;
7996 291 track->end_pts = AV_NOPTS_VALUE;
7997 291 track->dts_shift = AV_NOPTS_VALUE;
7998
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 108 times.
291 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7999
2/4
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 183 times.
✗ Branch 3 not taken.
183 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8000
2/4
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 183 times.
✗ Branch 3 not taken.
183 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8001
2/4
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
183 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8002 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8003 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8004 return AVERROR(EINVAL);
8005 }
8006 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8007 }
8008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
183 if (mov->video_track_timescale) {
8009 track->timescale = mov->video_track_timescale;
8010 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8011 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8012 } else {
8013 183 track->timescale = st->time_base.den;
8014
2/2
✓ Branch 0 taken 1476 times.
✓ Branch 1 taken 183 times.
1659 while(track->timescale < 10000)
8015 1476 track->timescale *= 2;
8016 }
8017
2/4
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
183 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8018 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8019 return AVERROR(EINVAL);
8020 }
8021
4/4
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 130 times.
183 if (track->mode == MODE_MOV && track->timescale > 100000)
8022 2 av_log(s, AV_LOG_WARNING,
8023 "WARNING codec timebase is very high. If duration is too long,\n"
8024 "file may not be playable by quicktime. Specify a shorter timebase\n"
8025 "or choose different container.\n");
8026
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 51 times.
183 if (track->mode == MODE_MOV &&
8027
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 115 times.
132 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8028
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8029 1 enum AVPixelFormat pix_fmt = track->par->format;
8030
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (pix_fmt == AV_PIX_FMT_NONE && track->par->bits_per_coded_sample == 1)
8031 pix_fmt = AV_PIX_FMT_MONOWHITE;
8032 1 track->is_unaligned_qt_rgb =
8033 pix_fmt == AV_PIX_FMT_RGB24 ||
8034 pix_fmt == AV_PIX_FMT_BGR24 ||
8035 pix_fmt == AV_PIX_FMT_PAL8 ||
8036 pix_fmt == AV_PIX_FMT_GRAY8 ||
8037
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 pix_fmt == AV_PIX_FMT_MONOWHITE ||
8038 pix_fmt == AV_PIX_FMT_MONOBLACK;
8039 }
8040
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
183 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8041 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8042 return AVERROR(EINVAL);
8043
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 182 times.
183 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8044
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8045 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8046 return AVERROR(EINVAL);
8047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
183 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8048 /* altref frames handling is not defined in the spec as of version v1.0,
8049 * so just forbid muxing VP8 streams altogether until a new version does */
8050 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8051 return AVERROR_PATCHWELCOME;
8052 }
8053
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 181 times.
183 if (is_cover_image(st)) {
8054 2 track->cover_image = av_packet_alloc();
8055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8056 return AVERROR(ENOMEM);
8057 }
8058
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 7 times.
108 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8059 101 track->timescale = st->codecpar->sample_rate;
8060
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 69 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 26 times.
101 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8061 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8062 6 track->audio_vbr = 1;
8063
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8064
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8066 if (!st->codecpar->block_align) {
8067 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8068 return AVERROR(EINVAL);
8069 }
8070 track->sample_size = st->codecpar->block_align;
8071
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 26 times.
95 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8072 69 track->audio_vbr = 1;
8073 }else{
8074 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8075 26 st->codecpar->ch_layout.nb_channels;
8076 }
8077
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8079 track->audio_vbr = 1;
8080 }
8081
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 32 times.
101 if (track->mode != MODE_MOV &&
8082
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
69 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8083 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8084 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8085 i, track->par->sample_rate);
8086 return AVERROR(EINVAL);
8087 } else {
8088 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8089 i, track->par->sample_rate);
8090 }
8091 }
8092
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 25 times.
101 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8093
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8094
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
76 track->par->codec_id == AV_CODEC_ID_OPUS) {
8095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8096 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8097 return AVERROR(EINVAL);
8098 }
8099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8100 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8101 av_log(s, AV_LOG_ERROR,
8102 "%s in MP4 support is experimental, add "
8103 "'-strict %d' if you want to use it.\n",
8104 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8105 return AVERROR_EXPERIMENTAL;
8106 }
8107 }
8108
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8109 3 track->timescale = st->time_base.den;
8110
8111
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8112 /* 14496-30 requires us to use a single sample per fragment
8113 for TTML, for which we define a per-track flag.
8114
8115 We set the flag in case we are receiving TTML paragraphs
8116 from the input, in other words in case we are not doing
8117 stream copy. */
8118 2 track->squash_fragment_samples_to_one =
8119 2 ff_is_ttml_stream_paragraph_based(track->par);
8120
8121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8122 track->squash_fragment_samples_to_one) {
8123 av_log(s, AV_LOG_ERROR,
8124 "Fragmentation is not currently supported for "
8125 "TTML in MP4/ISMV (track synchronization between "
8126 "subtitles and other media is not yet implemented)!\n");
8127 return AVERROR_PATCHWELCOME;
8128 }
8129
8130
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
8131
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8133 av_log(s, AV_LOG_ERROR,
8134 "ISMV style TTML support with the 'dfxp' tag in "
8135 "non-ISMV formats is not officially supported. Add "
8136 "'-strict unofficial' if you want to use it.\n");
8137 return AVERROR_EXPERIMENTAL;
8138 }
8139 }
8140
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8141 4 track->timescale = st->time_base.den;
8142 } else {
8143 track->timescale = mov->movie_timescale;
8144 }
8145
1/2
✓ Branch 0 taken 291 times.
✗ Branch 1 not taken.
291 if (!track->height)
8146 291 track->height = st->codecpar->height;
8147 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8148 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8149 for video tracks, so if user-set, it isn't overwritten */
8150
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 286 times.
291 if (mov->mode == MODE_ISM &&
8151
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8152
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !mov->video_track_timescale))) {
8153 5 track->timescale = 10000000;
8154 }
8155
8156 291 avpriv_set_pts_info(st, 64, 1, track->timescale);
8157
8158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 291 times.
291 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8159 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8160 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8161 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8162 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8163 if (ret)
8164 return ret;
8165 }
8166 }
8167
8168 211 enable_tracks(s);
8169 211 return 0;
8170 }
8171
8172 211 static int mov_write_header(AVFormatContext *s)
8173 {
8174 211 AVIOContext *pb = s->pb;
8175 211 MOVMuxContext *mov = s->priv_data;
8176 211 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8177
8178
4/4
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 205 times.
211 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8179 1 nb_tracks++;
8180
8181
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8182 1 hint_track = nb_tracks;
8183
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8184
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8185 2 nb_tracks++;
8186 }
8187 }
8188
8189
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 205 times.
211 if (mov->nb_meta_tmcd)
8190 6 tmcd_track = nb_tracks;
8191
8192
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 211 times.
482 for (int i = 0; i < mov->nb_streams; i++) {
8193 271 MOVTrack *track = &mov->tracks[i];
8194 271 AVStream *st = track->st;
8195
8196 /* copy extradata if it exists */
8197
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 154 times.
271 if (st->codecpar->extradata_size) {
8198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8199 mov_create_dvd_sub_decoder_specific_info(track, st);
8200
15/30
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 117 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 117 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 117 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 117 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 117 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 117 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 117 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 117 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 117 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 117 times.
✗ Branch 29 not taken.
117 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8201 117 track->vos_len = st->codecpar->extradata_size;
8202 117 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!track->vos_data) {
8204 return AVERROR(ENOMEM);
8205 }
8206 117 memcpy(track->vos_data, st->codecpar->extradata, track->vos_len);
8207 117 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8208 }
8209 }
8210
8211
4/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 14 times.
352 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8212 81 av_channel_layout_compare(&track->par->ch_layout,
8213 81 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8214 257 continue;
8215
8216
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8217 33 AVStream *stj= mov->tracks[j].st;
8218 33 MOVTrack *trackj= &mov->tracks[j];
8219
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8220 14 continue;
8221
8222
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8223
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
18 (trackj->par->ch_layout.nb_channels != 1 ||
8224 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8225 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8226 )
8227 4 track->mono_as_fc = -1;
8228
8229
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
30 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8230 11 av_channel_layout_compare(&trackj->par->ch_layout,
8231 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8232
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
11 trackj->par->ch_layout.nb_channels == 1 && track->mono_as_fc >= 0
8233 )
8234 7 track->mono_as_fc++;
8235
8236
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
30 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8237 11 av_channel_layout_compare(&trackj->par->ch_layout,
8238 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8239 trackj->language != track->language ||
8240 trackj->tag != track->tag
8241 )
8242 19 continue;
8243 track->multichannel_as_mono++;
8244 }
8245 }
8246
8247
2/2
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 17 times.
211 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8248
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 194 times.
194 if ((ret = mov_write_identification(pb, s)) < 0)
8249 return ret;
8250 }
8251
8252
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 208 times.
211 if (mov->reserved_moov_size){
8253 3 mov->reserved_header_pos = avio_tell(pb);
8254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8255 avio_skip(pb, mov->reserved_moov_size);
8256 }
8257
8258
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 176 times.
211 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8259 /* If no fragmentation options have been set, set a default. */
8260
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 30 times.
35 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8261 FF_MOV_FLAG_FRAG_CUSTOM |
8262 5 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8263
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
5 !mov->max_fragment_duration && !mov->max_fragment_size)
8264 4 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8265
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 33 times.
35 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8266 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8267
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8268 2 mov->mdat_pos = avio_tell(pb);
8269 }
8270
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 } else if (mov->mode != MODE_AVIF) {
8271
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 173 times.
176 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8272 3 mov->reserved_header_pos = avio_tell(pb);
8273 176 mov_write_mdat_tag(pb, mov);
8274 }
8275
8276 211 ff_parse_creation_time_metadata(s, &mov->time, 1);
8277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (mov->time)
8278 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8279
8280
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->chapter_track)
8281
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8282 return ret;
8283
8284
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
211 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8285
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8286
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8288 return ret;
8289 2 hint_track++;
8290 }
8291 }
8292 }
8293
8294
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 205 times.
211 if (mov->nb_meta_tmcd) {
8295 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8296 "timecode", NULL, 0);
8297 /* Initialize the tmcd tracks */
8298
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8299 8 AVStream *st = mov->tracks[i].st;
8300 8 t = global_tcr;
8301
8302
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8303 AVTimecode tc;
8304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8305 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8307 continue;
8308
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8309 continue;
8310
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8311 return ret;
8312 6 tmcd_track++;
8313 }
8314 }
8315 }
8316
8317 211 avio_flush(pb);
8318
8319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (mov->flags & FF_MOV_FLAG_ISML)
8320 mov_write_isml_manifest(pb, mov, s);
8321
8322
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 180 times.
211 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8323
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 17 times.
31 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8324
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8325 return ret;
8326 14 mov->moov_written = 1;
8327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8328 mov->reserved_header_pos = avio_tell(pb);
8329 }
8330
8331 211 return 0;
8332 }
8333
8334 27 static int get_moov_size(AVFormatContext *s)
8335 {
8336 int ret;
8337 AVIOContext *moov_buf;
8338 27 MOVMuxContext *mov = s->priv_data;
8339
8340
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8341 return ret;
8342
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8343 return ret;
8344 27 return ffio_close_null_buf(moov_buf);
8345 }
8346
8347 static int get_sidx_size(AVFormatContext *s)
8348 {
8349 int ret;
8350 AVIOContext *buf;
8351 MOVMuxContext *mov = s->priv_data;
8352
8353 if ((ret = ffio_open_null_buf(&buf)) < 0)
8354 return ret;
8355 mov_write_sidx_tags(buf, mov, -1, 0);
8356 return ffio_close_null_buf(buf);
8357 }
8358
8359 /*
8360 * This function gets the moov size if moved to the top of the file: the chunk
8361 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8362 * entries) when the moov is moved to the beginning, so the size of the moov
8363 * would change. It also updates the chunk offset tables.
8364 */
8365 3 static int compute_moov_size(AVFormatContext *s)
8366 {
8367 int i, moov_size, moov_size2;
8368 3 MOVMuxContext *mov = s->priv_data;
8369
8370 3 moov_size = get_moov_size(s);
8371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8372 return moov_size;
8373
8374
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8375 8 mov->tracks[i].data_offset += moov_size;
8376
8377 3 moov_size2 = get_moov_size(s);
8378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8379 return moov_size2;
8380
8381 /* if the size changed, we just switched from stco to co64 and need to
8382 * update the offsets */
8383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8384 for (i = 0; i < mov->nb_tracks; i++)
8385 mov->tracks[i].data_offset += moov_size2 - moov_size;
8386
8387 3 return moov_size2;
8388 }
8389
8390 static int compute_sidx_size(AVFormatContext *s)
8391 {
8392 int i, sidx_size;
8393 MOVMuxContext *mov = s->priv_data;
8394
8395 sidx_size = get_sidx_size(s);
8396 if (sidx_size < 0)
8397 return sidx_size;
8398
8399 for (i = 0; i < mov->nb_tracks; i++)
8400 mov->tracks[i].data_offset += sidx_size;
8401
8402 return sidx_size;
8403 }
8404
8405 3 static int shift_data(AVFormatContext *s)
8406 {
8407 int moov_size;
8408 3 MOVMuxContext *mov = s->priv_data;
8409
8410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8411 moov_size = compute_sidx_size(s);
8412 else
8413 3 moov_size = compute_moov_size(s);
8414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8415 return moov_size;
8416
8417 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8418 }
8419
8420 211 static int mov_write_trailer(AVFormatContext *s)
8421 {
8422 211 MOVMuxContext *mov = s->priv_data;
8423 211 AVIOContext *pb = s->pb;
8424 211 int res = 0;
8425 int i;
8426 int64_t moov_pos;
8427
8428
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 206 times.
211 if (mov->need_rewrite_extradata) {
8429
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
12 for (i = 0; i < mov->nb_streams; i++) {
8430 7 MOVTrack *track = &mov->tracks[i];
8431 7 AVCodecParameters *par = track->par;
8432
8433 7 track->vos_len = par->extradata_size;
8434 7 av_freep(&track->vos_data);
8435 7 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!track->vos_data)
8437 return AVERROR(ENOMEM);
8438 7 memcpy(track->vos_data, par->extradata, track->vos_len);
8439 7 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8440 }
8441 5 mov->need_rewrite_extradata = 0;
8442 }
8443
8444 /*
8445 * Before actually writing the trailer, make sure that there are no
8446 * dangling subtitles, that need a terminating sample.
8447 */
8448
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 211 times.
491 for (i = 0; i < mov->nb_tracks; i++) {
8449 280 MOVTrack *trk = &mov->tracks[i];
8450
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
280 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8451
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8452 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8453 1 trk->last_sample_is_subtitle_end = 1;
8454 }
8455 }
8456
8457 // Check if we have any tracks that require squashing.
8458 // In that case, we'll have to write the packet here.
8459
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 211 times.
211 if ((res = mov_write_squashed_packets(s)) < 0)
8460 return res;
8461
8462 // If there were no chapters when the header was written, but there
8463 // are chapters now, write them in the trailer. This only works
8464 // when we are not doing fragments.
8465
4/4
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 35 times.
211 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
8466
3/4
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 174 times.
175 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
8467 mov->chapter_track = mov->nb_tracks++;
8468 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8469 return res;
8470 }
8471 }
8472
8473
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 176 times.
211 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8474
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 33 times.
35 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8475
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 176 times.
178 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8476 2 mov_flush_fragment(s, 1);
8477 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8478
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
8479 4 MOVTrack *track = &mov->tracks[i];
8480 4 track->data_offset = 0;
8481 4 av_free(track->cluster);
8482 4 track->cluster = track->cluster_written;
8483 4 track->entry = track->entry_written;
8484 4 track->cluster_written = NULL;
8485 4 track->entry_written = 0;
8486 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8487 }
8488 // Clear the empty_moov flag, as we do want the moov to include
8489 // all the samples at this point.
8490 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8491 }
8492
8493 178 moov_pos = avio_tell(pb);
8494
8495 /* Write size of mdat tag */
8496
1/2
✓ Branch 0 taken 178 times.
✗ Branch 1 not taken.
178 if (mov->mdat_size + 8 <= UINT32_MAX) {
8497 178 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8498 178 avio_wb32(pb, mov->mdat_size + 8);
8499
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 176 times.
178 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8500 2 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8501 } else {
8502 /* overwrite 'wide' placeholder atom */
8503 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8504 /* special value: real atom size will be 64 bit value after
8505 * tag field */
8506 avio_wb32(pb, 1);
8507 ffio_wfourcc(pb, "mdat");
8508 avio_wb64(pb, mov->mdat_size + 16);
8509 }
8510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 178 times.
178 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
8511
8512
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 175 times.
178 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8513 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8514 3 res = shift_data(s);
8515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8516 return res;
8517 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8518
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8519 return res;
8520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 175 times.
175 } else if (mov->reserved_moov_size > 0) {
8521 int64_t size;
8522 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8523 return res;
8524 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8525 if (size < 8){
8526 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8527 return AVERROR(EINVAL);
8528 }
8529 avio_wb32(pb, size);
8530 ffio_wfourcc(pb, "free");
8531 ffio_fill(pb, 0, size - 8);
8532 avio_seek(pb, moov_pos, SEEK_SET);
8533 } else {
8534
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
175 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8535 return res;
8536 }
8537 178 res = 0;
8538 } else {
8539 33 mov_auto_flush_fragment(s, 1);
8540
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++)
8541 63 mov->tracks[i].data_offset = 0;
8542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8543 int64_t end;
8544 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8545 res = shift_data(s);
8546 if (res < 0)
8547 return res;
8548 end = avio_tell(pb);
8549 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8550 mov_write_sidx_tags(pb, mov, -1, 0);
8551 avio_seek(pb, end, SEEK_SET);
8552 }
8553
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8554 33 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8555 33 res = mov_write_mfra_tag(pb, mov);
8556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (res < 0)
8557 return res;
8558 }
8559 }
8560
8561 211 return res;
8562 }
8563
8564 234 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8565 const AVPacket *pkt)
8566 {
8567 234 int ret = 1;
8568
8569
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 225 times.
234 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8570
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
8571 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
225 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8573 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8574 }
8575
8576 234 return ret;
8577 }
8578
8579 #if CONFIG_AVIF_MUXER
8580 static int avif_write_trailer(AVFormatContext *s)
8581 {
8582 AVIOContext *pb = s->pb;
8583 MOVMuxContext *mov = s->priv_data;
8584 int64_t pos_backup, extent_offsets[2];
8585 uint8_t *buf;
8586 int buf_size, moov_size;
8587
8588 if (mov->moov_written) return 0;
8589
8590 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8591 if (mov->is_animated_avif && mov->nb_streams > 1) {
8592 // For animated avif with alpha channel, we need to write a tref tag
8593 // with type "auxl".
8594 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8595 mov->tracks[1].tref_id = 1;
8596 }
8597 mov_write_identification(pb, s);
8598 mov_write_meta_tag(pb, mov, s);
8599
8600 moov_size = get_moov_size(s);
8601 for (int i = 0; i < mov->nb_tracks; i++)
8602 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8603
8604 if (mov->is_animated_avif) {
8605 int ret;
8606 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8607 return ret;
8608 }
8609
8610 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8611 avio_wb32(pb, buf_size + 8);
8612 ffio_wfourcc(pb, "mdat");
8613
8614 // The offset for the YUV planes is the starting position of mdat.
8615 extent_offsets[0] = avio_tell(pb);
8616 // The offset for alpha plane is YUV offset + YUV size.
8617 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8618
8619 avio_write(pb, buf, buf_size);
8620
8621 // write extent offsets.
8622 pos_backup = avio_tell(pb);
8623 for (int i = 0; i < mov->nb_streams; i++) {
8624 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8625 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8626 return AVERROR_INVALIDDATA;
8627 }
8628 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8629 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8630 }
8631 avio_seek(pb, pos_backup, SEEK_SET);
8632
8633 return 0;
8634 }
8635 #endif
8636
8637 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8638 static const AVCodecTag codec_3gp_tags[] = {
8639 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8640 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8641 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8642 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8643 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8644 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8645 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8646 { AV_CODEC_ID_NONE, 0 },
8647 };
8648 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8649 #endif
8650
8651 static const AVCodecTag codec_mp4_tags[] = {
8652 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8653 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8654 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8655 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8656 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8657 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8658 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8659 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8660 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8661 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8662 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8663 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8664 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8665 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8666 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8667 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8668 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8669 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8670 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8671 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8672 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8673 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8674 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8675 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8676 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8677 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8678 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8679 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8680 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8681 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8682 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8683 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8684 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8685 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8686 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8687 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8688 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8689 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8690 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8691 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8692
8693 /* ISO/IEC 23003-5 integer formats */
8694 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8695 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8696 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8697 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8698 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8699 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8700 /* ISO/IEC 23003-5 floating-point formats */
8701 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8702 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8703 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8704 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8705
8706 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
8707
8708 { AV_CODEC_ID_NONE, 0 },
8709 };
8710 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8711 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8712 #endif
8713
8714 static const AVCodecTag codec_ism_tags[] = {
8715 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8716 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8717 { AV_CODEC_ID_NONE , 0 },
8718 };
8719
8720 static const AVCodecTag codec_ipod_tags[] = {
8721 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8722 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8723 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8724 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8725 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8726 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8727 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8728 { AV_CODEC_ID_NONE, 0 },
8729 };
8730
8731 static const AVCodecTag codec_f4v_tags[] = {
8732 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8733 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8734 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8735 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8736 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8737 { AV_CODEC_ID_NONE, 0 },
8738 };
8739
8740 #if CONFIG_AVIF_MUXER
8741
8742 static const AVOption avif_options[] = {
8743 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8744 { "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 },
8745 { NULL },
8746 };
8747 static const AVCodecTag codec_avif_tags[] = {
8748 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8749 { AV_CODEC_ID_NONE, 0 },
8750 };
8751 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8752
8753 static const AVClass mov_avif_muxer_class = {
8754 .class_name = "avif muxer",
8755 .item_name = av_default_item_name,
8756 .option = avif_options,
8757 .version = LIBAVUTIL_VERSION_INT,
8758 };
8759 #endif
8760
8761 #if CONFIG_MOV_MUXER
8762 const FFOutputFormat ff_mov_muxer = {
8763 .p.name = "mov",
8764 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8765 .p.extensions = "mov",
8766 .priv_data_size = sizeof(MOVMuxContext),
8767 .p.audio_codec = AV_CODEC_ID_AAC,
8768 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8769 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8770 .init = mov_init,
8771 .write_header = mov_write_header,
8772 .write_packet = mov_write_packet,
8773 .write_trailer = mov_write_trailer,
8774 .deinit = mov_free,
8775 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8776 .p.codec_tag = (const AVCodecTag* const []){
8777 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8778 },
8779 .check_bitstream = mov_check_bitstream,
8780 .p.priv_class = &mov_isobmff_muxer_class,
8781 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8782 };
8783 #endif
8784 #if CONFIG_TGP_MUXER
8785 const FFOutputFormat ff_tgp_muxer = {
8786 .p.name = "3gp",
8787 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8788 .p.extensions = "3gp",
8789 .priv_data_size = sizeof(MOVMuxContext),
8790 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8791 .p.video_codec = AV_CODEC_ID_H263,
8792 .init = mov_init,
8793 .write_header = mov_write_header,
8794 .write_packet = mov_write_packet,
8795 .write_trailer = mov_write_trailer,
8796 .deinit = mov_free,
8797 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8798 .p.codec_tag = codec_3gp_tags_list,
8799 .check_bitstream = mov_check_bitstream,
8800 .p.priv_class = &mov_isobmff_muxer_class,
8801 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8802 };
8803 #endif
8804 #if CONFIG_MP4_MUXER
8805 const FFOutputFormat ff_mp4_muxer = {
8806 .p.name = "mp4",
8807 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8808 .p.mime_type = "video/mp4",
8809 .p.extensions = "mp4",
8810 .priv_data_size = sizeof(MOVMuxContext),
8811 .p.audio_codec = AV_CODEC_ID_AAC,
8812 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8813 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8814 .init = mov_init,
8815 .write_header = mov_write_header,
8816 .write_packet = mov_write_packet,
8817 .write_trailer = mov_write_trailer,
8818 .deinit = mov_free,
8819 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8820 .p.codec_tag = mp4_codec_tags_list,
8821 .check_bitstream = mov_check_bitstream,
8822 .p.priv_class = &mov_isobmff_muxer_class,
8823 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8824 };
8825 #endif
8826 #if CONFIG_PSP_MUXER
8827 const FFOutputFormat ff_psp_muxer = {
8828 .p.name = "psp",
8829 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8830 .p.extensions = "mp4,psp",
8831 .priv_data_size = sizeof(MOVMuxContext),
8832 .p.audio_codec = AV_CODEC_ID_AAC,
8833 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8834 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8835 .init = mov_init,
8836 .write_header = mov_write_header,
8837 .write_packet = mov_write_packet,
8838 .write_trailer = mov_write_trailer,
8839 .deinit = mov_free,
8840 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8841 .p.codec_tag = mp4_codec_tags_list,
8842 .check_bitstream = mov_check_bitstream,
8843 .p.priv_class = &mov_isobmff_muxer_class,
8844 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8845 };
8846 #endif
8847 #if CONFIG_TG2_MUXER
8848 const FFOutputFormat ff_tg2_muxer = {
8849 .p.name = "3g2",
8850 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8851 .p.extensions = "3g2",
8852 .priv_data_size = sizeof(MOVMuxContext),
8853 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8854 .p.video_codec = AV_CODEC_ID_H263,
8855 .init = mov_init,
8856 .write_header = mov_write_header,
8857 .write_packet = mov_write_packet,
8858 .write_trailer = mov_write_trailer,
8859 .deinit = mov_free,
8860 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8861 .p.codec_tag = codec_3gp_tags_list,
8862 .check_bitstream = mov_check_bitstream,
8863 .p.priv_class = &mov_isobmff_muxer_class,
8864 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8865 };
8866 #endif
8867 #if CONFIG_IPOD_MUXER
8868 const FFOutputFormat ff_ipod_muxer = {
8869 .p.name = "ipod",
8870 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8871 .p.mime_type = "video/mp4",
8872 .p.extensions = "m4v,m4a,m4b",
8873 .priv_data_size = sizeof(MOVMuxContext),
8874 .p.audio_codec = AV_CODEC_ID_AAC,
8875 .p.video_codec = AV_CODEC_ID_H264,
8876 .init = mov_init,
8877 .write_header = mov_write_header,
8878 .write_packet = mov_write_packet,
8879 .write_trailer = mov_write_trailer,
8880 .deinit = mov_free,
8881 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8882 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
8883 .check_bitstream = mov_check_bitstream,
8884 .p.priv_class = &mov_isobmff_muxer_class,
8885 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8886 };
8887 #endif
8888 #if CONFIG_ISMV_MUXER
8889 const FFOutputFormat ff_ismv_muxer = {
8890 .p.name = "ismv",
8891 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
8892 .p.mime_type = "video/mp4",
8893 .p.extensions = "ismv,isma",
8894 .priv_data_size = sizeof(MOVMuxContext),
8895 .p.audio_codec = AV_CODEC_ID_AAC,
8896 .p.video_codec = AV_CODEC_ID_H264,
8897 .init = mov_init,
8898 .write_header = mov_write_header,
8899 .write_packet = mov_write_packet,
8900 .write_trailer = mov_write_trailer,
8901 .deinit = mov_free,
8902 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8903 .p.codec_tag = (const AVCodecTag* const []){
8904 codec_mp4_tags, codec_ism_tags, 0 },
8905 .check_bitstream = mov_check_bitstream,
8906 .p.priv_class = &mov_isobmff_muxer_class,
8907 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8908 };
8909 #endif
8910 #if CONFIG_F4V_MUXER
8911 const FFOutputFormat ff_f4v_muxer = {
8912 .p.name = "f4v",
8913 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
8914 .p.mime_type = "application/f4v",
8915 .p.extensions = "f4v",
8916 .priv_data_size = sizeof(MOVMuxContext),
8917 .p.audio_codec = AV_CODEC_ID_AAC,
8918 .p.video_codec = AV_CODEC_ID_H264,
8919 .init = mov_init,
8920 .write_header = mov_write_header,
8921 .write_packet = mov_write_packet,
8922 .write_trailer = mov_write_trailer,
8923 .deinit = mov_free,
8924 .p.flags = AVFMT_GLOBALHEADER,
8925 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
8926 .check_bitstream = mov_check_bitstream,
8927 .p.priv_class = &mov_isobmff_muxer_class,
8928 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8929 };
8930 #endif
8931 #if CONFIG_AVIF_MUXER
8932 const FFOutputFormat ff_avif_muxer = {
8933 .p.name = "avif",
8934 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
8935 .p.mime_type = "image/avif",
8936 .p.extensions = "avif",
8937 .priv_data_size = sizeof(MOVMuxContext),
8938 .p.video_codec = AV_CODEC_ID_AV1,
8939 .init = mov_init,
8940 .write_header = mov_write_header,
8941 .write_packet = mov_write_packet,
8942 .write_trailer = avif_write_trailer,
8943 .deinit = mov_free,
8944 .p.flags = AVFMT_GLOBALHEADER,
8945 .p.codec_tag = codec_avif_tags_list,
8946 .p.priv_class = &mov_avif_muxer_class,
8947 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8948 };
8949 #endif
8950