FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2026-09-28 17:50:41
Exec Total Coverage
Lines: 4004 5874 68.2%
Functions: 190 243 78.2%
Branches: 2393 4055 59.0%

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 <math.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29
30 #include "movenc.h"
31 #include "avformat.h"
32 #include "avio_internal.h"
33 #include "dovi_isom.h"
34 #include "riff.h"
35 #include "avio.h"
36 #include "iamf_writer.h"
37 #include "isom.h"
38 #include "av1.h"
39 #include "avc.h"
40 #include "evc.h"
41 #include "apv.h"
42 #include "lcevc.h"
43 #include "libavcodec/ac3_parser_internal.h"
44 #include "libavcodec/dnxhddata.h"
45 #include "libavcodec/flac.h"
46 #include "libavcodec/mpegaudiodata.h"
47 #include "libavcodec/get_bits.h"
48
49 #include "libavcodec/internal.h"
50 #include "libavcodec/put_bits.h"
51 #include "libavcodec/vc1_common.h"
52 #include "libavcodec/raw.h"
53 #include "internal.h"
54 #include "libavutil/avstring.h"
55 #include "libavutil/channel_layout.h"
56 #include "libavutil/csp.h"
57 #include "libavutil/intfloat.h"
58 #include "libavutil/mathematics.h"
59 #include "libavutil/mem.h"
60 #include "libavutil/opt.h"
61 #include "libavutil/dict.h"
62 #include "libavutil/pixdesc.h"
63 #include "libavutil/stereo3d.h"
64 #include "libavutil/timecode.h"
65 #include "libavutil/dovi_meta.h"
66 #include "libavutil/uuid.h"
67 #include "hevc.h"
68 #include "rtpenc.h"
69 #include "nal.h"
70 #include "mov_chan.h"
71 #include "movenc_ttml.h"
72 #include "mux.h"
73 #include "rawutils.h"
74 #include "ttmlenc.h"
75 #include "version.h"
76 #include "vpcc.h"
77 #include "vvc.h"
78
79 static const AVOption options[] = {
80 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "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},
82 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
84 { "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 },
85 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "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 },
87 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
88 { "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},
89 { "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},
90 { "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},
91 { "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},
92 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "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" },
94 { "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" },
95 { "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" },
96 { "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" },
97 { "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" },
98 { "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" },
99 { "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" },
100 { "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" },
101 { "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" },
102 { "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" },
103 { "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" },
104 { "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" },
105 { "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" },
106 { "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 },
107 { "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" },
108 { "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" },
109 { "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" },
110 { "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" },
111 { "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" },
112 { "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" },
113 { "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" },
114 { "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" },
115 { "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" },
116 { "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" },
117 { "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" },
118 { "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},
119 { "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},
120 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
121 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
122 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "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},
125 { "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},
126 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
127 { "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"},
128 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
129 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
130 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
131 { NULL },
132 };
133
134 static const AVClass mov_isobmff_muxer_class = {
135 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
136 .item_name = av_default_item_name,
137 .option = options,
138 .version = LIBAVUTIL_VERSION_INT,
139 };
140
141 static int get_moov_size(AVFormatContext *s);
142 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
143
144 31 static int utf8len(const uint8_t *b)
145 {
146 31 int len = 0;
147 int val;
148
2/2
✓ Branch 0 taken 581 times.
✓ Branch 1 taken 31 times.
612 while (*b) {
149
3/8
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 581 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 581 times.
581 GET_UTF8(val, *b++, return -1;)
150 581 len++;
151 }
152 31 return len;
153 }
154
155 //FIXME support 64 bit variant with wide placeholders
156 7289 static int64_t update_size(AVIOContext *pb, int64_t pos)
157 {
158 7289 int64_t curpos = avio_tell(pb);
159 7289 avio_seek(pb, pos, SEEK_SET);
160 7289 avio_wb32(pb, curpos - pos); /* rewrite size */
161 7289 avio_seek(pb, curpos, SEEK_SET);
162
163 7289 return curpos - pos;
164 }
165
166 383 static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version)
167 {
168 383 int64_t curpos = avio_tell(pb);
169 383 avio_seek(pb, pos, SEEK_SET);
170 383 avio_wb32(pb, curpos - pos); /* rewrite size */
171 383 avio_skip(pb, 4);
172 383 avio_w8(pb, version); /* rewrite version */
173 383 avio_seek(pb, curpos, SEEK_SET);
174
175 383 return curpos - pos;
176 }
177
178 383 static int co64_required(const MOVTrack *track)
179 {
180
3/4
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 276 times.
383 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
181 ✗ return 1;
182 383 return 0;
183 }
184
185 24517 static int is_cover_image(const AVStream *st)
186 {
187 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
188 * is encoded as sparse video track */
189
3/4
✓ Branch 0 taken 24517 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24505 times.
24517 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
190 }
191
192 6 static int rtp_hinting_needed(const AVStream *st)
193 {
194 /* Add hint tracks for each real audio and video stream */
195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
196 ✗ return 0;
197
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
198
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
199 }
200
201 /* Chunk offset atom */
202 383 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
203 {
204 int i;
205 383 int mode64 = co64_required(track); // use 32 bit size variant if possible
206 383 int64_t pos = avio_tell(pb);
207 383 avio_wb32(pb, 0); /* size */
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
383 if (mode64)
209 ✗ ffio_wfourcc(pb, "co64");
210 else
211 383 ffio_wfourcc(pb, "stco");
212 383 avio_wb32(pb, 0); /* version & flags */
213 383 avio_wb32(pb, track->chunkCount); /* entry count */
214
2/2
✓ Branch 0 taken 17325 times.
✓ Branch 1 taken 383 times.
17708 for (i = 0; i < track->entry; i++) {
215
2/2
✓ Branch 0 taken 14354 times.
✓ Branch 1 taken 2971 times.
17325 if (!track->cluster[i].chunkNum)
216 14354 continue;
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2971 times.
2971 if (mode64 == 1)
218 ✗ avio_wb64(pb, track->cluster[i].pos + track->data_offset);
219 else
220 2971 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
221 }
222 383 return update_size(pb, pos);
223 }
224
225 /* Sample size atom */
226 383 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
227 {
228 383 int equalChunks = 1;
229 383 int i, j, entries = 0, tst = -1, oldtst = -1;
230
231 383 int64_t pos = avio_tell(pb);
232 383 avio_wb32(pb, 0); /* size */
233 383 ffio_wfourcc(pb, "stsz");
234 383 avio_wb32(pb, 0); /* version & flags */
235
236
2/2
✓ Branch 0 taken 17325 times.
✓ Branch 1 taken 383 times.
17708 for (i = 0; i < track->entry; i++) {
237 17325 tst = track->cluster[i].size / track->cluster[i].entries;
238
4/4
✓ Branch 0 taken 17049 times.
✓ Branch 1 taken 276 times.
✓ Branch 2 taken 11937 times.
✓ Branch 3 taken 5112 times.
17325 if (oldtst != -1 && tst != oldtst)
239 11937 equalChunks = 0;
240 17325 oldtst = tst;
241 17325 entries += track->cluster[i].entries;
242 }
243
4/4
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 107 times.
503 if (equalChunks && track->entry) {
244
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
245 120 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
246 120 avio_wb32(pb, sSize); // sample size
247 120 avio_wb32(pb, entries); // sample count
248 } else {
249 263 avio_wb32(pb, 0); // sample size
250 263 avio_wb32(pb, entries); // sample count
251
2/2
✓ Branch 0 taken 13260 times.
✓ Branch 1 taken 263 times.
13523 for (i = 0; i < track->entry; i++) {
252
2/2
✓ Branch 0 taken 13260 times.
✓ Branch 1 taken 13260 times.
26520 for (j = 0; j < track->cluster[i].entries; j++) {
253 13260 avio_wb32(pb, track->cluster[i].size /
254 13260 track->cluster[i].entries);
255 }
256 }
257 }
258 383 return update_size(pb, pos);
259 }
260
261 /* Sample to chunk atom */
262 383 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
263 {
264 383 int index = 0, oldidx = -1, oldval = -1, i;
265 int64_t entryPos, curpos;
266
267 383 int64_t pos = avio_tell(pb);
268 383 avio_wb32(pb, 0); /* size */
269 383 ffio_wfourcc(pb, "stsc");
270 383 avio_wb32(pb, 0); // version & flags
271 383 entryPos = avio_tell(pb);
272 383 avio_wb32(pb, track->chunkCount); // entry count
273
2/2
✓ Branch 0 taken 17325 times.
✓ Branch 1 taken 383 times.
17708 for (i = 0; i < track->entry; i++) {
274
2/2
✓ Branch 0 taken 2133 times.
✓ Branch 1 taken 15192 times.
17325 if ((oldval != track->cluster[i].samples_in_chunk ||
275
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2131 times.
✓ Branch 2 taken 840 times.
✓ Branch 3 taken 14354 times.
17325 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
276 840 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
277 840 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
278 840 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
279 840 oldval = track->cluster[i].samples_in_chunk;
280 840 oldidx = track->cluster[i].stsd_index;
281 840 index++;
282 }
283 }
284 383 curpos = avio_tell(pb);
285 383 avio_seek(pb, entryPos, SEEK_SET);
286 383 avio_wb32(pb, index); // rewrite size
287 383 avio_seek(pb, curpos, SEEK_SET);
288
289 383 return update_size(pb, pos);
290 }
291
292 /* Sync sample atom */
293 69 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
294 {
295 int64_t curpos, entryPos;
296 69 int i, index = 0;
297 69 int64_t pos = avio_tell(pb);
298 69 avio_wb32(pb, 0); // size
299
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
300 69 avio_wb32(pb, 0); // version & flags
301 69 entryPos = avio_tell(pb);
302 69 avio_wb32(pb, track->entry); // entry count
303
2/2
✓ Branch 0 taken 3482 times.
✓ Branch 1 taken 69 times.
3551 for (i = 0; i < track->entry; i++) {
304
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 3256 times.
3482 if (track->cluster[i].flags & flag) {
305 226 avio_wb32(pb, i + 1);
306 226 index++;
307 }
308 }
309 69 curpos = avio_tell(pb);
310 69 avio_seek(pb, entryPos, SEEK_SET);
311 69 avio_wb32(pb, index); // rewrite size
312 69 avio_seek(pb, curpos, SEEK_SET);
313 69 return update_size(pb, pos);
314 }
315
316 /* Sample dependency atom */
317 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
318 {
319 int i;
320 uint8_t leading, dependent, reference, redundancy;
321 3 int64_t pos = avio_tell(pb);
322 3 avio_wb32(pb, 0); // size
323 3 ffio_wfourcc(pb, "sdtp");
324 3 avio_wb32(pb, 0); // version & flags
325
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
326 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
327 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
328
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
329 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
330 }
331
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
332 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
333 }
334 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
335 13 (reference << 2) | redundancy);
336 }
337 3 return update_size(pb, pos);
338 }
339
340 #if CONFIG_IAMFENC
341 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
342 {
343 AVIOContext *dyn_bc;
344 5 int64_t pos = avio_tell(pb);
345 5 uint8_t *dyn_buf = NULL;
346 int dyn_size;
347 5 int ret = avio_open_dyn_buf(&dyn_bc);
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
349 ✗ return ret;
350
351 5 avio_wb32(pb, 0);
352 5 ffio_wfourcc(pb, "iacb");
353 5 avio_w8(pb, 1); // configurationVersion
354
355 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0) {
357 ✗ ffio_free_dyn_buf(&dyn_bc);
358 ✗ return ret;
359 }
360
361 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
362 5 ffio_write_leb(pb, dyn_size);
363 5 avio_write(pb, dyn_buf, dyn_size);
364 5 av_free(dyn_buf);
365
366 5 return update_size(pb, pos);
367 }
368 #endif
369
370 ✗ static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
371 {
372 ✗ avio_wb32(pb, 0x11); /* size */
373 ✗ if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
374 ✗ else ffio_wfourcc(pb, "damr");
375 ✗ ffio_wfourcc(pb, "FFMP");
376 ✗ avio_w8(pb, 0); /* decoder version */
377
378 ✗ avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
379 ✗ avio_w8(pb, 0x00); /* Mode change period (no restriction) */
380 ✗ avio_w8(pb, 0x01); /* Frames per sample */
381 ✗ return 0x11;
382 }
383
384 struct eac3_info {
385 AVPacket *pkt;
386 uint8_t eof;
387 uint8_t ec3_done;
388 uint8_t num_blocks;
389
390 /* Layout of the EC3SpecificBox */
391 /* maximum bitrate */
392 uint16_t data_rate;
393 int8_t ac3_bit_rate_code;
394 /* number of independent substreams */
395 uint8_t num_ind_sub;
396 struct {
397 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
398 uint8_t fscod;
399 /* bit stream identification 5 bits */
400 uint8_t bsid;
401 /* one bit reserved */
402 /* audio service mixing (not supported yet) 1 bit */
403 /* bit stream mode 3 bits */
404 uint8_t bsmod;
405 /* audio coding mode 3 bits */
406 uint8_t acmod;
407 /* sub woofer on 1 bit */
408 uint8_t lfeon;
409 /* 3 bits reserved */
410 /* number of dependent substreams associated with this substream 4 bits */
411 uint8_t num_dep_sub;
412 /* channel locations of the dependent substream(s), if any, 9 bits */
413 uint16_t chan_loc;
414 /* if there is no dependent substream, then one bit reserved instead */
415 } substream[1]; /* TODO: support 8 independent substreams */
416 /* indicates the decoding complexity, 8 bits */
417 uint8_t complexity_index_type_a;
418 };
419
420 7 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
421 {
422 7 struct eac3_info *info = track->eac3_priv;
423 PutBitContext pbc;
424 uint8_t buf[3];
425
426
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!info || !info->ec3_done) {
427 ✗ av_log(s, AV_LOG_ERROR,
428 "Cannot write moov atom before AC3 packets."
429 " Set the delay_moov flag to fix this.\n");
430 ✗ return AVERROR(EINVAL);
431 }
432
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->substream[0].bsid > 8) {
434 ✗ av_log(s, AV_LOG_ERROR,
435 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
436 "ISOBMFF specification in ETSI TS 102 366!\n",
437 ✗ info->substream[0].bsid);
438 ✗ return AVERROR(EINVAL);
439 }
440
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->ac3_bit_rate_code < 0) {
442 ✗ av_log(s, AV_LOG_ERROR,
443 "No valid AC3 bit rate code for data rate of %d!\n",
444 ✗ info->data_rate);
445 ✗ return AVERROR(EINVAL);
446 }
447
448 7 avio_wb32(pb, 11);
449 7 ffio_wfourcc(pb, "dac3");
450
451 7 init_put_bits(&pbc, buf, sizeof(buf));
452 7 put_bits(&pbc, 2, info->substream[0].fscod);
453 7 put_bits(&pbc, 5, info->substream[0].bsid);
454 7 put_bits(&pbc, 3, info->substream[0].bsmod);
455 7 put_bits(&pbc, 3, info->substream[0].acmod);
456 7 put_bits(&pbc, 1, info->substream[0].lfeon);
457 7 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
458 7 put_bits(&pbc, 5, 0); // reserved
459
460 7 flush_put_bits(&pbc);
461 7 avio_write(pb, buf, sizeof(buf));
462
463 7 return 11;
464 }
465
466 1737 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
467 {
468 1737 AC3HeaderInfo *hdr = NULL;
469 struct eac3_info *info;
470 int num_blocks, ret;
471
472
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
1737 if (!track->eac3_priv) {
473
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
474 ✗ return AVERROR(ENOMEM);
475
476 10 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
477 }
478 1737 info = track->eac3_priv;
479
480
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
1737 if (!info->pkt && !(info->pkt = av_packet_alloc()))
481 ✗ return AVERROR(ENOMEM);
482
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (info->eof) {
484 av_assert1(!info->pkt->size);
485 ✗ ret = pkt->size;
486 ✗ goto end;
487 }
488
489
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1736 times.
1737 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
491 ✗ goto end;
492
493 /* drop the packets until we see a good one */
494
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
495 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
496 1 ret = 0;
497 } else
498 ✗ ret = AVERROR_INVALIDDATA;
499 1 goto end;
500 }
501
502 1736 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
503 1736 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
504 hdr->ac3_bit_rate_code);
505 1736 info->complexity_index_type_a = hdr->complexity_index_type_a;
506
507 1736 num_blocks = hdr->num_blocks;
508
509
2/2
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 14 times.
1736 if (!info->ec3_done) {
510 /* AC-3 substream must be the first one */
511
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
14 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
512 ✗ ret = AVERROR(EINVAL);
513 ✗ goto end;
514 }
515
516 /* this should always be the case, given that our AC-3 parser
517 * concatenates dependent frames to their independent parent */
518
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
519
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
520 /* substream ids must be incremental */
521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid > info->num_ind_sub + 1) {
522 ✗ ret = AVERROR(EINVAL);
523 ✗ goto end;
524 }
525
526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid == info->num_ind_sub + 1) {
527 //info->num_ind_sub++;
528 ✗ avpriv_request_sample(mov->fc, "Multiple independent substreams");
529 ✗ ret = AVERROR_PATCHWELCOME;
530 ✗ goto end;
531
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 } else if (hdr->substreamid < info->num_ind_sub ||
532
3/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 10 times.
14 hdr->substreamid == 0 && info->substream[0].bsid) {
533 4 info->ec3_done = 1;
534 4 goto concatenate;
535 }
536 } else {
537 ✗ if (hdr->substreamid != 0) {
538 ✗ avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
539 ✗ ret = AVERROR_PATCHWELCOME;
540 ✗ goto end;
541 }
542 }
543
544 /* fill the info needed for the "dec3" atom */
545 10 info->substream[hdr->substreamid].fscod = hdr->sr_code;
546 10 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
547 10 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
548 10 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
549 10 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
550
551
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (track->par->codec_id == AV_CODEC_ID_AC3) {
552 // with AC-3 we only require the information of a single packet,
553 // so we can finish as soon as the basic values of the bit stream
554 // have been set to the track's informational structure.
555 6 info->ec3_done = 1;
556 6 goto concatenate;
557 }
558
559 /* Parse dependent substream(s), if any */
560
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (pkt->size != hdr->frame_size) {
561 1 int cumul_size = hdr->frame_size;
562 1 int parent = hdr->substreamid;
563
564
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (cumul_size != pkt->size) {
565 1 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
567 ✗ goto end;
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
569 ✗ ret = AVERROR(EINVAL);
570 ✗ goto end;
571 }
572 1 info->substream[parent].num_dep_sub++;
573 1 ret /= 8;
574
575 /* get the dependent stream channel map, if exists */
576
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (hdr->channel_map_present) {
577 /* chanmap is a 16-bit field read MSB-first, so flag index
578 * i sits at bit (15 - i), matching the indexing of
579 * ff_eac3_custom_channel_map_locations. chan_loc bits 0-7
580 * carry flag indices 5-12, i.e. chanmap bit (10 - j).
581 * The mapping is not contiguous at the top: index 13
582 * (Lts/Rts) has no chan_loc bit and is skipped, and
583 * chan_loc bit 8 carries LFE2, which is index 14 and so
584 * chanmap bit 1. */
585
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for (int j = 0; j < 8; j++) {
586
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if ((hdr->channel_map >> (10 - j)) & 1)
587 1 info->substream[parent].chan_loc |= 1 << j;
588 }
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((hdr->channel_map >> 1) & 1)
590 ✗ info->substream[parent].chan_loc |= 1 << 8;
591 } else {
592 ✗ info->substream[parent].chan_loc |= hdr->channel_mode;
593 }
594 1 cumul_size += hdr->frame_size;
595 }
596 }
597 }
598
599 1726 concatenate:
600
2/4
✓ Branch 0 taken 1736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1736 times.
✗ Branch 3 not taken.
1736 if (!info->num_blocks && num_blocks == 6) {
601 1736 ret = pkt->size;
602 1736 goto end;
603 }
604 ✗ else if (info->num_blocks + num_blocks > 6) {
605 ✗ ret = AVERROR_INVALIDDATA;
606 ✗ goto end;
607 }
608
609 ✗ if (!info->num_blocks) {
610 ✗ ret = av_packet_ref(info->pkt, pkt);
611 ✗ if (!ret)
612 ✗ info->num_blocks = num_blocks;
613 ✗ goto end;
614 } else {
615 const AVPacketSideData *sd;
616 ✗ int64_t duration = pkt->duration;
617 ✗ if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
618 ✗ goto end;
619 ✗ sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
620 ✗ if (sd && sd->size >= 10) {
621 ✗ uint8_t *buf = av_packet_new_side_data(info->pkt, AV_PKT_DATA_SKIP_SAMPLES, sd->size);
622 ✗ if (buf)
623 ✗ memcpy(buf, sd->data, sd->size);
624 ✗ if (track->par->frame_size)
625 ✗ duration = FFMAX(av_rescale_q(track->par->frame_size, (AVRational){ 1, track->par->sample_rate },
626 track->st->time_base), duration);
627 }
628 ✗ memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
629 ✗ info->num_blocks += num_blocks;
630 ✗ info->pkt->duration += duration;
631 ✗ if (info->num_blocks != 6)
632 ✗ goto end;
633 ✗ av_packet_unref(pkt);
634 ✗ av_packet_move_ref(pkt, info->pkt);
635 ✗ info->num_blocks = 0;
636 }
637 ✗ ret = pkt->size;
638
639 1737 end:
640 1737 av_free(hdr);
641
642 1737 return ret;
643 }
644
645 4 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
646 {
647 PutBitContext pbc;
648 uint8_t *buf;
649 struct eac3_info *info;
650 int size, i;
651
652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->eac3_priv) {
653 ✗ av_log(s, AV_LOG_ERROR,
654 "Cannot write moov atom before EAC3 packets parsed.\n");
655 ✗ return AVERROR(EINVAL);
656 }
657
658 4 info = track->eac3_priv;
659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
660 4 buf = av_malloc(size);
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!buf) {
662 ✗ return AVERROR(ENOMEM);
663 }
664
665 4 init_put_bits(&pbc, buf, size);
666 4 put_bits(&pbc, 13, info->data_rate);
667 4 put_bits(&pbc, 3, info->num_ind_sub);
668
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i <= info->num_ind_sub; i++) {
669 4 put_bits(&pbc, 2, info->substream[i].fscod);
670 4 put_bits(&pbc, 5, info->substream[i].bsid);
671 4 put_bits(&pbc, 1, 0); /* reserved */
672 4 put_bits(&pbc, 1, 0); /* asvc */
673 4 put_bits(&pbc, 3, info->substream[i].bsmod);
674 4 put_bits(&pbc, 3, info->substream[i].acmod);
675 4 put_bits(&pbc, 1, info->substream[i].lfeon);
676 4 put_bits(&pbc, 3, 0); /* reserved */
677 4 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
678
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (!info->substream[i].num_dep_sub) {
679 3 put_bits(&pbc, 1, 0); /* reserved */
680 } else {
681 1 put_bits(&pbc, 9, info->substream[i].chan_loc);
682 }
683 }
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (info->complexity_index_type_a) {
685 ✗ put_bits(&pbc, 7, 0); /* reserved */
686 ✗ put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
687 ✗ put_bits(&pbc, 8, info->complexity_index_type_a);
688 }
689 4 flush_put_bits(&pbc);
690 4 size = put_bytes_output(&pbc);
691
692 4 avio_wb32(pb, size + 8);
693 4 ffio_wfourcc(pb, "dec3");
694 4 avio_write(pb, buf, size);
695
696 4 av_free(buf);
697
698 4 return size;
699 }
700
701 /**
702 * This function writes extradata "as is".
703 * Extradata must be formatted like a valid atom (with size and tag).
704 */
705 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
706 {
707 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
708 12 return track->extradata_size[track->last_stsd_index];
709 }
710
711 ✗ static int mov_write_enda_tag(AVIOContext *pb)
712 {
713 ✗ avio_wb32(pb, 10);
714 ✗ ffio_wfourcc(pb, "enda");
715 ✗ avio_wb16(pb, 1); /* little endian */
716 ✗ return 10;
717 }
718
719 2 static int mov_write_enda_tag_be(AVIOContext *pb)
720 {
721 2 avio_wb32(pb, 10);
722 2 ffio_wfourcc(pb, "enda");
723 2 avio_wb16(pb, 0); /* big endian */
724 2 return 10;
725 }
726
727 405 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
728 {
729 405 int i = 3;
730 405 avio_w8(pb, tag);
731
2/2
✓ Branch 0 taken 1215 times.
✓ Branch 1 taken 405 times.
1620 for (; i > 0; i--)
732 1215 avio_w8(pb, (size >> (7 * i)) | 0x80);
733 405 avio_w8(pb, size & 0x7F);
734 405 }
735
736 279 static unsigned compute_avg_bitrate(MOVTrack *track)
737 {
738 279 uint64_t size = 0;
739 int i;
740
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 227 times.
279 if (!track->track_duration)
741 52 return 0;
742
2/2
✓ Branch 0 taken 15261 times.
✓ Branch 1 taken 227 times.
15488 for (i = 0; i < track->entry; i++)
743 15261 size += track->cluster[i].size;
744 227 return size * 8 * track->timescale / track->track_duration;
745 }
746
747 struct mpeg4_bit_rate_values {
748 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
749 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
750 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
751 };
752
753 279 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
754 {
755 558 const AVPacketSideData *sd = track->st ?
756 278 av_packet_side_data_get(track->st->codecpar->coded_side_data,
757 278 track->st->codecpar->nb_coded_side_data,
758
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 1 times.
279 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
759
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 229 times.
279 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
760 279 struct mpeg4_bit_rate_values bit_rates = { 0 };
761
762 279 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
763
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 125 times.
279 if (!bit_rates.avg_bit_rate) {
764 // if the average bit rate cannot be calculated at this point, such as
765 // in the case of fragmented MP4, utilize the following values as
766 // fall-back in priority order:
767 //
768 // 1. average bit rate property
769 // 2. bit rate (usually average over the whole clip)
770 // 3. maximum bit rate property
771
772
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
154 if (props && props->avg_bitrate) {
773 16 bit_rates.avg_bit_rate = props->avg_bitrate;
774
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 129 times.
138 } else if (track->par->bit_rate) {
775 9 bit_rates.avg_bit_rate = track->par->bit_rate;
776
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
129 } else if (props && props->max_bitrate) {
777 ✗ bit_rates.avg_bit_rate = props->max_bitrate;
778 }
779 }
780
781 // (FIXME should be max rate in any 1 sec window)
782 279 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
783 bit_rates.avg_bit_rate);
784
785 // utilize values from properties if we have them available
786
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 229 times.
279 if (props) {
787 // no avg_bitrate signals that the track is VBR
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!props->avg_bitrate)
789 ✗ bit_rates.avg_bit_rate = props->avg_bitrate;
790 50 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
791 props->max_bitrate);
792 50 bit_rates.buffer_size = props->buffer_size / 8;
793 }
794
795 279 return bit_rates;
796 }
797
798 103 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
799 {
800 103 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
801 103 int64_t pos = avio_tell(pb);
802 206 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
803
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7 times.
103 5 + track->extradata_size[track->last_stsd_index] : 0;
804
805 103 avio_wb32(pb, 0); // size
806 103 ffio_wfourcc(pb, "esds");
807 103 avio_wb32(pb, 0); // Version
808
809 // ES descriptor
810 103 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
811 103 avio_wb16(pb, track->track_id);
812 103 avio_w8(pb, 0x00); // flags (= no flags)
813
814 // DecoderConfig descriptor
815 103 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
816
817 // Object type indication
818
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
103 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
819
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 102 times.
103 track->par->codec_id == AV_CODEC_ID_MP3) &&
820
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 track->par->sample_rate > 24000)
821 1 avio_w8(pb, 0x6B); // 11172-3
822 else
823 102 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
824
825 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
826 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
828 ✗ avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
829
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 36 times.
103 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
830 67 avio_w8(pb, 0x15); // flags (= Audiostream)
831 else
832 36 avio_w8(pb, 0x11); // flags (= Visualstream)
833
834 103 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
835 103 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
836 103 avio_wb32(pb, bit_rates.avg_bit_rate);
837
838
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7 times.
103 if (track->extradata_size[track->last_stsd_index]) {
839 // DecoderSpecific info descriptor
840 96 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
841 96 avio_write(pb, track->extradata[track->last_stsd_index],
842 96 track->extradata_size[track->last_stsd_index]);
843 }
844
845 // SL descriptor
846 103 put_descr(pb, 0x06, 1);
847 103 avio_w8(pb, 0x02);
848 103 return update_size(pb, pos);
849 }
850
851 75 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
852 {
853
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 return codec_id == AV_CODEC_ID_PCM_S24LE ||
854
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 codec_id == AV_CODEC_ID_PCM_S32LE ||
855
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
150 codec_id == AV_CODEC_ID_PCM_F32LE ||
856 codec_id == AV_CODEC_ID_PCM_F64LE;
857 }
858
859 75 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
860 {
861
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
71 return codec_id == AV_CODEC_ID_PCM_S24BE ||
862
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 codec_id == AV_CODEC_ID_PCM_S32BE ||
863
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
146 codec_id == AV_CODEC_ID_PCM_F32BE ||
864 codec_id == AV_CODEC_ID_PCM_F64BE;
865 }
866
867 ✗ static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
868 {
869 int ret;
870 ✗ int64_t pos = avio_tell(pb);
871 ✗ avio_wb32(pb, 0);
872 ✗ avio_wl32(pb, track->tag); // store it byteswapped
873 ✗ track->par->codec_tag = av_bswap16(track->tag >> 16);
874 ✗ if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
875 ✗ return ret;
876 ✗ return update_size(pb, pos);
877 }
878
879 ✗ static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
880 {
881 int ret;
882 ✗ int64_t pos = avio_tell(pb);
883 ✗ avio_wb32(pb, 0);
884 ✗ ffio_wfourcc(pb, "wfex");
885 ✗ if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
886 ✗ return ret;
887 ✗ return update_size(pb, pos);
888 }
889
890 ✗ static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
891 {
892 ✗ int64_t pos = avio_tell(pb);
893 ✗ avio_wb32(pb, 0);
894 ✗ ffio_wfourcc(pb, "dfLa");
895 ✗ avio_w8(pb, 0); /* version */
896 ✗ avio_wb24(pb, 0); /* flags */
897
898 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
899 ✗ if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
900 ✗ return AVERROR_INVALIDDATA;
901
902 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
903 ✗ avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
904 ✗ avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
905 ✗ avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
906
907 ✗ return update_size(pb, pos);
908 }
909
910 ✗ static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
911 {
912 ✗ int64_t pos = avio_tell(pb);
913 int channels, channel_map;
914 ✗ avio_wb32(pb, 0);
915 ✗ ffio_wfourcc(pb, "dOps");
916 ✗ avio_w8(pb, 0); /* Version */
917 ✗ if (track->extradata_size[track->last_stsd_index] < 19) {
918 ✗ av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
919 ✗ return AVERROR_INVALIDDATA;
920 }
921 /* extradata contains an Ogg OpusHead, other than byte-ordering and
922 OpusHead's preceding magic/version, OpusSpecificBox is currently
923 identical. */
924 ✗ channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
925 ✗ channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
926
927 ✗ avio_w8(pb, channels); /* OuputChannelCount */
928 ✗ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
929 ✗ avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
930 ✗ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
931 ✗ avio_w8(pb, channel_map); /* ChannelMappingFamily */
932 /* Write the rest of the header out without byte-swapping. */
933 ✗ if (channel_map) {
934 ✗ if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
935 ✗ av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
936 ✗ return AVERROR_INVALIDDATA;
937 }
938 ✗ avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
939 }
940
941 ✗ return update_size(pb, pos);
942 }
943
944 ✗ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
945 {
946 ✗ int64_t pos = avio_tell(pb);
947 int length;
948 ✗ avio_wb32(pb, 0);
949 ✗ ffio_wfourcc(pb, "dmlp");
950
951 ✗ if (track->extradata_size[track->last_stsd_index] < 20) {
952 ✗ av_log(s, AV_LOG_ERROR,
953 "Cannot write moov atom before TrueHD packets."
954 " Set the delay_moov flag to fix this.\n");
955 ✗ return AVERROR(EINVAL);
956 }
957
958 ✗ length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
959 ✗ if (length < 20 || length > track->extradata_size[track->last_stsd_index])
960 ✗ return AVERROR_INVALIDDATA;
961
962 // Only TrueHD is supported
963 ✗ if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
964 ✗ return AVERROR_INVALIDDATA;
965
966 ✗ avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
967 ✗ avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
968 ✗ avio_wb32(pb, 0); /* reserved */
969
970 ✗ return update_size(pb, pos);
971 }
972
973 1 static int mov_write_mhac_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
974 {
975 1 int64_t pos = avio_tell(pb);
976 1 int layout = 0;
977
978
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata_size[track->last_stsd_index] > UINT16_MAX) {
979 ✗ av_log(s, AV_LOG_ERROR,
980 "Invalid extradata size %d for MPEGH-H stream.\n",
981 ✗ track->extradata_size[track->last_stsd_index]);
982 ✗ return AVERROR(EINVAL);
983 }
984
985 1 avio_wb32(pb, 0);
986 1 ffio_wfourcc(pb, "mhaC");
987
988 1 avio_w8(pb, 1); // ConfigurationVersion
989 1 avio_w8(pb, track->par->profile * 5 + track->par->level);
990
991
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 for (size_t i = 0; i < FF_ARRAY_ELEMS(ff_mpa_cicp_channel_layout_masks); i++) {
992
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
17 if (ff_mpa_cicp_channel_layout_masks[i]) {
993 AVChannelLayout ch_layout;
994 15 av_channel_layout_from_mask(&ch_layout, ff_mpa_cicp_channel_layout_masks[i]);
995
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 14 times.
15 if (!av_channel_layout_compare(&track->par->ch_layout, &ch_layout)) {
996 1 layout = i;
997 1 break;
998 }
999 }
1000 }
1001
1002 1 avio_w8(pb, layout);
1003 1 avio_wb16(pb, track->extradata_size[track->last_stsd_index]);
1004 1 avio_write(pb, track->extradata[track->last_stsd_index],
1005 1 track->extradata_size[track->last_stsd_index]);
1006
1007 1 return update_size(pb, pos);
1008 }
1009
1010 87 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1011 {
1012 87 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
1013 87 AVChannelLayout ch_layout = { 0 };
1014 int64_t pos;
1015 int ambisonic_order, ambi_channels, non_diegetic_channels;
1016 int i, ret;
1017
1018
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
87 if (!str)
1019 87 return 0;
1020
1021 ✗ ret = av_channel_layout_from_string(&ch_layout, str->value);
1022 ✗ if (ret < 0) {
1023 ✗ if (ret == AVERROR(EINVAL)) {
1024 ✗ invalid:
1025 ✗ av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
1026 ✗ ret = 0;
1027 }
1028 ✗ av_channel_layout_uninit(&ch_layout);
1029 ✗ return ret;
1030 }
1031
1032 ✗ if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
1033 ✗ goto invalid;
1034
1035 ✗ ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
1036 ✗ if (ambisonic_order < 0)
1037 ✗ goto invalid;
1038
1039 ✗ ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
1040 ✗ non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
1041 ✗ if (non_diegetic_channels &&
1042 ✗ (non_diegetic_channels != 2 ||
1043 ✗ av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
1044 ✗ goto invalid;
1045
1046 ✗ av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
1047
1048 ✗ pos = avio_tell(pb);
1049
1050 ✗ avio_wb32(pb, 0); // Size
1051 ✗ ffio_wfourcc(pb, "SA3D");
1052 ✗ avio_w8(pb, 0); // version
1053 ✗ avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
1054 ✗ avio_wb32(pb, ambisonic_order); // ambisonic_order
1055 ✗ avio_w8(pb, 0); // ambisonic_channel_ordering
1056 ✗ avio_w8(pb, 0); // ambisonic_normalization
1057 ✗ avio_wb32(pb, ch_layout.nb_channels); // num_channels
1058 ✗ for (i = 0; i < ambi_channels; i++)
1059 ✗ avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
1060 ✗ for (; i < ch_layout.nb_channels; i++)
1061 ✗ avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
1062
1063 ✗ av_channel_layout_uninit(&ch_layout);
1064
1065 ✗ return update_size(pb, pos);
1066 }
1067
1068 39 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1069 {
1070 uint32_t layout_tag, bitmap, *channel_desc;
1071 39 int64_t pos = avio_tell(pb);
1072 int num_desc, ret;
1073
1074
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (track->multichannel_as_mono)
1075 ✗ return 0;
1076
1077 39 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
1078 &bitmap, &channel_desc);
1079
1080
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0) {
1081 ✗ if (ret == AVERROR(ENOSYS)) {
1082 ✗ av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
1083 "lack of channel information\n");
1084 ✗ ret = 0;
1085 }
1086
1087 ✗ return ret;
1088 }
1089
1090 /* no predefined tag found + ch_layout in AV_CHANNEL_ORDER_NATIVE
1091 * but bitstream channels not actually in native order */
1092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (layout_tag == MOV_CH_LAYOUT_UNKNOWN)
1093 ✗ return 0;
1094
1095
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
39 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1097 1 channel_desc = av_malloc(sizeof(*channel_desc));
1098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1099 ✗ return AVERROR(ENOMEM);
1100
1101 1 layout_tag = 0;
1102 1 bitmap = 0;
1103 1 *channel_desc = 3; // channel label "Center"
1104 }
1105
1106
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 36 times.
39 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1107
1108 39 avio_wb32(pb, 0); // Size
1109 39 ffio_wfourcc(pb, "chan"); // Type
1110 39 avio_w8(pb, 0); // Version
1111 39 avio_wb24(pb, 0); // Flags
1112 39 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1113 39 avio_wb32(pb, bitmap); // mChannelBitmap
1114 39 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1115
1116
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39 times.
42 for (int i = 0; i < num_desc; i++) {
1117 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1118 3 avio_wb32(pb, 0); // mChannelFlags
1119 3 avio_wl32(pb, 0); // mCoordinates[0]
1120 3 avio_wl32(pb, 0); // mCoordinates[1]
1121 3 avio_wl32(pb, 0); // mCoordinates[2]
1122 }
1123
1124 39 av_free(channel_desc);
1125
1126 39 return update_size(pb, pos);
1127 }
1128
1129 14 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1130 {
1131 14 int64_t pos = avio_tell(pb);
1132
1133 14 avio_wb32(pb, 0); /* size */
1134 14 ffio_wfourcc(pb, "wave");
1135
1136
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1137 14 avio_wb32(pb, 12); /* size */
1138 14 ffio_wfourcc(pb, "frma");
1139 14 avio_wl32(pb, track->tag);
1140 }
1141
1142
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1143 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1144 3 avio_wb32(pb, 12); /* size */
1145 3 ffio_wfourcc(pb, "mp4a");
1146 3 avio_wb32(pb, 0);
1147 3 mov_write_esds_tag(pb, track);
1148
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1149 ✗ mov_write_enda_tag(pb);
1150
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
11 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1151 2 mov_write_enda_tag_be(pb);
1152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1153 ✗ mov_write_amr_tag(pb, track);
1154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1155 ✗ mov_write_ac3_tag(s, pb, track);
1156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1157 ✗ mov_write_eac3_tag(s, pb, track);
1158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1159 ✗ track->par->codec_id == AV_CODEC_ID_QDM2) {
1160 9 mov_write_extradata_tag(pb, track);
1161 ✗ } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1162 ✗ track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1163 ✗ mov_write_ms_tag(s, pb, track);
1164 }
1165
1166 14 avio_wb32(pb, 8); /* size */
1167 14 avio_wb32(pb, 0); /* null tag */
1168
1169 14 return update_size(pb, pos);
1170 }
1171
1172 ✗ static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1173 {
1174 uint8_t *unescaped;
1175 ✗ const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1176 ✗ track->extradata_size[track->last_stsd_index];
1177 ✗ int unescaped_size, seq_found = 0;
1178 ✗ int level = 0, interlace = 0;
1179 ✗ int packet_seq = track->vc1_info.packet_seq;
1180 ✗ int packet_entry = track->vc1_info.packet_entry;
1181 ✗ int slices = track->vc1_info.slices;
1182 PutBitContext pbc;
1183
1184 ✗ if (track->start_dts == AV_NOPTS_VALUE) {
1185 /* No packets written yet, vc1_info isn't authoritative yet. */
1186 /* Assume inline sequence and entry headers. */
1187 ✗ packet_seq = packet_entry = 1;
1188 ✗ av_log(NULL, AV_LOG_WARNING,
1189 "moov atom written before any packets, unable to write correct "
1190 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1191 }
1192
1193 ✗ unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1194 ✗ if (!unescaped)
1195 ✗ return AVERROR(ENOMEM);
1196 ✗ start = find_next_marker(track->extradata[track->last_stsd_index], end);
1197 ✗ for (next = start; next < end; start = next) {
1198 GetBitContext gb;
1199 int size;
1200 ✗ next = find_next_marker(start + 4, end);
1201 ✗ size = next - start - 4;
1202 ✗ if (size <= 0)
1203 ✗ continue;
1204 ✗ unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1205 ✗ init_get_bits(&gb, unescaped, 8 * unescaped_size);
1206 ✗ if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1207 ✗ int profile = get_bits(&gb, 2);
1208 ✗ if (profile != PROFILE_ADVANCED) {
1209 ✗ av_free(unescaped);
1210 ✗ return AVERROR(ENOSYS);
1211 }
1212 ✗ seq_found = 1;
1213 ✗ level = get_bits(&gb, 3);
1214 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1215 * width, height */
1216 ✗ skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1217 ✗ skip_bits(&gb, 1); /* broadcast */
1218 ✗ interlace = get_bits1(&gb);
1219 ✗ skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1220 }
1221 }
1222 ✗ if (!seq_found) {
1223 ✗ av_free(unescaped);
1224 ✗ return AVERROR(ENOSYS);
1225 }
1226
1227 ✗ init_put_bits(&pbc, buf, 7);
1228 /* VC1DecSpecStruc */
1229 ✗ put_bits(&pbc, 4, 12); /* profile - advanced */
1230 ✗ put_bits(&pbc, 3, level);
1231 ✗ put_bits(&pbc, 1, 0); /* reserved */
1232 /* VC1AdvDecSpecStruc */
1233 ✗ put_bits(&pbc, 3, level);
1234 ✗ put_bits(&pbc, 1, 0); /* cbr */
1235 ✗ put_bits(&pbc, 6, 0); /* reserved */
1236 ✗ put_bits(&pbc, 1, !interlace); /* no interlace */
1237 ✗ put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1238 ✗ put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1239 ✗ put_bits(&pbc, 1, !slices); /* no slice code */
1240 ✗ put_bits(&pbc, 1, 0); /* no bframe */
1241 ✗ put_bits(&pbc, 1, 0); /* reserved */
1242
1243 /* framerate */
1244 ✗ if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1245 ✗ put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1246 else
1247 ✗ put_bits32(&pbc, 0xffffffff);
1248
1249 ✗ flush_put_bits(&pbc);
1250
1251 ✗ av_free(unescaped);
1252
1253 ✗ return 0;
1254 }
1255
1256 ✗ static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1257 {
1258 ✗ uint8_t buf[7] = { 0 };
1259 int ret;
1260
1261 ✗ if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1262 ✗ return ret;
1263
1264 ✗ avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1265 ✗ ffio_wfourcc(pb, "dvc1");
1266 ✗ avio_write(pb, buf, sizeof(buf));
1267 ✗ avio_write(pb, track->extradata[track->last_stsd_index],
1268 ✗ track->extradata_size[track->last_stsd_index]);
1269
1270 ✗ return 0;
1271 }
1272
1273 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1274 {
1275 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1276 4 ffio_wfourcc(pb, "glbl");
1277 4 avio_write(pb, track->extradata[track->last_stsd_index],
1278 4 track->extradata_size[track->last_stsd_index]);
1279 4 return 8 + track->extradata_size[track->last_stsd_index];
1280 }
1281
1282 /**
1283 * Compute flags for 'lpcm' tag.
1284 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1285 */
1286 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1287 {
1288
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) {
1289 ✗ case AV_CODEC_ID_PCM_F32BE:
1290 case AV_CODEC_ID_PCM_F64BE:
1291 ✗ return 11;
1292 ✗ case AV_CODEC_ID_PCM_F32LE:
1293 case AV_CODEC_ID_PCM_F64LE:
1294 ✗ return 9;
1295 ✗ case AV_CODEC_ID_PCM_U8:
1296 ✗ return 10;
1297 ✗ case AV_CODEC_ID_PCM_S16BE:
1298 case AV_CODEC_ID_PCM_S24BE:
1299 case AV_CODEC_ID_PCM_S32BE:
1300 ✗ return 14;
1301 ✗ case AV_CODEC_ID_PCM_S8:
1302 case AV_CODEC_ID_PCM_S16LE:
1303 case AV_CODEC_ID_PCM_S24LE:
1304 case AV_CODEC_ID_PCM_S32LE:
1305 ✗ return 12;
1306 8 default:
1307 8 return 0;
1308 }
1309 }
1310
1311 32944 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1312 {
1313 int64_t next_dts;
1314
1315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32944 times.
32944 if (cluster_idx >= track->entry)
1316 ✗ return 0;
1317
1318
2/2
✓ Branch 0 taken 925 times.
✓ Branch 1 taken 32019 times.
32944 if (cluster_idx + 1 == track->entry)
1319 925 next_dts = track->track_duration + track->start_dts;
1320 else
1321 32019 next_dts = track->cluster[cluster_idx + 1].dts;
1322
1323 32944 next_dts -= track->cluster[cluster_idx].dts;
1324
1325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32944 times.
32944 av_assert0(next_dts >= 0);
1326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32944 times.
32944 av_assert0(next_dts <= INT_MAX);
1327
1328 32944 return next_dts;
1329 }
1330
1331 4 static int get_samples_per_packet(MOVTrack *track)
1332 {
1333 int i, first_duration;
1334
1335 /* use 1 for raw PCM */
1336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1337 ✗ return 1;
1338
1339 /* check to see if duration is constant for all clusters */
1340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1341 ✗ return 0;
1342 4 first_duration = get_cluster_duration(track, 0);
1343
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1344
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1345 4 return 0;
1346 }
1347 ✗ return first_duration;
1348 }
1349
1350 176 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1351 {
1352 176 int64_t pos = avio_tell(pb);
1353 176 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1354
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
176 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1355
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 !bit_rates.buffer_size)
1356 // no useful data to be written, skip
1357 86 return 0;
1358
1359 90 avio_wb32(pb, 0); /* size */
1360 90 ffio_wfourcc(pb, "btrt");
1361
1362 90 avio_wb32(pb, bit_rates.buffer_size);
1363 90 avio_wb32(pb, bit_rates.max_bit_rate);
1364 90 avio_wb32(pb, bit_rates.avg_bit_rate);
1365
1366 90 return update_size(pb, pos);
1367 }
1368
1369 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1370 {
1371 7 int64_t pos = avio_tell(pb);
1372 7 int config = 0;
1373 int ret;
1374 7 uint8_t *speaker_pos = NULL;
1375 7 const AVChannelLayout *layout = &track->par->ch_layout;
1376
1377 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1378
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) {
1379 4 config = 0;
1380 4 speaker_pos = av_malloc(layout->nb_channels);
1381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1382 ✗ return AVERROR(ENOMEM);
1383 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1384 4 speaker_pos, layout->nb_channels);
1385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1386 ✗ char buf[128] = {0};
1387
1388 ✗ av_freep(&speaker_pos);
1389 ✗ av_channel_layout_describe(layout, buf, sizeof(buf));
1390 ✗ av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1391 ✗ return ret;
1392 }
1393 }
1394
1395 7 avio_wb32(pb, 0); /* size */
1396 7 ffio_wfourcc(pb, "chnl");
1397 7 avio_wb32(pb, 0); /* version & flags */
1398
1399 7 avio_w8(pb, 1); /* stream_structure */
1400 7 avio_w8(pb, config);
1401
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1402 3 avio_wb64(pb, 0);
1403 } else {
1404 4 avio_write(pb, speaker_pos, layout->nb_channels);
1405 4 av_freep(&speaker_pos);
1406 }
1407
1408 7 return update_size(pb, pos);
1409 }
1410
1411 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1412 {
1413 9 int64_t pos = avio_tell(pb);
1414 int format_flags;
1415 int sample_size;
1416
1417 9 avio_wb32(pb, 0); /* size */
1418 9 ffio_wfourcc(pb, "pcmC");
1419 9 avio_wb32(pb, 0); /* version & flags */
1420
1421 /* 0x01: indicates little-endian format */
1422 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1423
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1425
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 ||
1426 ✗ track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1427 9 avio_w8(pb, format_flags);
1428 9 sample_size = track->par->bits_per_raw_sample;
1429
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1430 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1432 9 avio_w8(pb, sample_size);
1433
1434 9 return update_size(pb, pos);
1435 }
1436
1437 5 static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track)
1438 {
1439 5 int64_t pos = avio_tell(pb);
1440 5 avio_wb32(pb, 0); /* size */
1441 5 ffio_wfourcc(pb, "srat");
1442 5 avio_wb32(pb, 0); /* version & flags */
1443
1444 5 avio_wb32(pb, track->par->sample_rate);
1445
1446 5 return update_size(pb, pos);
1447 }
1448
1449 129 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1450 {
1451 129 int64_t pos = avio_tell(pb);
1452 129 int version = 0;
1453 129 uint32_t tag = track->tag;
1454 129 int ret = 0;
1455
1456
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 90 times.
129 if (track->mode == MODE_MOV) {
1457
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
39 if (track->par->sample_rate > UINT16_MAX || !track->par->ch_layout.nb_channels ||
1458
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 track->par->ch_layout.nb_channels > 2) {
1460
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1461 ✗ tag = AV_RL32("lpcm");
1462 4 version = 2;
1463
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
61 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1464 26 mov_pcm_be_gt16(track->par->codec_id) ||
1465
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1466
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1468 11 version = 1;
1469 }
1470
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 3 times.
90 } else if (track->mode == MODE_MP4) {
1471
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
87 if (track->par->sample_rate > UINT16_MAX &&
1472 ✗ (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG))
1473 5 version = 1;
1474 }
1475
1476 129 avio_wb32(pb, 0); /* size */
1477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
129 if (mov->encryption_scheme != MOV_ENC_NONE) {
1478 ✗ ffio_wfourcc(pb, "enca");
1479 } else {
1480 129 avio_wl32(pb, tag); // store it byteswapped
1481 }
1482 129 avio_wb32(pb, 0); /* Reserved */
1483 129 avio_wb16(pb, 0); /* Reserved */
1484 129 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1485
1486 /* SoundDescription */
1487 129 avio_wb16(pb, version); /* Version */
1488 129 avio_wb16(pb, 0); /* Revision level */
1489 129 avio_wb32(pb, 0); /* Reserved */
1490
1491
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 125 times.
129 if (version == 2) {
1492 4 avio_wb16(pb, 3);
1493 4 avio_wb16(pb, 16);
1494 4 avio_wb16(pb, 0xfffe);
1495 4 avio_wb16(pb, 0);
1496 4 avio_wb32(pb, 0x00010000);
1497 4 avio_wb32(pb, 72);
1498 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1499 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1500 4 avio_wb32(pb, 0x7F000000);
1501 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1502 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1503 4 avio_wb32(pb, track->sample_size);
1504 4 avio_wb32(pb, get_samples_per_packet(track));
1505 } else {
1506 125 unsigned sample_rate = track->par->sample_rate;
1507
1508
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 90 times.
125 if (track->mode == MODE_MOV) {
1509 35 avio_wb16(pb, track->par->ch_layout.nb_channels);
1510
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1511
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1512 1 avio_wb16(pb, 8); /* bits per sample */
1513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1514 ✗ avio_wb16(pb, track->par->bits_per_coded_sample);
1515 else
1516 34 avio_wb16(pb, 16);
1517
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26 times.
35 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1518 } else { /* reserved for mp4/3gp */
1519
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 5 times.
175 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1520 85 0 : track->par->ch_layout.nb_channels);
1521
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 5 times.
90 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 track->par->codec_id == AV_CODEC_ID_ALAC) {
1523 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1524 } else {
1525 85 avio_wb16(pb, 16);
1526 }
1527 90 avio_wb16(pb, 0);
1528
1529
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 90 times.
95 while (sample_rate > UINT16_MAX)
1530 5 sample_rate >>= 1;
1531 }
1532
1533 125 avio_wb16(pb, 0); /* packet size (= 0) */
1534
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 120 times.
125 if (track->tag == MKTAG('i','a','m','f'))
1535 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1537 ✗ avio_wb16(pb, 48000);
1538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1539 ✗ avio_wb32(pb, track->par->sample_rate);
1540 else
1541 120 avio_wb16(pb, sample_rate);
1542
1543
1/2
✓ Branch 0 taken 125 times.
✗ Branch 1 not taken.
125 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1544 125 avio_wb16(pb, 0); /* Reserved */
1545 }
1546
1547
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 28 times.
129 if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */
1548
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 9 times.
22 if (mov_pcm_le_gt16(track->par->codec_id) ||
1549 11 mov_pcm_be_gt16(track->par->codec_id))
1550 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1551 else
1552 9 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1553 11 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1554 11 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1555 11 avio_wb32(pb, 2); /* Bytes per sample */
1556 }
1557
1558
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 90 times.
129 if (track->mode == MODE_MOV &&
1559
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
39 (track->par->codec_id == AV_CODEC_ID_AAC ||
1560
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AC3 ||
1561
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1562
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1563
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1564
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1565
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1566
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 ||
1567
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) ||
1568
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1569 14 ret = mov_write_wave_tag(s, pb, track);
1570
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 51 times.
115 else if (track->tag == MKTAG('m','p','4','a'))
1571 64 ret = mov_write_esds_tag(pb, track);
1572 #if CONFIG_IAMFENC
1573
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 46 times.
51 else if (track->tag == MKTAG('i','a','m','f'))
1574 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1575 #endif
1576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1577 ✗ ret = mov_write_amr_tag(pb, track);
1578
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
46 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1579 7 ret = mov_write_ac3_tag(s, pb, track);
1580
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1581 4 ret = mov_write_eac3_tag(s, pb, track);
1582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1583 ✗ ret = mov_write_extradata_tag(pb, track);
1584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1585 ✗ ret = mov_write_wfex_tag(s, pb, track);
1586
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1587 ✗ ret = mov_write_dfla_tag(pb, track);
1588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1589 ✗ ret = mov_write_dops_tag(s, pb, track);
1590
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1591 ✗ ret = mov_write_dmlp_tag(s, pb, track);
1592
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO)
1593 1 ret = mov_write_mhac_tag(s, pb, track);
1594
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) {
1595
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (track->par->sample_rate > UINT16_MAX)
1596 5 mov_write_srat_tag(pb, track);
1597
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1598 7 ret = mov_write_chnl_tag(s, pb, track);
1599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1600 ✗ return ret;
1601 9 ret = mov_write_pcmc_tag(s, pb, track);
1602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1603 ✗ ret = mov_write_glbl_tag(pb, track);
1604
1605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
129 if (ret < 0)
1606 ✗ return ret;
1607
1608
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
129 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1609
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
87 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1610 ✗ return ret;
1611 }
1612
1613
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
129 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1614
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1615 ✗ return ret;
1616 }
1617
1618
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
129 if (mov->encryption_scheme != MOV_ENC_NONE
1619 ✗ && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1620 ✗ return ret;
1621 }
1622
1623
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 87 times.
216 if (mov->write_btrt &&
1624 87 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1625 ✗ return ret;
1626
1627
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 42 times.
129 if (track->mode == MODE_MP4)
1628 87 track->entry_version = version;
1629
1630 129 ret = update_size(pb, pos);
1631 129 return ret;
1632 }
1633
1634 ✗ static int mov_write_d263_tag(AVIOContext *pb)
1635 {
1636 ✗ avio_wb32(pb, 0xf); /* size */
1637 ✗ ffio_wfourcc(pb, "d263");
1638 ✗ ffio_wfourcc(pb, "FFMP");
1639 ✗ avio_w8(pb, 0); /* decoder version */
1640 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1641 ✗ avio_w8(pb, 0xa); /* level */
1642 ✗ avio_w8(pb, 0); /* profile */
1643 ✗ return 0xf;
1644 }
1645
1646 2 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1647 {
1648 2 int64_t pos = avio_tell(pb);
1649
1650 2 avio_wb32(pb, 0);
1651 2 ffio_wfourcc(pb, "av1C");
1652 2 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1653 2 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1654 2 return update_size(pb, pos);
1655 }
1656
1657 59 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1658 {
1659 59 int64_t pos = avio_tell(pb);
1660
1661 59 avio_wb32(pb, 0);
1662 59 ffio_wfourcc(pb, "avcC");
1663 59 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1664 59 track->extradata_size[track->last_stsd_index]);
1665 59 return update_size(pb, pos);
1666 }
1667
1668 /* AVS3 Intelligent Media Coding
1669 * Information Technology - Intelligent Media Coding
1670 * Part 6: Intelligent Media Format
1671 */
1672 ✗ static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1673 {
1674 ✗ if (len < 4)
1675 ✗ return AVERROR_INVALIDDATA;
1676
1677 ✗ if (data[0] == 1) {
1678 // In Avs3DecoderConfigurationRecord format
1679 ✗ avio_write(pb, data, len);
1680 ✗ return 0;
1681 }
1682
1683 ✗ avio_w8(pb, 1); // version
1684 ✗ avio_wb16(pb, len); // sequence_header_length
1685 ✗ avio_write(pb, data, len); // sequence_header
1686 ✗ avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1687
1688 ✗ return 0;
1689 }
1690
1691 ✗ static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1692 {
1693 ✗ int64_t pos = avio_tell(pb);
1694 ✗ avio_wb32(pb, 0);
1695 ✗ ffio_wfourcc(pb, "av3c");
1696 ✗ mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1697 ✗ track->extradata_size[track->last_stsd_index]);
1698 ✗ return update_size(pb, pos);
1699 }
1700
1701 ✗ static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1702 {
1703 ✗ int64_t pos = avio_tell(pb);
1704
1705 ✗ avio_wb32(pb, 0);
1706 ✗ ffio_wfourcc(pb, "vpcC");
1707 ✗ ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1708 ✗ track->extradata_size[track->last_stsd_index], track->par);
1709 ✗ return update_size(pb, pos);
1710 }
1711
1712 11 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1713 {
1714 11 int64_t pos = avio_tell(pb);
1715
1716 11 avio_wb32(pb, 0);
1717 11 ffio_wfourcc(pb, "hvcC");
1718
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (track->tag == MKTAG('h','v','c','1'))
1719 3 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1720 3 track->extradata_size[track->last_stsd_index], 1, s);
1721 else
1722 8 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1723 8 track->extradata_size[track->last_stsd_index], 0, s);
1724 11 return update_size(pb, pos);
1725 }
1726
1727 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1728 {
1729 1 int64_t pos = avio_tell(pb);
1730 int ret;
1731
1732 1 avio_wb32(pb, 0);
1733 1 ffio_wfourcc(pb, "lhvC");
1734
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1735 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1736 1 track->extradata_size[track->last_stsd_index], 1, s);
1737 else
1738 ✗ ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1739 ✗ track->extradata_size[track->last_stsd_index], 0, s);
1740
1741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1742 ✗ avio_seek(pb, pos, SEEK_SET);
1743 ✗ return ret;
1744 }
1745
1746 1 return update_size(pb, pos);
1747 }
1748
1749 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1750 {
1751 1 int64_t pos = avio_tell(pb);
1752
1753 1 avio_wb32(pb, 0);
1754 1 ffio_wfourcc(pb, "evcC");
1755
1756
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1757 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1758 1 track->extradata_size[track->last_stsd_index], 1);
1759 else
1760 ✗ ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1761 ✗ track->extradata_size[track->last_stsd_index], 0);
1762
1763 1 return update_size(pb, pos);
1764 }
1765
1766 ✗ static int mov_write_lvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1767 {
1768 ✗ int64_t pos = avio_tell(pb);
1769
1770 ✗ avio_wb32(pb, 0);
1771 ✗ ffio_wfourcc(pb, "lvcC");
1772
1773 ✗ ff_isom_write_lvcc(pb, track->extradata[track->last_stsd_index],
1774 ✗ track->extradata_size[track->last_stsd_index], s);
1775
1776 ✗ return update_size(pb, pos);
1777 }
1778
1779 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1780 {
1781 1 int64_t pos = avio_tell(pb);
1782
1783 1 avio_wb32(pb, 0);
1784 1 ffio_wfourcc(pb, "vvcC");
1785
1786 1 avio_w8 (pb, 0); /* version */
1787 1 avio_wb24(pb, 0); /* flags */
1788
1789
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1790 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1791 1 track->extradata_size[track->last_stsd_index], 1);
1792 else
1793 ✗ ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1794 ✗ track->extradata_size[track->last_stsd_index], 0);
1795 1 return update_size(pb, pos);
1796 }
1797
1798 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1799 {
1800 1 int64_t pos = avio_tell(pb);
1801
1802 1 avio_wb32(pb, 0);
1803 1 ffio_wfourcc(pb, "apvC");
1804
1805 1 avio_w8 (pb, 0); /* version */
1806 1 avio_wb24(pb, 0); /* flags */
1807
1808 1 ff_isom_write_apvc(pb, track->apv, s);
1809
1810 1 return update_size(pb, pos);
1811 }
1812
1813 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1814 /* https://community.avid.com/forums/t/136517.aspx */
1815 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1816 {
1817 int interlaced;
1818 int cid;
1819 23 int display_width = track->par->width;
1820 const uint8_t *extradata;
1821
1822
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (track->extradata[track->last_stsd_index] && track->extradata_size[track->last_stsd_index] > 0x29) {
1823
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->extradata[track->last_stsd_index]) != 0) {
1824 /* looks like a DNxHD bit stream */
1825 23 extradata = track->extradata[track->last_stsd_index];
1826 } else {
1827 ✗ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1828 ✗ return 0;
1829 }
1830 } else {
1831 ✗ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1832 ✗ return 0;
1833 }
1834
1835 23 cid = AV_RB32(extradata + 0x28);
1836
1837 23 avio_wb32(pb, 24); /* size */
1838 23 ffio_wfourcc(pb, "ACLR");
1839 23 ffio_wfourcc(pb, "ACLR");
1840 23 ffio_wfourcc(pb, "0001");
1841 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1842 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1843
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1844 ✗ track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1845 23 avio_wb32(pb, 1);
1846 } else {
1847 ✗ avio_wb32(pb, 2);
1848 }
1849 23 avio_wb32(pb, 0); /* reserved */
1850
1851
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1852 12 int alp = extradata[0x07] & 1;
1853 12 int pma = (extradata[0x07] >> 2) & 1;
1854 12 int sbd = (extradata[0x21] >> 5) & 3;
1855 12 int ssc = (extradata[0x2C] >> 5) & 3;
1856 12 int clv = (extradata[0x2C] >> 1) & 3;
1857 12 int clf = extradata[0x2C] & 1;
1858
1859 12 avio_wb32(pb, 32);
1860 12 ffio_wfourcc(pb, "ADHR");
1861 12 ffio_wfourcc(pb, "0001");
1862 12 avio_wb32(pb, cid); // Compression ID
1863 // 0: 4:2:2 Sub Sampling
1864 // 1: 4:2:0 Sub Sampling
1865 // 2: 4:4:4 Sub Sampling
1866 12 avio_wb32(pb, ssc); // Sub Sampling Control
1867 // 1: 8-bits per sample
1868 // 2: 10-bits per sample
1869 // 3: 12-bits per sample
1870 12 avio_wb32(pb, sbd); // Sample Bit Depth
1871 // 0: Bitstream is encoded using the YCBCR format rules and tables
1872 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1873 12 avio_wb16(pb, clf); // Color Format
1874 // 0: ITU-R BT.709
1875 // 1: ITU-R BT.2020
1876 // 2: ITU-R BT.2020 C
1877 // 3: Out-of-band
1878 12 avio_wb16(pb, clv); // Color Volume
1879 // 0: Alpha channel not present
1880 // 1: Alpha channel present
1881 12 avio_wb16(pb, alp); // Alpha Present
1882 // 0: Alpha has not been applied to video channels
1883 // 1: Alpha has been applied to the video channels prior to encoding
1884 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1885 12 return 0;
1886 }
1887
1888 11 interlaced = extradata[5] & 2;
1889
1890 11 avio_wb32(pb, 24); /* size */
1891 11 ffio_wfourcc(pb, "APRG");
1892 11 ffio_wfourcc(pb, "APRG");
1893 11 ffio_wfourcc(pb, "0001");
1894 // 1 for progressive or 2 for interlaced
1895
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1896 11 avio_wb32(pb, 2);
1897 else
1898 ✗ avio_wb32(pb, 1);
1899 11 avio_wb32(pb, 0); /* reserved */
1900
1901 11 avio_wb32(pb, 120); /* size */
1902 11 ffio_wfourcc(pb, "ARES");
1903 11 ffio_wfourcc(pb, "ARES");
1904 11 ffio_wfourcc(pb, "0001");
1905 11 avio_wb32(pb, cid); /* cid */
1906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1907 ✗ && track->par->sample_aspect_ratio.den > 0)
1908 ✗ display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1909 11 avio_wb32(pb, display_width); // field width
1910
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1911 11 avio_wb32(pb, track->par->height / 2); // field height
1912 11 avio_wb32(pb, 2); // num fields
1913 11 avio_wb32(pb, 0); // num black lines (must be 0)
1914 // 4: HD1080i
1915 // 5: HD1080P
1916 // 6: HD720P
1917 11 avio_wb32(pb, 4); // video format
1918 } else {
1919 ✗ avio_wb32(pb, track->par->height);
1920 ✗ avio_wb32(pb, 1); // num fields
1921 ✗ avio_wb32(pb, 0);
1922 ✗ if (track->par->height == 1080)
1923 ✗ avio_wb32(pb, 5);
1924 else
1925 ✗ avio_wb32(pb, 6);
1926 }
1927 /* padding */
1928 11 ffio_fill(pb, 0, 10 * 8);
1929
1930 11 return 0;
1931 }
1932
1933 ✗ static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1934 {
1935 ✗ avio_wb32(pb, 12);
1936 ✗ ffio_wfourcc(pb, "DpxE");
1937 ✗ if (track->extradata_size[track->last_stsd_index] >= 12 &&
1938 ✗ !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1939 ✗ avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1940 } else {
1941 ✗ avio_wb32(pb, 1);
1942 }
1943 ✗ return 0;
1944 }
1945
1946 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1947 {
1948 int tag;
1949
1950
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1951
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1952
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');
1953 1 else tag = MKTAG('d','v','c',' ');
1954 ✗ }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1955 ✗ else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1956 ✗ else tag = MKTAG('d','v','p','p');
1957 ✗ } else if (track->par->height == 720) { /* HD 720 line */
1958 ✗ if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1959 ✗ else tag = MKTAG('d','v','h','p');
1960 ✗ } else if (track->par->height == 1080) { /* HD 1080 line */
1961 ✗ if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1962 ✗ else tag = MKTAG('d','v','h','6');
1963 } else {
1964 ✗ av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1965 ✗ return 0;
1966 }
1967
1968 1 return tag;
1969 }
1970
1971 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1972 {
1973 3 AVRational rational_framerate = st->avg_frame_rate;
1974 3 int rate = 0;
1975
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1976 3 rate = av_q2d(rational_framerate);
1977 3 return rate;
1978 }
1979
1980 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1981 {
1982 1 int tag = track->par->codec_tag;
1983 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1984 1 AVStream *st = track->st;
1985 1 int rate = defined_frame_rate(s, st);
1986
1987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1988 ✗ tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1989
1990
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1991
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) {
1992 ✗ if (!interlaced) {
1993 ✗ if (rate == 24) tag = MKTAG('x','d','v','4');
1994 ✗ else if (rate == 25) tag = MKTAG('x','d','v','5');
1995 ✗ else if (rate == 30) tag = MKTAG('x','d','v','1');
1996 ✗ else if (rate == 50) tag = MKTAG('x','d','v','a');
1997 ✗ else if (rate == 60) tag = MKTAG('x','d','v','9');
1998 }
1999
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) {
2000 ✗ if (!interlaced) {
2001 ✗ if (rate == 24) tag = MKTAG('x','d','v','6');
2002 ✗ else if (rate == 25) tag = MKTAG('x','d','v','7');
2003 ✗ else if (rate == 30) tag = MKTAG('x','d','v','8');
2004 } else {
2005 ✗ if (rate == 25) tag = MKTAG('x','d','v','3');
2006 ✗ else if (rate == 30) tag = MKTAG('x','d','v','2');
2007 }
2008
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) {
2009 ✗ if (!interlaced) {
2010 ✗ if (rate == 24) tag = MKTAG('x','d','v','d');
2011 ✗ else if (rate == 25) tag = MKTAG('x','d','v','e');
2012 ✗ else if (rate == 30) tag = MKTAG('x','d','v','f');
2013 } else {
2014 ✗ if (rate == 25) tag = MKTAG('x','d','v','c');
2015 ✗ else if (rate == 30) tag = MKTAG('x','d','v','b');
2016 }
2017 }
2018 ✗ } else if (track->par->format == AV_PIX_FMT_YUV422P) {
2019 ✗ if (track->par->width == 1280 && track->par->height == 720) {
2020 ✗ if (!interlaced) {
2021 ✗ if (rate == 24) tag = MKTAG('x','d','5','4');
2022 ✗ else if (rate == 25) tag = MKTAG('x','d','5','5');
2023 ✗ else if (rate == 30) tag = MKTAG('x','d','5','1');
2024 ✗ else if (rate == 50) tag = MKTAG('x','d','5','a');
2025 ✗ else if (rate == 60) tag = MKTAG('x','d','5','9');
2026 }
2027 ✗ } else if (track->par->width == 1920 && track->par->height == 1080) {
2028 ✗ if (!interlaced) {
2029 ✗ if (rate == 24) tag = MKTAG('x','d','5','d');
2030 ✗ else if (rate == 25) tag = MKTAG('x','d','5','e');
2031 ✗ else if (rate == 30) tag = MKTAG('x','d','5','f');
2032 } else {
2033 ✗ if (rate == 25) tag = MKTAG('x','d','5','c');
2034 ✗ else if (rate == 30) tag = MKTAG('x','d','5','b');
2035 }
2036 }
2037 }
2038
2039 1 return tag;
2040 }
2041
2042 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
2043 {
2044 2 int tag = track->par->codec_tag;
2045 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2046 2 AVStream *st = track->st;
2047 2 int rate = defined_frame_rate(s, st);
2048
2049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
2050 ✗ tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
2051
2052
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
2053
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
2054 2 return tag;
2055
2056 ✗ if (track->par->format == AV_PIX_FMT_YUV420P10) {
2057 ✗ if (track->par->width == 960 && track->par->height == 720) {
2058 ✗ if (!interlaced) {
2059 ✗ if (rate == 24) tag = MKTAG('a','i','5','p');
2060 ✗ else if (rate == 25) tag = MKTAG('a','i','5','q');
2061 ✗ else if (rate == 30) tag = MKTAG('a','i','5','p');
2062 ✗ else if (rate == 50) tag = MKTAG('a','i','5','q');
2063 ✗ else if (rate == 60) tag = MKTAG('a','i','5','p');
2064 }
2065 ✗ } else if (track->par->width == 1440 && track->par->height == 1080) {
2066 ✗ if (!interlaced) {
2067 ✗ if (rate == 24) tag = MKTAG('a','i','5','3');
2068 ✗ else if (rate == 25) tag = MKTAG('a','i','5','2');
2069 ✗ else if (rate == 30) tag = MKTAG('a','i','5','3');
2070 } else {
2071 ✗ if (rate == 50) tag = MKTAG('a','i','5','5');
2072 ✗ else if (rate == 60) tag = MKTAG('a','i','5','6');
2073 }
2074 }
2075 ✗ } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
2076 ✗ if (track->par->width == 1280 && track->par->height == 720) {
2077 ✗ if (!interlaced) {
2078 ✗ if (rate == 24) tag = MKTAG('a','i','1','p');
2079 ✗ else if (rate == 25) tag = MKTAG('a','i','1','q');
2080 ✗ else if (rate == 30) tag = MKTAG('a','i','1','p');
2081 ✗ else if (rate == 50) tag = MKTAG('a','i','1','q');
2082 ✗ else if (rate == 60) tag = MKTAG('a','i','1','p');
2083 }
2084 ✗ } else if (track->par->width == 1920 && track->par->height == 1080) {
2085 ✗ if (!interlaced) {
2086 ✗ if (rate == 24) tag = MKTAG('a','i','1','3');
2087 ✗ else if (rate == 25) tag = MKTAG('a','i','1','2');
2088 ✗ else if (rate == 30) tag = MKTAG('a','i','1','3');
2089 } else {
2090 ✗ if (rate == 25) tag = MKTAG('a','i','1','5');
2091 ✗ else if (rate == 50) tag = MKTAG('a','i','1','5');
2092 ✗ else if (rate == 60) tag = MKTAG('a','i','1','6');
2093 }
2094 ✗ } else if ( track->par->width == 4096 && track->par->height == 2160
2095 ✗ || track->par->width == 3840 && track->par->height == 2160
2096 ✗ || track->par->width == 2048 && track->par->height == 1080) {
2097 ✗ tag = MKTAG('a','i','v','x');
2098 }
2099 }
2100
2101 ✗ return tag;
2102 }
2103
2104 ✗ static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
2105 {
2106 ✗ int tag = track->par->codec_tag;
2107
2108 ✗ if (!tag)
2109 ✗ tag = MKTAG('e', 'v', 'c', '1');
2110
2111 ✗ return tag;
2112 }
2113
2114 ✗ static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
2115 {
2116 ✗ int tag = track->par->codec_tag;
2117
2118 ✗ if (!tag)
2119 ✗ tag = MKTAG('a', 'p', 'v', '1');
2120
2121 ✗ return tag;
2122 }
2123
2124
2125 static const struct {
2126 enum AVPixelFormat pix_fmt;
2127 uint32_t tag;
2128 unsigned bps;
2129 } mov_pix_fmt_tags[] = {
2130 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
2131 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2132 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2133 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2134 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2135 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2136 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2137 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2138 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2139 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2140 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2141 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2142 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2143 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2144 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2145 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2146 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2147 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2148 };
2149
2150 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2151 {
2152 23 int tag = MKTAG('A','V','d','n');
2153
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2154
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2155 12 tag = MKTAG('A','V','d','h');
2156 23 return tag;
2157 }
2158
2159 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2160 {
2161 17 int tag = track->par->codec_tag;
2162 int i;
2163 enum AVPixelFormat pix_fmt;
2164
2165
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++) {
2166
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2167 17 tag = mov_pix_fmt_tags[i].tag;
2168 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2169
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2170 5 break;
2171 }
2172 }
2173
2174 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2175 17 track->par->bits_per_coded_sample);
2176
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2178 ✗ track->par->format != AV_PIX_FMT_GRAY8 &&
2179 ✗ track->par->format != AV_PIX_FMT_NONE)
2180 ✗ av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2181 ✗ av_get_pix_fmt_name(track->par->format));
2182 17 return tag;
2183 }
2184
2185 170 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2186 {
2187 170 unsigned int tag = track->par->codec_tag;
2188
2189 // "rtp " is used to distinguish internally created RTP-hint tracks
2190 // (with rtp_ctx) from other tracks.
2191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (tag == MKTAG('r','t','p',' '))
2192 ✗ tag = 0;
2193
3/4
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 36 times.
170 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
2194
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2195
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 17 times.
133 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2196
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 track->par->codec_id == AV_CODEC_ID_H263 ||
2197
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 2 times.
116 track->par->codec_id == AV_CODEC_ID_H264 ||
2198
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 23 times.
114 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2199
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 72 times.
181 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
2200 90 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2201
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2202 1 tag = mov_get_dv_codec_tag(s, track);
2203
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2204 17 tag = mov_get_rawvideo_codec_tag(s, track);
2205
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2206 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2207
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2208 2 tag = mov_get_h264_codec_tag(s, track);
2209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2210 ✗ tag = mov_get_evc_codec_tag(s, track);
2211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2212 ✗ tag = mov_get_apv_codec_tag(s, track);
2213
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2214 23 tag = mov_get_dnxhd_codec_tag(s, track);
2215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2216 ✗ tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2217 ✗ if (!tag) { // if no mac fcc found, try with Microsoft tags
2218 ✗ tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2219 ✗ if (tag)
2220 ✗ av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2221 "the file may be unplayable!\n");
2222 }
2223
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2224 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2226 ✗ int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2227 ✗ if (ms_tag) {
2228 ✗ tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2229 ✗ av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2230 "the file may be unplayable!\n");
2231 }
2232 }
2233 ✗ } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2234 ✗ tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2235 }
2236
2237 170 return tag;
2238 }
2239
2240 static const AVCodecTag codec_cover_image_tags[] = {
2241 { AV_CODEC_ID_MJPEG, 0xD },
2242 { AV_CODEC_ID_PNG, 0xE },
2243 { AV_CODEC_ID_BMP, 0x1B },
2244 { AV_CODEC_ID_NONE, 0 },
2245 };
2246
2247 133 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2248 unsigned int tag, int codec_id)
2249 {
2250 int i;
2251
2252 /**
2253 * Check that tag + id is in the table
2254 */
2255
2/4
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133 times.
✗ Branch 3 not taken.
133 for (i = 0; tags && tags[i]; i++) {
2256 133 const AVCodecTag *codec_tags = tags[i];
2257
1/2
✓ Branch 0 taken 2171 times.
✗ Branch 1 not taken.
2171 while (codec_tags->id != AV_CODEC_ID_NONE) {
2258
2/2
✓ Branch 2 taken 155 times.
✓ Branch 3 taken 2016 times.
2171 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2259
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 22 times.
155 codec_tags->id == codec_id)
2260 133 return codec_tags->tag;
2261 2038 codec_tags++;
2262 }
2263 }
2264 ✗ return 0;
2265 }
2266
2267 305 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2268 {
2269
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 303 times.
305 if (is_cover_image(track->st))
2270 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2271
2272
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 302 times.
303 if (track->mode == MODE_IPOD)
2273
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") &&
2274
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2275 1 !av_match_ext(s->url, "m4b"))
2276 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2277 "Quicktime/Ipod might not play the file\n");
2278
2279
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 133 times.
303 if (track->mode == MODE_MOV) {
2280 170 return mov_get_codec_tag(s, track);
2281 } else
2282 133 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2283 133 track->par->codec_id);
2284 }
2285
2286 /** Write uuid atom.
2287 * Needed to make file play in iPods running newest firmware
2288 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2289 */
2290 ✗ static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2291 {
2292 ✗ avio_wb32(pb, 28);
2293 ✗ ffio_wfourcc(pb, "uuid");
2294 ✗ avio_wb32(pb, 0x6b6840f2);
2295 ✗ avio_wb32(pb, 0x5f244fc5);
2296 ✗ avio_wb32(pb, 0xba39a51b);
2297 ✗ avio_wb32(pb, 0xcf0323f3);
2298 ✗ avio_wb32(pb, 0x0);
2299 ✗ return 28;
2300 }
2301
2302 static const uint16_t fiel_data[] = {
2303 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2304 };
2305
2306 101 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2307 {
2308 101 unsigned mov_field_order = 0;
2309
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2310 101 mov_field_order = fiel_data[field_order];
2311 else
2312 ✗ return 0;
2313 101 avio_wb32(pb, 10);
2314 101 ffio_wfourcc(pb, "fiel");
2315 101 avio_wb16(pb, mov_field_order);
2316 101 return 10;
2317 }
2318
2319 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2320 {
2321 6 MOVMuxContext *mov = s->priv_data;
2322 6 int ret = AVERROR_BUG;
2323 6 int64_t pos = avio_tell(pb);
2324 6 avio_wb32(pb, 0); /* size */
2325 6 avio_wl32(pb, track->tag); // store it byteswapped
2326 6 avio_wb32(pb, 0); /* Reserved */
2327 6 avio_wb16(pb, 0); /* Reserved */
2328 6 avio_wb16(pb, 1); /* Data-reference index */
2329
2330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2331 ✗ mov_write_esds_tag(pb, track);
2332
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2333
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2334 2 case MOV_ISMV_TTML_TAG:
2335 // ISMV dfxp requires no extradata.
2336 4 break;
2337 2 case MOV_MP4_TTML_TAG:
2338 // As specified in 14496-30, XMLSubtitleSampleEntry
2339 // Namespace
2340 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2341 // Empty schema_location
2342 2 avio_w8(pb, 0);
2343 // Empty auxiliary_mime_types
2344 2 avio_w8(pb, 0);
2345 2 break;
2346 ✗ default:
2347 ✗ av_log(NULL, AV_LOG_ERROR,
2348 "Unknown codec tag '%s' utilized for TTML stream with "
2349 "index %d (track id %d)!\n",
2350 ✗ av_fourcc2str(track->par->codec_tag), track->st->index,
2351 track->track_id);
2352 ✗ return AVERROR(EINVAL);
2353 }
2354
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2355 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2356
2357
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
11 if (mov->write_btrt &&
2358 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2359 ✗ return ret;
2360
2361 6 return update_size(pb, pos);
2362 }
2363
2364 1 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2365 {
2366 int8_t stereo_mode;
2367
2368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo_3d->flags != 0) {
2369 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2370 ✗ return 0;
2371 }
2372
2373
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo_3d->type) {
2374 ✗ case AV_STEREO3D_2D:
2375 ✗ stereo_mode = 0;
2376 ✗ break;
2377 ✗ case AV_STEREO3D_TOPBOTTOM:
2378 ✗ stereo_mode = 1;
2379 ✗ break;
2380 1 case AV_STEREO3D_SIDEBYSIDE:
2381 1 stereo_mode = 2;
2382 1 break;
2383 ✗ default:
2384 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2385 ✗ return 0;
2386 }
2387 1 avio_wb32(pb, 13); /* size */
2388 1 ffio_wfourcc(pb, "st3d");
2389 1 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2390 1 avio_w8(pb, stereo_mode);
2391 1 return 13;
2392 }
2393
2394 ✗ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2395 {
2396 int64_t sv3d_pos, svhd_pos, proj_pos;
2397 ✗ const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2398
2399 ✗ if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2400 ✗ spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2401 ✗ spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2402 ✗ av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2403 ✗ return 0;
2404 }
2405
2406 ✗ sv3d_pos = avio_tell(pb);
2407 ✗ avio_wb32(pb, 0); /* size */
2408 ✗ ffio_wfourcc(pb, "sv3d");
2409
2410 ✗ svhd_pos = avio_tell(pb);
2411 ✗ avio_wb32(pb, 0); /* size */
2412 ✗ ffio_wfourcc(pb, "svhd");
2413 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2414 ✗ avio_put_str(pb, metadata_source);
2415 ✗ update_size(pb, svhd_pos);
2416
2417 ✗ proj_pos = avio_tell(pb);
2418 ✗ avio_wb32(pb, 0); /* size */
2419 ✗ ffio_wfourcc(pb, "proj");
2420
2421 ✗ avio_wb32(pb, 24); /* size */
2422 ✗ ffio_wfourcc(pb, "prhd");
2423 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2424 ✗ avio_wb32(pb, spherical_mapping->yaw);
2425 ✗ avio_wb32(pb, spherical_mapping->pitch);
2426 ✗ avio_wb32(pb, spherical_mapping->roll);
2427
2428 ✗ switch (spherical_mapping->projection) {
2429 ✗ case AV_SPHERICAL_EQUIRECTANGULAR:
2430 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2431 ✗ avio_wb32(pb, 28); /* size */
2432 ✗ ffio_wfourcc(pb, "equi");
2433 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2434 ✗ avio_wb32(pb, spherical_mapping->bound_top);
2435 ✗ avio_wb32(pb, spherical_mapping->bound_bottom);
2436 ✗ avio_wb32(pb, spherical_mapping->bound_left);
2437 ✗ avio_wb32(pb, spherical_mapping->bound_right);
2438 ✗ break;
2439 ✗ case AV_SPHERICAL_CUBEMAP:
2440 ✗ avio_wb32(pb, 20); /* size */
2441 ✗ ffio_wfourcc(pb, "cbmp");
2442 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2443 ✗ avio_wb32(pb, 0); /* layout */
2444 ✗ avio_wb32(pb, spherical_mapping->padding); /* padding */
2445 ✗ break;
2446 }
2447 ✗ update_size(pb, proj_pos);
2448
2449 ✗ return update_size(pb, sv3d_pos);
2450 }
2451
2452 5 static inline int64_t rescale_rational(AVRational q, int b)
2453 {
2454 5 return av_rescale(q.num, b, q.den);
2455 }
2456
2457 2 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2458 const AVStereo3D *stereo3d)
2459 {
2460
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!stereo3d->horizontal_field_of_view.num)
2461 1 return;
2462
2463 1 avio_wb32(pb, 12); /* size */
2464 1 ffio_wfourcc(pb, "hfov");
2465 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2466 }
2467
2468 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2469 const AVSphericalMapping *spherical_mapping)
2470 {
2471 1 avio_wb32(pb, 24); /* size */
2472 1 ffio_wfourcc(pb, "proj");
2473 1 avio_wb32(pb, 16); /* size */
2474 1 ffio_wfourcc(pb, "prji");
2475 1 avio_wb32(pb, 0); /* version + flags */
2476
2477
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) {
2478 1 case AV_SPHERICAL_RECTILINEAR:
2479 1 ffio_wfourcc(pb, "rect");
2480 1 break;
2481 ✗ case AV_SPHERICAL_EQUIRECTANGULAR:
2482 ✗ ffio_wfourcc(pb, "equi");
2483 ✗ break;
2484 ✗ case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2485 ✗ ffio_wfourcc(pb, "hequ");
2486 ✗ break;
2487 ✗ case AV_SPHERICAL_FISHEYE:
2488 ✗ ffio_wfourcc(pb, "fish");
2489 ✗ break;
2490 ✗ default:
2491 ✗ av_assert0(0);
2492 }
2493 1 }
2494
2495 2 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2496 const AVStereo3D *stereo3d)
2497 {
2498 2 int64_t pos = avio_tell(pb);
2499 2 int view = 0;
2500
2501 2 avio_wb32(pb, 0); /* size */
2502 2 ffio_wfourcc(pb, "eyes");
2503
2504 // stri is mandatory
2505 2 avio_wb32(pb, 13); /* size */
2506 2 ffio_wfourcc(pb, "stri");
2507 2 avio_wb32(pb, 0); /* version + flags */
2508
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 switch (stereo3d->view) {
2509 ✗ case AV_STEREO3D_VIEW_LEFT:
2510 ✗ view |= 1 << 0;
2511 ✗ break;
2512 ✗ case AV_STEREO3D_VIEW_RIGHT:
2513 ✗ view |= 1 << 1;
2514 ✗ break;
2515 2 case AV_STEREO3D_VIEW_PACKED:
2516 2 view |= (1 << 0) | (1 << 1);
2517 2 break;
2518 }
2519 2 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2520 2 avio_w8(pb, view);
2521
2522 // hero is optional
2523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2524 ✗ avio_wb32(pb, 13); /* size */
2525 ✗ ffio_wfourcc(pb, "hero");
2526 ✗ avio_wb32(pb, 0); /* version + flags */
2527 ✗ avio_w8(pb, stereo3d->primary_eye);
2528 }
2529
2530 // it's not clear if cams is mandatory or optional
2531
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->baseline) {
2532 1 avio_wb32(pb, 24); /* size */
2533 1 ffio_wfourcc(pb, "cams");
2534 1 avio_wb32(pb, 16); /* size */
2535 1 ffio_wfourcc(pb, "blin");
2536 1 avio_wb32(pb, 0); /* version + flags */
2537 1 avio_wb32(pb, stereo3d->baseline);
2538 }
2539
2540 // it's not clear if cmfy is mandatory or optional
2541
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->horizontal_disparity_adjustment.num) {
2542 1 avio_wb32(pb, 24); /* size */
2543 1 ffio_wfourcc(pb, "cmfy");
2544 1 avio_wb32(pb, 16); /* size */
2545 1 ffio_wfourcc(pb, "dadj");
2546 1 avio_wb32(pb, 0); /* version + flags */
2547 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2548 }
2549
2550 2 return update_size(pb, pos);
2551 }
2552
2553 2 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2554 const AVStereo3D *stereo3d,
2555 const AVSphericalMapping *spherical_mapping)
2556 {
2557 int64_t pos;
2558
2559
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping &&
2560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2561 ✗ spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2562 ✗ spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2563 ✗ spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2564 ✗ av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2565 ✗ spherical_mapping->projection);
2566 ✗ spherical_mapping = NULL;
2567 }
2568
2569
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2570
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2571
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2572 ✗ stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2573 ✗ !stereo3d->baseline &&
2574 ✗ !stereo3d->horizontal_disparity_adjustment.num))) {
2575 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2576 ✗ stereo3d = NULL;
2577 }
2578
2579
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (!spherical_mapping && !stereo3d)
2580 ✗ return 0;
2581
2582 2 pos = avio_tell(pb);
2583 2 avio_wb32(pb, 0); /* size */
2584 2 ffio_wfourcc(pb, "vexu");
2585
2586
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping)
2587 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2588
2589
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (stereo3d)
2590 2 mov_write_eyes_tag(s, pb, stereo3d);
2591
2592 2 return update_size(pb, pos);
2593 }
2594
2595 2 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2596 {
2597 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2598
2599 2 avio_wb32(pb, 32); /* size = 8 + 24 */
2600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (dovi->dv_profile > 10)
2601 ✗ ffio_wfourcc(pb, "dvwC");
2602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (dovi->dv_profile > 7)
2603 ✗ ffio_wfourcc(pb, "dvvC");
2604 else
2605 2 ffio_wfourcc(pb, "dvcC");
2606
2607 2 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2608 2 avio_write(pb, buf, sizeof(buf));
2609
2610 2 return 32; /* 8 + 24 */
2611 }
2612
2613 2 static int mov_write_hvce_tag(AVIOContext *pb, const AVPacketSideData *sd)
2614 {
2615 2 avio_wb32(pb, 8 + sd->size);
2616 2 ffio_wfourcc(pb, "hvcE");
2617 2 avio_write(pb, sd->data, sd->size);
2618 2 return 8 + sd->size;
2619 }
2620
2621 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2622 uint32_t top, uint32_t bottom,
2623 uint32_t left, uint32_t right)
2624 {
2625 5 uint32_t cropped_width = track->par->width - left - right;
2626 5 uint32_t cropped_height = track->height - top - bottom;
2627 AVRational horizOff =
2628 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2629 5 (AVRational) { left, 1 });
2630 AVRational vertOff =
2631 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2632 5 (AVRational) { top, 1 });
2633
2634 5 avio_wb32(pb, 40);
2635 5 ffio_wfourcc(pb, "clap");
2636 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2637 5 avio_wb32(pb, 1); /* apertureWidthD */
2638 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2639 5 avio_wb32(pb, 1); /* apertureHeightD */
2640
2641 5 avio_wb32(pb, -horizOff.num);
2642 5 avio_wb32(pb, horizOff.den);
2643 5 avio_wb32(pb, -vertOff.num);
2644 5 avio_wb32(pb, vertOff.den);
2645
2646 5 return 40;
2647 }
2648
2649 26 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2650 {
2651 AVRational sar;
2652 26 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2653 26 track->par->sample_aspect_ratio.den, INT_MAX);
2654
2655 26 avio_wb32(pb, 16);
2656 26 ffio_wfourcc(pb, "pasp");
2657 26 avio_wb32(pb, sar.num);
2658 26 avio_wb32(pb, sar.den);
2659 26 return 16;
2660 }
2661
2662 ✗ static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2663 {
2664 ✗ uint32_t gama = 0;
2665 ✗ if (gamma <= 0.0)
2666 ✗ gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2667 ✗ av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2668
2669 ✗ if (gamma > 1e-6) {
2670 ✗ gama = (uint32_t)lrint((double)(1<<16) * gamma);
2671 ✗ av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2672
2673 ✗ av_assert0(track->mode == MODE_MOV);
2674 ✗ avio_wb32(pb, 12);
2675 ✗ ffio_wfourcc(pb, "gama");
2676 ✗ avio_wb32(pb, gama);
2677 ✗ return 12;
2678 } else {
2679 ✗ av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2680 }
2681 ✗ return 0;
2682 }
2683
2684 12 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2685 {
2686 12 int64_t pos = avio_tell(pb);
2687
2688 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2689 // Ref (MP4): ISO/IEC 14496-12:2012
2690
2691
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (prefer_icc) {
2692 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2693 4 track->st->codecpar->nb_coded_side_data,
2694 AV_PKT_DATA_ICC_PROFILE);
2695
2696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2697 ✗ avio_wb32(pb, 12 + sd->size);
2698 ✗ ffio_wfourcc(pb, "colr");
2699 ✗ ffio_wfourcc(pb, "prof");
2700 ✗ avio_write(pb, sd->data, sd->size);
2701 ✗ return 12 + sd->size;
2702 }
2703 else {
2704 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2705 }
2706 }
2707
2708 /* We should only ever be called for MOV, MP4 and AVIF. */
2709
3/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
12 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2710 track->mode == MODE_AVIF);
2711
2712 12 avio_wb32(pb, 0); /* size */
2713 12 ffio_wfourcc(pb, "colr");
2714
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2715 4 ffio_wfourcc(pb, "nclx");
2716 else
2717 8 ffio_wfourcc(pb, "nclc");
2718 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2719 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2720 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2721 12 avio_wb16(pb, track->par->color_primaries);
2722 12 avio_wb16(pb, track->par->color_trc);
2723 12 avio_wb16(pb, track->par->color_space);
2724
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2725 4 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2726 4 avio_w8(pb, full_range << 7);
2727 }
2728
2729 12 return update_size(pb, pos);
2730 }
2731
2732 228 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2733 {
2734 const AVPacketSideData *side_data;
2735 const AVContentLightMetadata *content_light_metadata;
2736
2737 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2738 228 track->st->codecpar->nb_coded_side_data,
2739 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2740
1/2
✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
228 if (!side_data) {
2741 228 return 0;
2742 }
2743 ✗ content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2744
2745 ✗ avio_wb32(pb, 12); // size
2746 ✗ ffio_wfourcc(pb, "clli");
2747 ✗ avio_wb16(pb, content_light_metadata->MaxCLL);
2748 ✗ avio_wb16(pb, content_light_metadata->MaxFALL);
2749 ✗ return 12;
2750 }
2751
2752 228 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2753 {
2754 228 const int chroma_den = 50000;
2755 228 const int luma_den = 10000;
2756 const AVPacketSideData *side_data;
2757 228 const AVMasteringDisplayMetadata *metadata = NULL;
2758
2759 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2760 228 track->st->codecpar->nb_coded_side_data,
2761 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 228 times.
228 if (side_data)
2763 ✗ metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2764
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
228 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2765 228 return 0;
2766 }
2767
2768 ✗ avio_wb32(pb, 32); // size
2769 ✗ ffio_wfourcc(pb, "mdcv");
2770 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2771 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2772 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2773 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2774 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2775 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2776 ✗ avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2777 ✗ avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2778 ✗ avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2779 ✗ avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2780 ✗ return 32;
2781 }
2782
2783 228 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2784 {
2785 228 const int illuminance_den = 10000;
2786 228 const int ambient_den = 50000;
2787 const AVPacketSideData *side_data;
2788 const AVAmbientViewingEnvironment *ambient;
2789
2790
2791 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2792 228 track->st->codecpar->nb_coded_side_data,
2793 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2794
2795
2/2
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 1 times.
228 if (!side_data)
2796 227 return 0;
2797
2798 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2799
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)
2800 ✗ return 0;
2801
2802 1 avio_wb32(pb, 16); // size
2803 1 ffio_wfourcc(pb, "amve");
2804 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2805 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2806 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2807 1 return 16;
2808 }
2809
2810 234 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2811 {
2812 AVDictionaryEntry *encoder;
2813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2814
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
233 || (track->par->width == 1440 && track->par->height == 1080)
2815
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
468 || (track->par->width == 1920 && track->par->height == 1080);
2816
2817
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if ((track->mode == MODE_AVIF ||
2818
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
234 track->mode == MODE_MOV ||
2819
4/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 69 times.
318 track->mode == MODE_MP4) &&
2820 228 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2821 159 av_strlcpy(compressor_name, encoder->value, 32);
2822
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
75 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2823 ✗ int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2824 ✗ AVStream *st = track->st;
2825 ✗ int rate = defined_frame_rate(NULL, st);
2826 ✗ av_strlcatf(compressor_name, len, "XDCAM");
2827 ✗ if (track->par->format == AV_PIX_FMT_YUV422P) {
2828 ✗ av_strlcatf(compressor_name, len, " HD422");
2829 ✗ } else if(track->par->width == 1440) {
2830 ✗ av_strlcatf(compressor_name, len, " HD");
2831 } else
2832 ✗ av_strlcatf(compressor_name, len, " EX");
2833
2834 ✗ av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2835
2836 ✗ av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2837 }
2838 234 }
2839
2840 ✗ static int mov_write_ccst_tag(AVIOContext *pb)
2841 {
2842 ✗ int64_t pos = avio_tell(pb);
2843 // Write sane defaults:
2844 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2845 // intra_pred_used = 1 : intra prediction may or may not be used.
2846 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2847 // reference images can be used.
2848 ✗ uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2849 (1 << 6) | /* intra_pred_used */
2850 (15 << 2); /* max_ref_per_pic */
2851 ✗ avio_wb32(pb, 0); /* size */
2852 ✗ ffio_wfourcc(pb, "ccst");
2853 ✗ avio_wb32(pb, 0); /* Version & flags */
2854 ✗ avio_w8(pb, ccstValue);
2855 ✗ avio_wb24(pb, 0); /* reserved */
2856 ✗ return update_size(pb, pos);
2857 }
2858
2859 ✗ static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2860 {
2861 ✗ int64_t pos = avio_tell(pb);
2862 ✗ avio_wb32(pb, 0); /* size */
2863 ✗ ffio_wfourcc(pb, aux_type);
2864 ✗ avio_wb32(pb, 0); /* Version & flags */
2865 ✗ avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2866 ✗ return update_size(pb, pos);
2867 }
2868
2869 234 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2870 {
2871 234 int ret = AVERROR_BUG;
2872 234 int64_t pos = avio_tell(pb);
2873 const AVPacketSideData *sd;
2874 234 char compressor_name[32] = { 0 };
2875 234 int avid = 0;
2876
2877
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)
2878
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2879
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2880
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2881
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2882
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 230 times.
468 || track->par->codec_id == AV_CODEC_ID_V210);
2883
2884 234 avio_wb32(pb, 0); /* size */
2885
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 228 times.
234 if (mov->encryption_scheme != MOV_ENC_NONE) {
2886 6 ffio_wfourcc(pb, "encv");
2887 } else {
2888 228 avio_wl32(pb, track->tag); // store it byteswapped
2889 }
2890 234 avio_wb32(pb, 0); /* Reserved */
2891 234 avio_wb16(pb, 0); /* Reserved */
2892 234 avio_wb16(pb, 1); /* Data-reference index */
2893
2894
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 230 times.
234 if (uncompressed_ycbcr) {
2895 4 avio_wb16(pb, 2); /* Codec stream version */
2896 } else {
2897 230 avio_wb16(pb, 0); /* Codec stream version */
2898 }
2899 234 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2900
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
234 if (track->mode == MODE_MOV) {
2901 144 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2902
3/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 127 times.
144 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2903 17 avio_wb32(pb, 0); /* Temporal Quality */
2904 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2905 } else {
2906 127 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2907 127 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2908 }
2909 } else {
2910 90 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2911 }
2912 234 avio_wb16(pb, track->par->width); /* Video width */
2913 234 avio_wb16(pb, track->height); /* Video height */
2914 234 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2915 234 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2916 234 avio_wb32(pb, 0); /* Data size (= 0) */
2917 234 avio_wb16(pb, 1); /* Frame count (= 1) */
2918
2919 234 find_compressor(compressor_name, 32, track);
2920 234 avio_w8(pb, strlen(compressor_name));
2921 234 avio_write(pb, compressor_name, 31);
2922
2923
3/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
234 if (track->mode == MODE_MOV && track->par->codec_id == AV_CODEC_ID_V210)
2924 ✗ avio_wb16(pb, 0x18);
2925
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 111 times.
234 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2926 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2927
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2928 else
2929 201 avio_wb16(pb, 0x18); /* Reserved */
2930
2931
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 139 times.
239 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2932 int pal_size, i;
2933 5 avio_wb16(pb, 0); /* Color table ID */
2934 5 avio_wb32(pb, 0); /* Color table seed */
2935 5 avio_wb16(pb, 0x8000); /* Color table flags */
2936
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)
2937 ✗ return AVERROR(EINVAL);
2938 5 pal_size = 1 << track->par->bits_per_coded_sample;
2939 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2940
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2941 1040 uint32_t rgb = track->palette[i];
2942 1040 uint16_t r = (rgb >> 16) & 0xff;
2943 1040 uint16_t g = (rgb >> 8) & 0xff;
2944 1040 uint16_t b = rgb & 0xff;
2945 1040 avio_wb16(pb, 0);
2946 1040 avio_wb16(pb, (r << 8) | r);
2947 1040 avio_wb16(pb, (g << 8) | g);
2948 1040 avio_wb16(pb, (b << 8) | b);
2949 }
2950 } else
2951 229 avio_wb16(pb, 0xffff); /* Reserved */
2952
2953
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 198 times.
234 if (track->tag == MKTAG('m','p','4','v'))
2954 36 mov_write_esds_tag(pb, track);
2955
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 else if (track->par->codec_id == AV_CODEC_ID_H263)
2956 ✗ mov_write_d263_tag(pb);
2957
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 3 times.
198 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2959 3 mov_write_extradata_tag(pb, track);
2960 3 avio_wb32(pb, 0);
2961
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 172 times.
195 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2962 23 mov_write_avid_tag(pb, track);
2963 23 avid = 1;
2964
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 161 times.
172 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2965 11 mov_write_hvcc_tag(mov->fc, pb, track);
2966
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2967 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2969 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2970 }
2971
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160 times.
161 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2972 1 mov_write_vvcc_tag(pb, track);
2973
16/30
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 59 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 59 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 59 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 59 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 59 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 59 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 59 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 59 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 59 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 59 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 59 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 59 times.
✗ Branch 29 not taken.
160 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2974 59 mov_write_avcc_tag(pb, track);
2975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 if (track->mode == MODE_IPOD)
2976 ✗ mov_write_uuid_tag_ipod(pb);
2977 }
2978
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2979 1 mov_write_evcc_tag(pb, track);
2980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 } else if (track->par->codec_id == AV_CODEC_ID_LCEVC) {
2981 ✗ mov_write_lvcc_tag(mov->fc, pb, track);
2982
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2983 1 mov_write_apvc_tag(mov->fc, pb, track);
2984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2985 ✗ mov_write_vpcc_tag(mov->fc, pb, track);
2986
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 97 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2987 2 mov_write_av1c_tag(pb, track);
2988
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->extradata_size[track->last_stsd_index] > 0)
2989 ✗ mov_write_dvc1_tag(pb, track);
2990
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2991
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2992 /* Don't write any potential extradata here - the cropping
2993 * is signalled via the normal width/height fields. */
2994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2995 ✗ if (track->par->codec_tag == MKTAG('R','1','0','k'))
2996 ✗ mov_write_dpxe_tag(pb, track);
2997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2998 ✗ mov_write_av3c_tag(pb, track);
2999
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
3000 4 mov_write_glbl_tag(pb, track);
3001
3002
2/2
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 59 times.
234 if (track->par->codec_id != AV_CODEC_ID_H264 &&
3003
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
3004
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 23 times.
145 track->par->codec_id != AV_CODEC_ID_DNXHD) {
3005 122 int field_order = track->par->field_order;
3006
3007
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 21 times.
122 if (field_order != AV_FIELD_UNKNOWN)
3008 101 mov_write_fiel_tag(pb, track, field_order);
3009 }
3010
3011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
3012 ✗ if (track->mode == MODE_MOV)
3013 ✗ mov_write_gama_tag(s, pb, track, mov->gamma);
3014 else
3015 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
3016 }
3017
5/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 84 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
462 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
3018 464 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
3019
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
236 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
3020
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
3021
5/6
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 216 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 216 times.
444 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
3022 216 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
3023 AV_PKT_DATA_ICC_PROFILE)) {
3024
3/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
12 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
3025 12 mov_write_colr_tag(pb, track, prefer_icc);
3026 }
3027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
3028 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
3029 }
3030
3031
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 6 times.
234 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
3032 228 mov_write_clli_tag(pb, track);
3033 228 mov_write_mdcv_tag(pb, track);
3034 228 mov_write_amve_tag(pb, track);
3035 }
3036
3037
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
234 if (track->mode == MODE_MP4) {
3038 84 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3039 84 track->st->codecpar->nb_coded_side_data,
3040 AV_PKT_DATA_STEREO3D);
3041 84 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3042 84 track->st->codecpar->nb_coded_side_data,
3043 AV_PKT_DATA_SPHERICAL);
3044
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
84 if (stereo_3d && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3045 1 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
3046
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 else if (stereo_3d)
3047 ✗ av_log(s, AV_LOG_WARNING, "Writing supported 'st3d' metadata requires -strict unofficial.\n");
3048
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
84 if (spherical_mapping && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3049 ✗ mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
3050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 else if (spherical_mapping)
3051 ✗ av_log(s, AV_LOG_WARNING, "Writing supported 'sv3d' metadata requires -strict unofficial.\n");
3052 }
3053
3054
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 6 times.
234 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
3055
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 81 times.
84 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
3056 147 const AVStereo3D *stereo3d = NULL;
3057 147 const AVSphericalMapping *spherical_mapping = NULL;
3058
3059 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3060 147 track->st->codecpar->nb_coded_side_data,
3061 AV_PKT_DATA_STEREO3D);
3062
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (sd)
3063 2 stereo3d = (AVStereo3D *)sd->data;
3064
3065 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3066 147 track->st->codecpar->nb_coded_side_data,
3067 AV_PKT_DATA_SPHERICAL);
3068
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 146 times.
147 if (sd)
3069 1 spherical_mapping = (AVSphericalMapping *)sd->data;
3070
3071
3/4
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 145 times.
147 if (stereo3d || spherical_mapping)
3072 2 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
3073
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (stereo3d)
3074 2 mov_write_hfov_tag(s, pb, stereo3d);
3075 }
3076
3077
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
234 if (track->mode == MODE_MP4) {
3078 84 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3079 84 track->st->codecpar->nb_coded_side_data,
3080 AV_PKT_DATA_DOVI_CONF);
3081
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
84 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3082 2 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
3083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (dovi) {
3084 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
3085 }
3086
3087 84 const AVPacketSideData *hvce = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3088 84 track->st->codecpar->nb_coded_side_data,
3089 AV_PKT_DATA_HEVC_CONF);
3090
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
84 if (hvce && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3091 2 mov_write_hvce_tag(pb, hvce);
3092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (hvce) {
3093 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'hvcE' box. Requires -strict unofficial.\n");
3094 }
3095 }
3096
3097
3/4
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 208 times.
234 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
3098 26 mov_write_pasp_tag(pb, track);
3099 }
3100
3101 234 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3102 234 track->st->codecpar->nb_coded_side_data,
3103 AV_PKT_DATA_FRAME_CROPPING);
3104
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
235 if (sd && sd->size >= sizeof(uint32_t) * 4) {
3105 1 uint64_t top = AV_RL32(sd->data + 0);
3106 1 uint64_t bottom = AV_RL32(sd->data + 4);
3107 1 uint64_t left = AV_RL32(sd->data + 8);
3108 1 uint64_t right = AV_RL32(sd->data + 12);
3109
3110
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
3111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
3112 ✗ av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
3113 ✗ return AVERROR(EINVAL);
3114 }
3115
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)
3116 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
3117
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 229 times.
233 } else if (uncompressed_ycbcr)
3118 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
3119
3120
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 228 times.
234 if (mov->encryption_scheme != MOV_ENC_NONE) {
3121 6 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
3122 }
3123
3124
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
318 if (mov->write_btrt &&
3125 84 ((ret = mov_write_btrt_tag(pb, track)) < 0))
3126 ✗ return ret;
3127
3128 /* extra padding for avid stsd */
3129 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3130
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 211 times.
234 if (avid)
3131 23 avio_wb32(pb, 0);
3132
3133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (track->mode == MODE_AVIF) {
3134 ✗ mov_write_ccst_tag(pb);
3135 ✗ if (mov->nb_streams > 0 && track == &mov->tracks[1])
3136 ✗ mov_write_aux_tag(pb, "auxi");
3137 }
3138
3139 234 return update_size(pb, pos);
3140 }
3141
3142 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
3143 {
3144 2 int64_t pos = avio_tell(pb);
3145 2 avio_wb32(pb, 0); /* size */
3146 2 ffio_wfourcc(pb, "rtp ");
3147 2 avio_wb32(pb, 0); /* Reserved */
3148 2 avio_wb16(pb, 0); /* Reserved */
3149 2 avio_wb16(pb, 1); /* Data-reference index */
3150
3151 2 avio_wb16(pb, 1); /* Hint track version */
3152 2 avio_wb16(pb, 1); /* Highest compatible version */
3153 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3154
3155 2 avio_wb32(pb, 12); /* size */
3156 2 ffio_wfourcc(pb, "tims");
3157 2 avio_wb32(pb, track->timescale);
3158
3159 2 return update_size(pb, pos);
3160 }
3161
3162 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3163 {
3164 2 uint64_t str_size =strlen(reel_name);
3165 2 int64_t pos = avio_tell(pb);
3166
3167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3168 ✗ av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3169 ✗ avio_wb16(pb, 0);
3170 ✗ return AVERROR(EINVAL);
3171 }
3172
3173 2 avio_wb32(pb, 0); /* size */
3174 2 ffio_wfourcc(pb, "name"); /* Data format */
3175 2 avio_wb16(pb, str_size); /* string size */
3176 2 avio_wb16(pb, track->language); /* langcode */
3177 2 avio_write(pb, reel_name, str_size); /* reel name */
3178 2 return update_size(pb,pos);
3179 }
3180
3181 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3182 {
3183 13 int64_t pos = avio_tell(pb);
3184 #if 1
3185 int frame_duration;
3186 int nb_frames;
3187 13 AVDictionaryEntry *t = NULL;
3188
3189
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) {
3190 ✗ av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3191 ✗ return AVERROR(EINVAL);
3192 } else {
3193 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3194
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);
3195 }
3196
3197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3198 ✗ av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3199 ✗ return AVERROR(EINVAL);
3200 }
3201
3202 13 avio_wb32(pb, 0); /* size */
3203 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3204 13 avio_wb32(pb, 0); /* Reserved */
3205 13 avio_wb32(pb, 1); /* Data reference index */
3206 13 avio_wb32(pb, 0); /* Flags */
3207 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3208 13 avio_wb32(pb, track->timescale); /* Timescale */
3209 13 avio_wb32(pb, frame_duration); /* Frame duration */
3210 13 avio_w8(pb, nb_frames); /* Number of frames */
3211 13 avio_w8(pb, 0); /* Reserved */
3212
3213 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3214
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)
3215 2 mov_write_source_reference_tag(pb, track, t->value);
3216 else
3217 11 avio_wb16(pb, 0); /* zero size */
3218 #else
3219
3220 avio_wb32(pb, 0); /* size */
3221 ffio_wfourcc(pb, "tmcd"); /* Data format */
3222 avio_wb32(pb, 0); /* Reserved */
3223 avio_wb32(pb, 1); /* Data reference index */
3224 if (track->par->extradata_size)
3225 avio_write(pb, track->par->extradata, track->par->extradata_size);
3226 #endif
3227 13 return update_size(pb, pos);
3228 }
3229
3230 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3231 {
3232 1 int64_t pos = avio_tell(pb);
3233 1 avio_wb32(pb, 0); /* size */
3234 1 ffio_wfourcc(pb, "gpmd");
3235 1 avio_wb32(pb, 0); /* Reserved */
3236 1 avio_wb16(pb, 0); /* Reserved */
3237 1 avio_wb16(pb, 1); /* Data-reference index */
3238 1 avio_wb32(pb, 0); /* Reserved */
3239 1 return update_size(pb, pos);
3240 }
3241
3242 383 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3243 {
3244 383 int64_t pos = avio_tell(pb);
3245 383 int ret = 0;
3246 383 avio_wb32(pb, 0); /* size */
3247 383 ffio_wfourcc(pb, "stsd");
3248 383 avio_wb32(pb, 0); /* version & flags */
3249 383 avio_wb32(pb, track->stsd_count);
3250
3251 383 int stsd_index_back = track->last_stsd_index;
3252 383 for (track->last_stsd_index = 0;
3253
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 383 times.
768 track->last_stsd_index < track->stsd_count;
3254 385 track->last_stsd_index++) {
3255
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 151 times.
385 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3256 234 ret = mov_write_video_tag(s, pb, mov, track);
3257
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 22 times.
151 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3258 129 ret = mov_write_audio_tag(s, pb, mov, track);
3259
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3260 6 ret = mov_write_subtitle_tag(s, pb, track);
3261
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3262 2 ret = mov_write_rtp_tag(pb, track);
3263
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3264 13 ret = mov_write_tmcd_tag(pb, track);
3265
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3266 1 ret = mov_write_gpmd_tag(pb, track);
3267
3268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 385 times.
385 if (ret < 0)
3269 ✗ return ret;
3270 }
3271
3272 383 track->last_stsd_index = stsd_index_back;
3273
3274 383 return update_size_and_version(pb, pos, track->entry_version);
3275 }
3276
3277 15 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3278 {
3279 15 MOVMuxContext *mov = s->priv_data;
3280 MOVCtts *ctts_entries;
3281 15 uint32_t entries = 0;
3282 uint32_t atom_size;
3283 int i;
3284
3285 15 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!ctts_entries)
3287 ✗ return AVERROR(ENOMEM);
3288 15 ctts_entries[0].count = 1;
3289 15 ctts_entries[0].offset = track->cluster[0].cts;
3290
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 15 times.
775 for (i = 1; i < track->entry; i++) {
3291
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 629 times.
760 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3292 131 ctts_entries[entries].count++; /* compress */
3293 } else {
3294 629 entries++;
3295 629 ctts_entries[entries].offset = track->cluster[i].cts;
3296 629 ctts_entries[entries].count = 1;
3297 }
3298 }
3299 15 entries++; /* last one */
3300 15 atom_size = 16 + (entries * 8);
3301 15 avio_wb32(pb, atom_size); /* size */
3302 15 ffio_wfourcc(pb, "ctts");
3303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3304 ✗ avio_w8(pb, 1); /* version */
3305 else
3306 15 avio_w8(pb, 0); /* version */
3307 15 avio_wb24(pb, 0); /* flags */
3308 15 avio_wb32(pb, entries); /* entry count */
3309
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 15 times.
659 for (i = 0; i < entries; i++) {
3310 644 avio_wb32(pb, ctts_entries[i].count);
3311 644 avio_wb32(pb, ctts_entries[i].offset);
3312 }
3313 15 av_free(ctts_entries);
3314 15 return atom_size;
3315 }
3316
3317 /* Time to sample atom */
3318 383 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3319 {
3320 383 MOVStts *stts_entries = NULL;
3321 383 uint32_t entries = -1;
3322 uint32_t atom_size;
3323 int i;
3324
3325
4/4
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 94 times.
383 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3326 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3328 ✗ return AVERROR(ENOMEM);
3329 35 stts_entries[0].count = track->sample_count;
3330 35 stts_entries[0].duration = 1;
3331 35 entries = 1;
3332 } else {
3333
2/2
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 106 times.
348 if (track->entry) {
3334 242 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (!stts_entries)
3336 ✗ return AVERROR(ENOMEM);
3337 }
3338
2/2
✓ Branch 0 taken 15833 times.
✓ Branch 1 taken 348 times.
16181 for (i = 0; i < track->entry; i++) {
3339 15833 int duration = get_cluster_duration(track, i);
3340 #if CONFIG_IAMFENC
3341
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 15778 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
15833 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3342 ✗ duration = av_rescale(duration, 48000, track->par->sample_rate);
3343 #endif
3344
4/4
✓ Branch 0 taken 15591 times.
✓ Branch 1 taken 242 times.
✓ Branch 2 taken 15161 times.
✓ Branch 3 taken 430 times.
15833 if (i && duration == stts_entries[entries].duration) {
3345 15161 stts_entries[entries].count++; /* compress */
3346 } else {
3347 672 entries++;
3348 672 stts_entries[entries].duration = duration;
3349 672 stts_entries[entries].count = 1;
3350 }
3351 }
3352 348 entries++; /* last one */
3353 }
3354 383 atom_size = 16 + (entries * 8);
3355 383 avio_wb32(pb, atom_size); /* size */
3356 383 ffio_wfourcc(pb, "stts");
3357 383 avio_wb32(pb, 0); /* version & flags */
3358 383 avio_wb32(pb, entries); /* entry count */
3359
2/2
✓ Branch 0 taken 707 times.
✓ Branch 1 taken 383 times.
1090 for (i = 0; i < entries; i++) {
3360 707 avio_wb32(pb, stts_entries[i].count);
3361 707 avio_wb32(pb, stts_entries[i].duration);
3362 }
3363 383 av_free(stts_entries);
3364 383 return atom_size;
3365 }
3366
3367 383 static int mov_write_dref_tag(AVIOContext *pb)
3368 {
3369 383 avio_wb32(pb, 28); /* size */
3370 383 ffio_wfourcc(pb, "dref");
3371 383 avio_wb32(pb, 0); /* version & flags */
3372 383 avio_wb32(pb, 1); /* entry count */
3373
3374 383 avio_wb32(pb, 0xc); /* size */
3375 //FIXME add the alis and rsrc atom
3376 383 ffio_wfourcc(pb, "url ");
3377 383 avio_wb32(pb, 1); /* version & flags */
3378
3379 383 return 28;
3380 }
3381
3382 65 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3383 {
3384 struct sgpd_entry {
3385 int count;
3386 int16_t roll_distance;
3387 int group_description_index;
3388 };
3389
3390 65 struct sgpd_entry *sgpd_entries = NULL;
3391 65 int entries = -1;
3392 65 int group = 0;
3393 int i, j;
3394
3395 65 const int OPUS_SEEK_PREROLL_MS = 80;
3396 65 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3397 65 (AVRational){1, 1000},
3398 65 (AVRational){1, 48000});
3399
3400
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 20 times.
65 if (!track->entry)
3401 45 return 0;
3402
3403 20 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!sgpd_entries)
3405 ✗ return AVERROR(ENOMEM);
3406
3407
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3408
3409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3410 ✗ for (i = 0; i < track->entry; i++) {
3411 ✗ int roll_samples_remaining = roll_samples;
3412 ✗ int distance = 0;
3413 ✗ for (j = i - 1; j >= 0; j--) {
3414 ✗ roll_samples_remaining -= get_cluster_duration(track, j);
3415 ✗ distance++;
3416 ✗ if (roll_samples_remaining <= 0)
3417 ✗ break;
3418 }
3419 /* We don't have enough preceding samples to compute a valid
3420 roll_distance here, so this sample can't be independently
3421 decoded. */
3422 ✗ if (roll_samples_remaining > 0)
3423 ✗ distance = 0;
3424 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3425 ✗ if (distance > 32) {
3426 ✗ av_freep(&sgpd_entries);
3427 ✗ return AVERROR_INVALIDDATA;
3428 }
3429 ✗ if (i && distance == sgpd_entries[entries].roll_distance) {
3430 ✗ sgpd_entries[entries].count++;
3431 } else {
3432 ✗ entries++;
3433 ✗ sgpd_entries[entries].count = 1;
3434 ✗ sgpd_entries[entries].roll_distance = distance;
3435 ✗ sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3436 }
3437 }
3438 } else {
3439 20 entries++;
3440 20 sgpd_entries[entries].count = track->sample_count;
3441 20 sgpd_entries[entries].roll_distance = 1;
3442 20 sgpd_entries[entries].group_description_index = ++group;
3443 }
3444 20 entries++;
3445
3446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!group) {
3447 ✗ av_free(sgpd_entries);
3448 ✗ return 0;
3449 }
3450
3451 /* Write sgpd tag */
3452 20 avio_wb32(pb, 24 + (group * 2)); /* size */
3453 20 ffio_wfourcc(pb, "sgpd");
3454 20 avio_wb32(pb, 1 << 24); /* fullbox */
3455 20 ffio_wfourcc(pb, "roll");
3456 20 avio_wb32(pb, 2); /* default_length */
3457 20 avio_wb32(pb, group); /* entry_count */
3458
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for (i = 0; i < entries; i++) {
3459
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (sgpd_entries[i].group_description_index) {
3460 20 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3461 }
3462 }
3463
3464 /* Write sbgp tag */
3465 20 avio_wb32(pb, 20 + (entries * 8)); /* size */
3466 20 ffio_wfourcc(pb, "sbgp");
3467 20 avio_wb32(pb, 0); /* fullbox */
3468 20 ffio_wfourcc(pb, "roll");
3469 20 avio_wb32(pb, entries); /* entry_count */
3470
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for (i = 0; i < entries; i++) {
3471 20 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3472 20 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3473 }
3474
3475 20 av_free(sgpd_entries);
3476 20 return 0;
3477 }
3478
3479 383 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3480 {
3481 383 int64_t pos = avio_tell(pb);
3482 383 int ret = 0;
3483
3484 383 avio_wb32(pb, 0); /* size */
3485 383 ffio_wfourcc(pb, "stbl");
3486
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 383 times.
383 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3487 ✗ return ret;
3488 383 mov_write_stts_tag(pb, track);
3489
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 232 times.
383 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3490
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3491
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 1 times.
151 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3492
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
150 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3493
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 148 times.
150 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3494
4/4
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 111 times.
235 track->has_keyframes && track->has_keyframes < track->entry)
3495 69 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3496
5/6
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 229 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
383 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3497 3 mov_write_sdtp_tag(pb, track);
3498
3/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 191 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
383 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3499 ✗ mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3500
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 151 times.
383 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3501
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24 times.
232 track->flags & MOV_TRACK_CTTS && track->entry) {
3502
3503
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3504 ✗ return ret;
3505 }
3506 383 mov_write_stsc_tag(pb, track);
3507 383 mov_write_stsz_tag(pb, track);
3508 383 mov_write_stco_tag(pb, track);
3509
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 378 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
383 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3510 5 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3511 }
3512
3/4
✓ Branch 0 taken 383 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 318 times.
383 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3513 65 mov_preroll_write_stbl_atoms(pb, track);
3514 }
3515 383 return update_size(pb, pos);
3516 }
3517
3518 383 static int mov_write_dinf_tag(AVIOContext *pb)
3519 {
3520 383 int64_t pos = avio_tell(pb);
3521 383 avio_wb32(pb, 0); /* size */
3522 383 ffio_wfourcc(pb, "dinf");
3523 383 mov_write_dref_tag(pb);
3524 383 return update_size(pb, pos);
3525 }
3526
3527 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3528 {
3529 7 avio_wb32(pb, 12);
3530 7 ffio_wfourcc(pb, "nmhd");
3531 7 avio_wb32(pb, 0);
3532 7 return 12;
3533 }
3534
3535 2 static int mov_write_sthd_tag(AVIOContext *pb)
3536 {
3537 2 avio_wb32(pb, 12);
3538 2 ffio_wfourcc(pb, "sthd");
3539 2 avio_wb32(pb, 0);
3540 2 return 12;
3541 }
3542
3543 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3544 {
3545 9 int64_t pos = avio_tell(pb);
3546 9 const char *font = "Lucida Grande";
3547 9 avio_wb32(pb, 0); /* size */
3548 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3549 9 avio_wb32(pb, 0); /* version & flags */
3550 9 avio_wb16(pb, 0); /* text font */
3551 9 avio_wb16(pb, 0); /* text face */
3552 9 avio_wb16(pb, 12); /* text size */
3553 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3554 9 avio_wb16(pb, 0x0000); /* text color (red) */
3555 9 avio_wb16(pb, 0x0000); /* text color (green) */
3556 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3557 9 avio_wb16(pb, 0xffff); /* background color (red) */
3558 9 avio_wb16(pb, 0xffff); /* background color (green) */
3559 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3560 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3561 9 avio_write(pb, font, strlen(font)); /* font name */
3562 9 return update_size(pb, pos);
3563 }
3564
3565 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3566 {
3567 11 int64_t pos = avio_tell(pb);
3568 11 avio_wb32(pb, 0); /* size */
3569 11 ffio_wfourcc(pb, "gmhd");
3570 11 avio_wb32(pb, 0x18); /* gmin size */
3571 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3572 11 avio_wb32(pb, 0); /* version & flags */
3573 11 avio_wb16(pb, 0x40); /* graphics mode = */
3574 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3575 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3576 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3577 11 avio_wb16(pb, 0); /* balance */
3578 11 avio_wb16(pb, 0); /* reserved */
3579
3580 /*
3581 * This special text atom is required for
3582 * Apple Quicktime chapters. The contents
3583 * don't appear to be documented, so the
3584 * bytes are copied verbatim.
3585 */
3586
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3587 11 avio_wb32(pb, 0x2C); /* size */
3588 11 ffio_wfourcc(pb, "text");
3589 11 avio_wb16(pb, 0x01);
3590 11 avio_wb32(pb, 0x00);
3591 11 avio_wb32(pb, 0x00);
3592 11 avio_wb32(pb, 0x00);
3593 11 avio_wb32(pb, 0x01);
3594 11 avio_wb32(pb, 0x00);
3595 11 avio_wb32(pb, 0x00);
3596 11 avio_wb32(pb, 0x00);
3597 11 avio_wb32(pb, 0x00004000);
3598 11 avio_wb16(pb, 0x0000);
3599 }
3600
3601
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3602 9 int64_t tmcd_pos = avio_tell(pb);
3603 9 avio_wb32(pb, 0); /* size */
3604 9 ffio_wfourcc(pb, "tmcd");
3605 9 mov_write_tcmi_tag(pb, track);
3606 9 update_size(pb, tmcd_pos);
3607
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3608 1 int64_t gpmd_pos = avio_tell(pb);
3609 1 avio_wb32(pb, 0); /* size */
3610 1 ffio_wfourcc(pb, "gpmd");
3611 1 avio_wb32(pb, 0); /* version */
3612 1 update_size(pb, gpmd_pos);
3613 }
3614 11 return update_size(pb, pos);
3615 }
3616
3617 129 static int mov_write_smhd_tag(AVIOContext *pb)
3618 {
3619 129 avio_wb32(pb, 16); /* size */
3620 129 ffio_wfourcc(pb, "smhd");
3621 129 avio_wb32(pb, 0); /* version & flags */
3622 129 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3623 129 avio_wb16(pb, 0); /* reserved */
3624 129 return 16;
3625 }
3626
3627 232 static uint16_t mov_graphics_mode(MOVTrack *track)
3628 {
3629
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 144 times.
232 if (track->mode != MODE_MOV)
3630 88 return 0; /* ISO/IEC 14496-12 doesn't define any other modes */
3631
3632
1/3
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
144 switch (track->par->alpha_mode) {
3633 144 default: return MOV_GRAPHICS_MODE_COPY;
3634 ✗ case AVALPHA_MODE_STRAIGHT: return MOV_GRAPHICS_MODE_STRAIGHT_ALPHA;
3635 ✗ case AVALPHA_MODE_PREMULTIPLIED: return MOV_GRAPHICS_MODE_PREMUL_BLACK_ALPHA;
3636 }
3637 }
3638
3639 232 static int mov_write_vmhd_tag(AVIOContext *pb, MOVTrack *track)
3640 {
3641 232 avio_wb32(pb, 0x14); /* size (always 0x14) */
3642 232 ffio_wfourcc(pb, "vmhd");
3643 232 avio_wb32(pb, 0x01); /* version & flags */
3644 232 avio_wb16(pb, mov_graphics_mode(track));
3645
2/2
✓ Branch 0 taken 696 times.
✓ Branch 1 taken 232 times.
928 for (int i = 0; i < 3; i++)
3646 696 avio_wb16(pb, 0); /* opcolor */
3647 232 return 0x14;
3648 }
3649
3650 229 static int is_clcp_track(MOVTrack *track)
3651 {
3652
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
458 return track->tag == MKTAG('c','7','0','8') ||
3653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 track->tag == MKTAG('c','6','0','8');
3654 }
3655
3656 575 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3657 {
3658 575 MOVMuxContext *mov = s->priv_data;
3659 575 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3660 575 int64_t pos = avio_tell(pb);
3661 size_t descr_len;
3662
3663 575 hdlr = "dhlr";
3664 575 hdlr_type = "url ";
3665 575 descr = "DataHandler";
3666
3667
2/2
✓ Branch 0 taken 383 times.
✓ Branch 1 taken 192 times.
575 if (track) {
3668
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 191 times.
383 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3669
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 151 times.
383 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
232 if (track->mode == MODE_AVIF) {
3671 ✗ hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3672 ✗ descr = "PictureHandler";
3673 } else {
3674 232 hdlr_type = "vide";
3675 232 descr = "VideoHandler";
3676 }
3677
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 22 times.
151 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3678 129 hdlr_type = "soun";
3679 129 descr = "SoundHandler";
3680
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3681
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3682 ✗ hdlr_type = "clcp";
3683 ✗ descr = "ClosedCaptionHandler";
3684 } else {
3685
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3686 1 hdlr_type = "sbtl";
3687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3688 ✗ hdlr_type = "subp";
3689
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3690 2 hdlr_type = "subt";
3691 } else {
3692 3 hdlr_type = "text";
3693 }
3694 6 descr = "SubtitleHandler";
3695 }
3696
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3697 2 hdlr_type = "hint";
3698 2 descr = "HintHandler";
3699
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3700 13 hdlr_type = "tmcd";
3701 13 descr = "TimeCodeHandler";
3702
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3703 1 hdlr_type = "meta";
3704 1 descr = "GoPro MET"; // GoPro Metadata
3705 } else {
3706 ✗ av_log(s, AV_LOG_WARNING,
3707 "Unknown hdlr_type for %s, writing dummy values\n",
3708 ✗ av_fourcc2str(track->par->codec_tag));
3709 }
3710
2/2
✓ Branch 0 taken 380 times.
✓ Branch 1 taken 3 times.
383 if (track->st) {
3711 // hdlr.name is used by some players to identify the content title
3712 // of the track. So if an alternate handler description is
3713 // specified, use it.
3714 AVDictionaryEntry *t;
3715 380 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3716
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 352 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
380 if (t && utf8len(t->value))
3717 28 descr = t->value;
3718 }
3719 }
3720
3721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 575 times.
575 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3722 ✗ descr = "";
3723
3724 575 avio_wb32(pb, 0); /* size */
3725 575 ffio_wfourcc(pb, "hdlr");
3726 575 avio_wb32(pb, 0); /* Version & flags */
3727 575 avio_write(pb, hdlr, 4); /* handler */
3728 575 ffio_wfourcc(pb, hdlr_type); /* handler type */
3729 575 avio_wb32(pb, 0); /* reserved */
3730 575 avio_wb32(pb, 0); /* reserved */
3731 575 avio_wb32(pb, 0); /* reserved */
3732 575 descr_len = strlen(descr);
3733
4/4
✓ Branch 0 taken 383 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 191 times.
575 if (!track || track->mode == MODE_MOV)
3734 384 avio_w8(pb, descr_len); /* pascal string */
3735 575 avio_write(pb, descr, descr_len); /* handler description */
3736
4/4
✓ Branch 0 taken 383 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 192 times.
575 if (track && track->mode != MODE_MOV)
3737 191 avio_w8(pb, 0); /* c string */
3738 575 return update_size(pb, pos);
3739 }
3740
3741 ✗ static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3742 {
3743 ✗ int64_t pos = avio_tell(pb);
3744 ✗ avio_wb32(pb, 0); /* size */
3745 ✗ ffio_wfourcc(pb, "pitm");
3746 ✗ avio_wb32(pb, 0); /* Version & flags */
3747 ✗ avio_wb16(pb, item_id); /* item_id */
3748 ✗ return update_size(pb, pos);
3749 }
3750
3751 ✗ static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3752 {
3753 ✗ int64_t pos = avio_tell(pb);
3754 ✗ avio_wb32(pb, 0); /* size */
3755 ✗ ffio_wfourcc(pb, "iloc");
3756 ✗ avio_wb32(pb, 0); /* Version & flags */
3757 ✗ avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3758 ✗ avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3759 ✗ avio_wb16(pb, mov->nb_streams); /* item_count */
3760
3761 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3762 ✗ avio_wb16(pb, i + 1); /* item_id */
3763 ✗ avio_wb16(pb, 0); /* data_reference_index */
3764 ✗ avio_wb16(pb, 1); /* extent_count */
3765 ✗ mov->avif_extent_pos[i] = avio_tell(pb);
3766 ✗ avio_wb32(pb, 0); /* extent_offset (written later) */
3767 // For animated AVIF, we simply write the first packet's size.
3768 ✗ avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3769 }
3770
3771 ✗ return update_size(pb, pos);
3772 }
3773
3774 ✗ static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3775 {
3776 ✗ int64_t iinf_pos = avio_tell(pb);
3777 ✗ avio_wb32(pb, 0); /* size */
3778 ✗ ffio_wfourcc(pb, "iinf");
3779 ✗ avio_wb32(pb, 0); /* Version & flags */
3780 ✗ avio_wb16(pb, mov->nb_streams); /* entry_count */
3781
3782 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3783 ✗ int64_t infe_pos = avio_tell(pb);
3784 ✗ avio_wb32(pb, 0); /* size */
3785 ✗ ffio_wfourcc(pb, "infe");
3786 ✗ avio_w8(pb, 0x2); /* Version */
3787 ✗ avio_wb24(pb, 0); /* flags */
3788 ✗ avio_wb16(pb, i + 1); /* item_id */
3789 ✗ avio_wb16(pb, 0); /* item_protection_index */
3790 ✗ avio_write(pb, "av01", 4); /* item_type */
3791 ✗ avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3792 ✗ update_size(pb, infe_pos);
3793 }
3794
3795 ✗ return update_size(pb, iinf_pos);
3796 }
3797
3798
3799 ✗ static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3800 {
3801 int64_t auxl_pos;
3802 ✗ int64_t iref_pos = avio_tell(pb);
3803 ✗ avio_wb32(pb, 0); /* size */
3804 ✗ ffio_wfourcc(pb, "iref");
3805 ✗ avio_wb32(pb, 0); /* Version & flags */
3806
3807 ✗ auxl_pos = avio_tell(pb);
3808 ✗ avio_wb32(pb, 0); /* size */
3809 ✗ ffio_wfourcc(pb, "auxl");
3810 ✗ avio_wb16(pb, 2); /* from_item_ID */
3811 ✗ avio_wb16(pb, 1); /* reference_count */
3812 ✗ avio_wb16(pb, 1); /* to_item_ID */
3813 ✗ update_size(pb, auxl_pos);
3814
3815 ✗ return update_size(pb, iref_pos);
3816 }
3817
3818 ✗ static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3819 int stream_index)
3820 {
3821 ✗ int64_t pos = avio_tell(pb);
3822 ✗ avio_wb32(pb, 0); /* size */
3823 ✗ ffio_wfourcc(pb, "ispe");
3824 ✗ avio_wb32(pb, 0); /* Version & flags */
3825 ✗ avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3826 ✗ avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3827 ✗ return update_size(pb, pos);
3828 }
3829
3830 ✗ static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3831 int stream_index)
3832 {
3833 ✗ int64_t pos = avio_tell(pb);
3834 const AVPixFmtDescriptor *pixdesc =
3835 ✗ av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3836 ✗ avio_wb32(pb, 0); /* size */
3837 ✗ ffio_wfourcc(pb, "pixi");
3838 ✗ avio_wb32(pb, 0); /* Version & flags */
3839 ✗ avio_w8(pb, pixdesc->nb_components); /* num_channels */
3840 ✗ for (int i = 0; i < pixdesc->nb_components; ++i) {
3841 ✗ avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3842 }
3843 ✗ return update_size(pb, pos);
3844 }
3845
3846 ✗ static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3847 {
3848 ✗ int64_t pos = avio_tell(pb);
3849 ✗ avio_wb32(pb, 0); /* size */
3850 ✗ ffio_wfourcc(pb, "ipco");
3851 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3852 ✗ mov_write_ispe_tag(pb, mov, s, i);
3853 ✗ mov_write_pixi_tag(pb, mov, s, i);
3854 ✗ mov_write_av1c_tag(pb, &mov->tracks[i]);
3855 ✗ if (!i)
3856 ✗ mov_write_colr_tag(pb, &mov->tracks[0], 0);
3857 else
3858 ✗ mov_write_aux_tag(pb, "auxC");
3859 }
3860 ✗ return update_size(pb, pos);
3861 }
3862
3863 ✗ static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3864 {
3865 ✗ int64_t pos = avio_tell(pb);
3866 ✗ avio_wb32(pb, 0); /* size */
3867 ✗ ffio_wfourcc(pb, "ipma");
3868 ✗ avio_wb32(pb, 0); /* Version & flags */
3869 ✗ avio_wb32(pb, mov->nb_streams); /* entry_count */
3870
3871 ✗ for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3872 ✗ avio_wb16(pb, i + 1); /* item_ID */
3873 ✗ avio_w8(pb, 4); /* association_count */
3874
3875 // ispe association.
3876 ✗ avio_w8(pb, index++); /* essential and property_index */
3877 // pixi association.
3878 ✗ avio_w8(pb, index++); /* essential and property_index */
3879 // av1C association.
3880 ✗ avio_w8(pb, 0x80 | index++); /* essential and property_index */
3881 // colr/auxC association.
3882 ✗ avio_w8(pb, index++); /* essential and property_index */
3883 }
3884 ✗ return update_size(pb, pos);
3885 }
3886
3887 ✗ static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3888 {
3889 ✗ int64_t pos = avio_tell(pb);
3890 ✗ avio_wb32(pb, 0); /* size */
3891 ✗ ffio_wfourcc(pb, "iprp");
3892 ✗ mov_write_ipco_tag(pb, mov, s);
3893 ✗ mov_write_ipma_tag(pb, mov, s);
3894 ✗ return update_size(pb, pos);
3895 }
3896
3897 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3898 {
3899 /* This atom must be present, but leaving the values at zero
3900 * seems harmless. */
3901 2 avio_wb32(pb, 28); /* size */
3902 2 ffio_wfourcc(pb, "hmhd");
3903 2 avio_wb32(pb, 0); /* version, flags */
3904 2 avio_wb16(pb, 0); /* maxPDUsize */
3905 2 avio_wb16(pb, 0); /* avgPDUsize */
3906 2 avio_wb32(pb, 0); /* maxbitrate */
3907 2 avio_wb32(pb, 0); /* avgbitrate */
3908 2 avio_wb32(pb, 0); /* reserved */
3909 2 return 28;
3910 }
3911
3912 383 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3913 {
3914 383 int64_t pos = avio_tell(pb);
3915 int ret;
3916
3917 383 avio_wb32(pb, 0); /* size */
3918 383 ffio_wfourcc(pb, "minf");
3919
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 151 times.
383 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3920 232 mov_write_vmhd_tag(pb, track);
3921
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 22 times.
151 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3922 129 mov_write_smhd_tag(pb);
3923
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3924
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
6 if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
3925 1 mov_write_gmhd_tag(pb, track);
3926
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3927 2 mov_write_sthd_tag(pb);
3928 } else {
3929 3 mov_write_nmhd_tag(pb);
3930 }
3931
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3932 2 mov_write_hmhd_tag(pb);
3933
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3934
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3935 4 mov_write_nmhd_tag(pb);
3936 else
3937 9 mov_write_gmhd_tag(pb, track);
3938
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3939 1 mov_write_gmhd_tag(pb, track);
3940 }
3941
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 191 times.
383 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3942 192 mov_write_hdlr_tag(s, pb, NULL);
3943 383 mov_write_dinf_tag(pb);
3944
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 383 times.
383 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3945 ✗ return ret;
3946 383 return update_size(pb, pos);
3947 }
3948
3949 1470 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3950 int64_t *start, int64_t *end, int elst, int mdhd)
3951 {
3952
5/6
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1420 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
1470 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd && track->nb_src_track) {
3953 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3954 // another track's duration, while the end_pts may be left at zero.
3955 // Calculate the pts duration for that track instead.
3956 38 get_pts_range(mov, &mov->tracks[*track->src_track], start, end, elst, mdhd);
3957 38 *start = av_rescale(*start, track->timescale,
3958 38 mov->tracks[*track->src_track].timescale);
3959 38 *end = av_rescale(*end, track->timescale,
3960 38 mov->tracks[*track->src_track].timescale);
3961 38 return;
3962 }
3963
4/4
✓ Branch 0 taken 1049 times.
✓ Branch 1 taken 383 times.
✓ Branch 2 taken 1008 times.
✓ Branch 3 taken 41 times.
1432 if (!mdhd && track->end_pts != AV_NOPTS_VALUE &&
3964
1/2
✓ Branch 0 taken 1008 times.
✗ Branch 1 not taken.
1008 track->start_dts != AV_NOPTS_VALUE &&
3965
1/2
✓ Branch 0 taken 1008 times.
✗ Branch 1 not taken.
1008 track->start_cts != AV_NOPTS_VALUE) {
3966 1008 *start = track->start_dts + track->start_cts;
3967
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 688 times.
1008 *end = elst ? track->elst_end_pts : track->end_pts;
3968 1008 return;
3969 }
3970 424 *start = 0;
3971 424 *end = track->track_duration;
3972 }
3973
3974 383 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3975 {
3976 int64_t start, end;
3977 383 get_pts_range(mov, track, &start, &end, 0, 1);
3978 383 return end - start;
3979 }
3980
3981 // Calculate the actual duration of the track, after edits.
3982 // If it starts with a pts < 0, that is removed by the edit list.
3983 // If it starts with a pts > 0, the edit list adds a delay before that.
3984 // Thus, with edit lists enabled, the post-edit output of the file is
3985 // starting with pts=0.
3986 729 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3987 {
3988 int64_t start, end;
3989 729 get_pts_range(mov, track, &start, &end, 0, 0);
3990
2/2
✓ Branch 0 taken 646 times.
✓ Branch 1 taken 83 times.
729 if (mov->use_editlist != 0)
3991 646 start = 0;
3992 729 return end - start;
3993 }
3994
3995 320 static int64_t calc_elst_duration(MOVMuxContext *mov, MOVTrack *track)
3996 {
3997 int64_t start, end;
3998 320 get_pts_range(mov, track, &start, &end, 1, 0);
3999 320 return end - start;
4000 }
4001
4002 1047 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
4003 {
4004
4/4
✓ Branch 0 taken 766 times.
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 748 times.
1047 if (track && track->mode == MODE_ISM)
4005 18 return 1;
4006
2/2
✓ Branch 0 taken 1021 times.
✓ Branch 1 taken 8 times.
1029 if (duration < INT32_MAX)
4007 1021 return 0;
4008 8 return 1;
4009 }
4010
4011 383 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4012 MOVTrack *track)
4013 {
4014 383 int64_t duration = calc_samples_pts_duration(mov, track);
4015 383 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4016
4017
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 370 times.
383 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
4018 383 ffio_wfourcc(pb, "mdhd");
4019 383 avio_w8(pb, version);
4020 383 avio_wb24(pb, 0); /* flags */
4021
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 370 times.
383 if (version == 1) {
4022 13 avio_wb64(pb, track->time);
4023 13 avio_wb64(pb, track->time);
4024 } else {
4025 370 avio_wb32(pb, track->time); /* creation time */
4026 370 avio_wb32(pb, track->time); /* modification time */
4027 }
4028 383 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
4029
4/4
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 276 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 98 times.
383 if (!track->entry && mov->mode == MODE_ISM)
4030
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4031
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 276 times.
374 else if (!track->entry)
4032
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 94 times.
98 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4033 else
4034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
276 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
4035 383 avio_wb16(pb, track->language); /* language */
4036 383 avio_wb16(pb, 0); /* reserved (quality) */
4037
4038
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 370 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
383 if (version != 0 && track->mode == MODE_MOV) {
4039 ✗ av_log(NULL, AV_LOG_ERROR,
4040 "FATAL error, file duration too long for timebase, this file will not be\n"
4041 "playable with QuickTime. Choose a different timebase with "
4042 "-video_track_timescale or a different container format\n");
4043 }
4044
4045 383 return 32;
4046 }
4047
4048 383 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
4049 MOVMuxContext *mov, MOVTrack *track)
4050 {
4051 383 int64_t pos = avio_tell(pb);
4052 int ret;
4053
4054 383 avio_wb32(pb, 0); /* size */
4055 383 ffio_wfourcc(pb, "mdia");
4056 383 mov_write_mdhd_tag(pb, mov, track);
4057 383 mov_write_hdlr_tag(s, pb, track);
4058
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 383 times.
383 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
4059 ✗ return ret;
4060 383 return update_size(pb, pos);
4061 }
4062
4063 /* transformation matrix
4064 |a b u|
4065 |c d v|
4066 |tx ty w| */
4067 663 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
4068 int16_t d, int16_t tx, int16_t ty)
4069 {
4070 663 avio_wb32(pb, a << 16); /* 16.16 format */
4071 663 avio_wb32(pb, b << 16); /* 16.16 format */
4072 663 avio_wb32(pb, 0); /* u in 2.30 format */
4073 663 avio_wb32(pb, c << 16); /* 16.16 format */
4074 663 avio_wb32(pb, d << 16); /* 16.16 format */
4075 663 avio_wb32(pb, 0); /* v in 2.30 format */
4076 663 avio_wb32(pb, tx << 16); /* 16.16 format */
4077 663 avio_wb32(pb, ty << 16); /* 16.16 format */
4078 663 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
4079 663 }
4080
4081 383 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4082 MOVTrack *track, AVStream *st)
4083 {
4084 766 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
4085 383 mov->movie_timescale, track->timescale,
4086 AV_ROUND_UP);
4087 int version;
4088 383 int flags = MOV_TKHD_FLAG_IN_MOVIE;
4089 383 int group = 0;
4090
4091 383 uint32_t *display_matrix = NULL;
4092 int i;
4093
4094
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
383 if (mov->mode == MODE_AVIF)
4095 ✗ if (!mov->avif_loop_count)
4096 ✗ duration = INT64_MAX;
4097 else
4098 ✗ duration *= mov->avif_loop_count;
4099
4100
2/2
✓ Branch 0 taken 370 times.
✓ Branch 1 taken 13 times.
383 if (st) {
4101 const AVPacketSideData *sd;
4102
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 368 times.
370 if (mov->per_stream_grouping)
4103 2 group = st->index;
4104 else
4105 368 group = st->codecpar->codec_type;
4106
4107 370 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4108 370 st->codecpar->nb_coded_side_data,
4109 AV_PKT_DATA_DISPLAYMATRIX);
4110
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 369 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
370 if (sd && sd->size == 9 * sizeof(*display_matrix))
4111 1 display_matrix = (uint32_t *)sd->data;
4112 }
4113
4114
2/2
✓ Branch 0 taken 358 times.
✓ Branch 1 taken 25 times.
383 if (track->flags & MOV_TRACK_ENABLED)
4115 358 flags |= MOV_TKHD_FLAG_ENABLED;
4116
4117 383 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4118
4119
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 370 times.
383 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
4120 383 ffio_wfourcc(pb, "tkhd");
4121 383 avio_w8(pb, version);
4122 383 avio_wb24(pb, flags);
4123
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 370 times.
383 if (version == 1) {
4124 13 avio_wb64(pb, track->time);
4125 13 avio_wb64(pb, track->time);
4126 } else {
4127 370 avio_wb32(pb, track->time); /* creation time */
4128 370 avio_wb32(pb, track->time); /* modification time */
4129 }
4130 383 avio_wb32(pb, track->track_id); /* track-id */
4131 383 avio_wb32(pb, 0); /* reserved */
4132
4/4
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 276 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 98 times.
383 if (!track->entry && mov->mode == MODE_ISM)
4133
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4134
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 276 times.
374 else if (!track->entry)
4135
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 94 times.
98 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4136 else
4137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
276 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
4138
4139 383 avio_wb32(pb, 0); /* reserved */
4140 383 avio_wb32(pb, 0); /* reserved */
4141 383 avio_wb16(pb, 0); /* layer */
4142 383 avio_wb16(pb, group); /* alternate group) */
4143 /* Volume, only for audio */
4144
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 254 times.
383 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
4145 129 avio_wb16(pb, 0x0100);
4146 else
4147 254 avio_wb16(pb, 0);
4148 383 avio_wb16(pb, 0); /* reserved */
4149
4150 /* Matrix structure */
4151
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 382 times.
383 if (display_matrix) {
4152
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
4153 9 avio_wb32(pb, display_matrix[i]);
4154 } else {
4155 382 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4156 }
4157 /* Track width and height, for visual only */
4158
4/4
✓ Branch 0 taken 370 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 138 times.
✓ Branch 3 taken 232 times.
383 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
4159
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 133 times.
375 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
4160 int64_t track_width_1616;
4161
3/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
237 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
4162 144 track_width_1616 = track->par->width * 0x10000ULL;
4163 } else {
4164 93 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
4165 93 track->par->width * 0x10000LL,
4166 93 st->sample_aspect_ratio.den);
4167
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 74 times.
93 if (!track_width_1616 ||
4168
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
19 track->height != track->par->height ||
4169 track_width_1616 > UINT32_MAX)
4170 74 track_width_1616 = track->par->width * 0x10000ULL;
4171 }
4172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track_width_1616 > UINT32_MAX) {
4173 ✗ av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4174 ✗ track_width_1616 = 0;
4175 }
4176 237 avio_wb32(pb, track_width_1616);
4177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track->height > 0xFFFF) {
4178 ✗ av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4179 ✗ avio_wb32(pb, 0);
4180 } else
4181 237 avio_wb32(pb, track->height * 0x10000U);
4182 } else {
4183 146 avio_wb32(pb, 0);
4184 146 avio_wb32(pb, 0);
4185 }
4186 383 return 0x5c;
4187 }
4188
4189 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4190 {
4191 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4192 1 track->par->sample_aspect_ratio.den);
4193
4194 1 int64_t pos = avio_tell(pb);
4195
4196 1 avio_wb32(pb, 0); /* size */
4197 1 ffio_wfourcc(pb, "tapt");
4198
4199 1 avio_wb32(pb, 20);
4200 1 ffio_wfourcc(pb, "clef");
4201 1 avio_wb32(pb, 0);
4202 1 avio_wb32(pb, width << 16);
4203 1 avio_wb32(pb, track->par->height << 16);
4204
4205 1 avio_wb32(pb, 20);
4206 1 ffio_wfourcc(pb, "prof");
4207 1 avio_wb32(pb, 0);
4208 1 avio_wb32(pb, width << 16);
4209 1 avio_wb32(pb, track->par->height << 16);
4210
4211 1 avio_wb32(pb, 20);
4212 1 ffio_wfourcc(pb, "enof");
4213 1 avio_wb32(pb, 0);
4214 1 avio_wb32(pb, track->par->width << 16);
4215 1 avio_wb32(pb, track->par->height << 16);
4216
4217 1 return update_size(pb, pos);
4218 }
4219
4220 // This box is written in the following cases:
4221 // * Seems important for the psp playback. Without it the movie seems to hang.
4222 // * Used for specifying the looping behavior of animated AVIF (as specified
4223 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4224 320 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4225 MOVTrack *track)
4226 {
4227 640 int64_t duration = av_rescale_rnd(calc_elst_duration(mov, track),
4228 320 mov->movie_timescale, track->timescale,
4229 AV_ROUND_UP);
4230 320 int version = duration < INT32_MAX ? 0 : 1;
4231 int entry_size, entry_count, size;
4232 320 int64_t delay, start_ct = track->start_cts;
4233 320 int64_t start_dts = track->start_dts;
4234 320 int flags = 0;
4235
4236
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 60 times.
320 if (track->entry) {
4237
4/6
✓ Branch 0 taken 260 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 257 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
260 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4238
4239 ✗ av_log(mov->fc, AV_LOG_DEBUG,
4240 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4241 ✗ track->cluster[0].dts, track->cluster[0].cts,
4242 start_dts, start_ct, track->track_id);
4243 ✗ start_dts = track->cluster[0].dts;
4244 ✗ start_ct = track->cluster[0].cts;
4245 }
4246 }
4247
4248 320 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4249 320 track->timescale, AV_ROUND_DOWN);
4250
4251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (mov->mode == MODE_AVIF) {
4252 ✗ delay = 0;
4253 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4254 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4255 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4256 // edit list is repeated.
4257 ✗ flags = mov->avif_loop_count != 1;
4258 ✗ start_ct = 0;
4259 }
4260
4261 320 version |= delay < INT32_MAX ? 0 : 1;
4262
4263
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 316 times.
320 entry_size = (version == 1) ? 20 : 12;
4264
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 316 times.
320 entry_count = 1 + (delay > 0);
4265 320 size = 24 + entry_count * entry_size;
4266
4267 /* write the atom data */
4268 320 avio_wb32(pb, size);
4269 320 ffio_wfourcc(pb, "edts");
4270 320 avio_wb32(pb, size - 8);
4271 320 ffio_wfourcc(pb, "elst");
4272 320 avio_w8(pb, version);
4273 320 avio_wb24(pb, flags); /* flags */
4274
4275 320 avio_wb32(pb, entry_count);
4276
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 316 times.
320 if (delay > 0) { /* add an empty edit to delay presentation */
4277 /* In the positive delay case, the delay includes the cts
4278 * offset, and the second edit list entry below trims out
4279 * the same amount from the actual content. This makes sure
4280 * that the offset last sample is included in the edit
4281 * list duration as well. */
4282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (version == 1) {
4283 ✗ avio_wb64(pb, delay);
4284 ✗ avio_wb64(pb, -1);
4285 } else {
4286 4 avio_wb32(pb, delay);
4287 4 avio_wb32(pb, -1);
4288 }
4289 4 avio_wb32(pb, 0x00010000);
4290
1/2
✓ Branch 0 taken 316 times.
✗ Branch 1 not taken.
316 } else if (mov->mode != MODE_AVIF) {
4291 /* Avoid accidentally ending up with start_ct = -1 which has got a
4292 * special meaning. Normally start_ct should end up positive or zero
4293 * here, but use FFMIN in case dts is a small positive integer
4294 * rounded to 0 when represented in movie timescale units. */
4295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 316 times.
316 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4296 316 start_ct = -FFMIN(start_dts, 0);
4297
4298 #if CONFIG_IAMFENC
4299
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 311 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
316 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4300 ✗ start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4301 #endif
4302 /* Note, this delay is calculated from the pts of the first sample,
4303 * ensuring that we don't reduce the duration for cases with
4304 * dts<0 pts=0. */
4305 316 duration += delay;
4306 }
4307
4308 /* For fragmented files, we don't know the full length yet. Setting
4309 * duration to 0 allows us to only specify the offset, including
4310 * the rest of the content (from all future fragments) without specifying
4311 * an explicit duration.
4312 *
4313 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4314 * don't reset duration to zero.
4315 */
4316
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 256 times.
320 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4317
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
64 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4318 64 duration = 0;
4319
4320 /* duration */
4321
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 316 times.
320 if (version == 1) {
4322 4 avio_wb64(pb, duration);
4323 4 avio_wb64(pb, start_ct);
4324 } else {
4325 316 avio_wb32(pb, duration);
4326 316 avio_wb32(pb, start_ct);
4327 }
4328 320 avio_wb32(pb, 0x00010000);
4329 320 return size;
4330 }
4331
4332 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4333 {
4334 14 int64_t pos = avio_tell(pb);
4335 14 avio_wb32(pb, 0); // size placeholder
4336 14 ffio_wfourcc(pb, "tref");
4337
4338
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 for (int i = 0; i < track->nb_tref_tags; i++) {
4339 14 MovTag *tag = &track->tref_tags[i];
4340 14 avio_wb32(pb, 8 + tag->nb_id * sizeof(*tag->id)); // size (subatom)
4341 14 avio_wl32(pb, tag->name);
4342
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 14 times.
30 for (int j = 0; j < tag->nb_id; j++)
4343 16 avio_wb32(pb, tag->id[j]);
4344 }
4345 14 return update_size(pb, pos);
4346 }
4347
4348 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4349 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4350 {
4351 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4352 2 ffio_wfourcc(pb, "uuid");
4353 2 ffio_wfourcc(pb, "USMT");
4354 2 avio_wb32(pb, 0x21d24fce);
4355 2 avio_wb32(pb, 0xbb88695c);
4356 2 avio_wb32(pb, 0xfac9c740);
4357 2 avio_wb32(pb, 0x1c); // another size here!
4358 2 ffio_wfourcc(pb, "MTDT");
4359 2 avio_wb32(pb, 0x00010012);
4360 2 avio_wb32(pb, 0x0a);
4361 2 avio_wb32(pb, 0x55c40000);
4362 2 avio_wb32(pb, 0x1);
4363 2 avio_wb32(pb, 0x0);
4364 2 return 0x34;
4365 }
4366
4367 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4368 {
4369 2 AVFormatContext *ctx = track->rtp_ctx;
4370 2 char buf[1000] = "";
4371 int len;
4372
4373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
4374 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], *track->src_track,
4375 NULL, NULL, 0, 0, ctx);
4376 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4377 2 len = strlen(buf);
4378
4379 2 avio_wb32(pb, len + 24);
4380 2 ffio_wfourcc(pb, "udta");
4381 2 avio_wb32(pb, len + 16);
4382 2 ffio_wfourcc(pb, "hnti");
4383 2 avio_wb32(pb, len + 8);
4384 2 ffio_wfourcc(pb, "sdp ");
4385 2 avio_write(pb, buf, len);
4386 2 return len + 24;
4387 }
4388
4389 360 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4390 const char *tag, const char *str)
4391 {
4392 360 int64_t pos = avio_tell(pb);
4393 360 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4394
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 359 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
360 if (!t || !utf8len(t->value))
4395 359 return 0;
4396
4397 1 avio_wb32(pb, 0); /* size */
4398 1 ffio_wfourcc(pb, tag); /* type */
4399 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4400 1 return update_size(pb, pos);
4401 }
4402
4403 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4404 const char *value)
4405 {
4406 2 int64_t pos = avio_tell(pb);
4407
4408 /* Box|FullBox basics */
4409 2 avio_wb32(pb, 0); /* size placeholder */
4410 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4411 2 avio_w8(pb, 0); /* version = 0 */
4412 2 avio_wb24(pb, 0); /* flags = 0 */
4413
4414 /* Required null-terminated scheme URI */
4415 2 avio_write(pb, (const unsigned char *)scheme_uri,
4416 2 strlen(scheme_uri));
4417 2 avio_w8(pb, 0);
4418
4419 /* Optional value string */
4420
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])
4421 2 avio_write(pb, (const unsigned char *)value,
4422 2 strlen(value));
4423
4424 2 avio_w8(pb, 0);
4425
4426 2 return update_size(pb, pos);
4427 }
4428
4429 174 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4430 {
4431 174 int ret = AVERROR_BUG;
4432
4433
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 174 times.
348 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4434 174 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4435
4436
2/2
✓ Branch 0 taken 870 times.
✓ Branch 1 taken 174 times.
1044 for (int j = 0; map.value_maps[j].disposition; j++) {
4437 870 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4438
2/2
✓ Branch 0 taken 868 times.
✓ Branch 1 taken 2 times.
870 if (!(st->disposition & value_map.disposition))
4439 868 continue;
4440
4441
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)
4442 ✗ return ret;
4443 }
4444 }
4445
4446 174 return 0;
4447 }
4448
4449 383 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4450 AVStream *st)
4451 {
4452 AVIOContext *pb_buf;
4453 int ret, size;
4454 uint8_t *buf;
4455
4456
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 370 times.
383 if (!st)
4457 13 return 0;
4458
4459 370 ret = avio_open_dyn_buf(&pb_buf);
4460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 370 times.
370 if (ret < 0)
4461 ✗ return ret;
4462
4463
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 10 times.
370 if (mov->mode & (MODE_MP4|MODE_MOV))
4464 360 mov_write_track_metadata(pb_buf, st, "name", "title");
4465
4466
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 196 times.
370 if (mov->mode & MODE_MP4) {
4467
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4468 ✗ goto end;
4469 }
4470
4471
2/2
✓ Branch 1 taken 367 times.
✓ Branch 2 taken 3 times.
370 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4472 3 avio_wb32(pb, size + 8);
4473 3 ffio_wfourcc(pb, "udta");
4474 3 avio_write(pb, buf, size);
4475 }
4476 367 end:
4477 370 ffio_free_dyn_buf(&pb_buf);
4478
4479 370 return ret;
4480 }
4481
4482 383 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4483 MOVTrack *track, AVStream *st)
4484 {
4485 383 int64_t pos = avio_tell(pb);
4486 383 int entry_backup = track->entry;
4487 383 int chunk_backup = track->chunkCount;
4488 int ret;
4489
4490 /* If we want to have an empty moov, but some samples already have been
4491 * buffered (delay_moov), pretend that no samples have been written yet. */
4492
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 280 times.
383 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4493 103 track->chunkCount = track->entry = 0;
4494
4495 383 avio_wb32(pb, 0); /* size */
4496 383 ffio_wfourcc(pb, "trak");
4497 383 mov_write_tkhd_tag(pb, mov, track, st);
4498
4499 av_assert2(mov->use_editlist >= 0);
4500
4501
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 37 times.
383 if (track->start_dts != AV_NOPTS_VALUE) {
4502
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 26 times.
346 if (mov->use_editlist)
4503 320 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4504
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))
4505 ✗ av_log(mov->fc, AV_LOG_WARNING,
4506 "Not writing any edit list even though one would have been required\n");
4507 }
4508
4509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
383 if (mov->is_animated_avif)
4510 ✗ mov_write_edts_tag(pb, mov, track);
4511
4512
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 369 times.
383 if (track->nb_tref_tags)
4513 14 mov_write_tref_tag(pb, track);
4514
4515
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 383 times.
383 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4516 ✗ return ret;
4517
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 381 times.
383 if (track->mode == MODE_PSP)
4518 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4519
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 381 times.
383 if (track->tag == MKTAG('r','t','p',' '))
4520 2 mov_write_udta_sdp(pb, track);
4521
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 191 times.
383 if (track->mode == MODE_MOV) {
4522
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 48 times.
192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4523 144 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4524
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
144 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4525 1 mov_write_tapt_tag(pb, track);
4526 }
4527 }
4528
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
192 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4529 ✗ mov_write_tapt_tag(pb, track);
4530 }
4531 }
4532 383 mov_write_track_udta_tag(pb, mov, st);
4533 383 track->entry = entry_backup;
4534 383 track->chunkCount = chunk_backup;
4535 383 return update_size(pb, pos);
4536 }
4537
4538 ✗ static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4539 {
4540 ✗ int i, has_audio = 0, has_video = 0;
4541 ✗ int64_t pos = avio_tell(pb);
4542 ✗ int audio_profile = mov->iods_audio_profile;
4543 ✗ int video_profile = mov->iods_video_profile;
4544 ✗ for (i = 0; i < mov->nb_tracks; i++) {
4545 ✗ if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4546 ✗ has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4547 ✗ has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4548 }
4549 }
4550 ✗ if (audio_profile < 0)
4551 ✗ audio_profile = 0xFF - has_audio;
4552 ✗ if (video_profile < 0)
4553 ✗ video_profile = 0xFF - has_video;
4554 ✗ avio_wb32(pb, 0x0); /* size */
4555 ✗ ffio_wfourcc(pb, "iods");
4556 ✗ avio_wb32(pb, 0); /* version & flags */
4557 ✗ put_descr(pb, 0x10, 7);
4558 ✗ avio_wb16(pb, 0x004f);
4559 ✗ avio_w8(pb, 0xff);
4560 ✗ avio_w8(pb, 0xff);
4561 ✗ avio_w8(pb, audio_profile);
4562 ✗ avio_w8(pb, video_profile);
4563 ✗ avio_w8(pb, 0xff);
4564 ✗ return update_size(pb, pos);
4565 }
4566
4567 123 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4568 {
4569 123 avio_wb32(pb, 0x20); /* size */
4570 123 ffio_wfourcc(pb, "trex");
4571 123 avio_wb32(pb, 0); /* version & flags */
4572 123 avio_wb32(pb, track->track_id); /* track ID */
4573 123 avio_wb32(pb, 1); /* default sample description index */
4574 123 avio_wb32(pb, 0); /* default sample duration */
4575 123 avio_wb32(pb, 0); /* default sample size */
4576 123 avio_wb32(pb, 0); /* default sample flags */
4577 123 return 0;
4578 }
4579
4580 67 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4581 {
4582 67 int64_t pos = avio_tell(pb);
4583 int i;
4584 67 avio_wb32(pb, 0x0); /* size */
4585 67 ffio_wfourcc(pb, "mvex");
4586
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 67 times.
190 for (i = 0; i < mov->nb_tracks; i++)
4587 123 mov_write_trex_tag(pb, &mov->tracks[i]);
4588 67 return update_size(pb, pos);
4589 }
4590
4591 281 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4592 {
4593 281 int max_track_id = 1, i;
4594 281 int64_t max_track_len = 0;
4595 int version;
4596 int timescale;
4597
4598
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 281 times.
666 for (i = 0; i < mov->nb_tracks; i++) {
4599
3/4
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 346 times.
✗ Branch 3 not taken.
385 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4600 692 int64_t max_track_len_temp = av_rescale_rnd(
4601 346 calc_pts_duration(mov, &mov->tracks[i]),
4602 346 mov->movie_timescale,
4603 346 mov->tracks[i].timescale,
4604 AV_ROUND_UP);
4605
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 70 times.
346 if (max_track_len < max_track_len_temp)
4606 276 max_track_len = max_track_len_temp;
4607
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 262 times.
346 if (max_track_id < mov->tracks[i].track_id)
4608 84 max_track_id = mov->tracks[i].track_id;
4609 }
4610 }
4611 /* If using delay_moov, make sure the output is the same as if no
4612 * samples had been written yet. */
4613
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 224 times.
281 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4614 57 max_track_len = 0;
4615 57 max_track_id = 1;
4616 }
4617
4618 281 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
281 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4620
4621 281 ffio_wfourcc(pb, "mvhd");
4622 281 avio_w8(pb, version);
4623 281 avio_wb24(pb, 0); /* flags */
4624
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
281 if (version == 1) {
4625 ✗ avio_wb64(pb, mov->time);
4626 ✗ avio_wb64(pb, mov->time);
4627 } else {
4628 281 avio_wb32(pb, mov->time); /* creation time */
4629 281 avio_wb32(pb, mov->time); /* modification time */
4630 }
4631
4632 281 timescale = mov->movie_timescale;
4633
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
281 if (mov->mode == MODE_AVIF && !timescale)
4634 ✗ timescale = mov->tracks[0].timescale;
4635
4636 281 avio_wb32(pb, timescale);
4637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
281 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4638
4639 281 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4640 281 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4641 281 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4642
4643 /* Matrix structure */
4644 281 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4645
4646 281 avio_wb32(pb, 0); /* reserved (preview time) */
4647 281 avio_wb32(pb, 0); /* reserved (preview duration) */
4648 281 avio_wb32(pb, 0); /* reserved (poster time) */
4649 281 avio_wb32(pb, 0); /* reserved (selection time) */
4650 281 avio_wb32(pb, 0); /* reserved (selection duration) */
4651 281 avio_wb32(pb, 0); /* reserved (current time) */
4652 281 avio_wb32(pb, max_track_id + 1); /* Next track id */
4653 281 return 0x6c;
4654 }
4655
4656 121 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4657 AVFormatContext *s)
4658 {
4659 121 avio_wb32(pb, 33); /* size */
4660 121 ffio_wfourcc(pb, "hdlr");
4661 121 avio_wb32(pb, 0);
4662 121 avio_wb32(pb, 0);
4663 121 ffio_wfourcc(pb, "mdir");
4664 121 ffio_wfourcc(pb, "appl");
4665 121 avio_wb32(pb, 0);
4666 121 avio_wb32(pb, 0);
4667 121 avio_w8(pb, 0);
4668 121 return 33;
4669 }
4670
4671 /* helper function to write a data tag with the specified string as data */
4672 75 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4673 {
4674 75 size_t data_len = strlen(data);
4675
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 34 times.
75 if (long_style) {
4676 41 int size = 16 + data_len;
4677 41 avio_wb32(pb, size); /* size */
4678 41 ffio_wfourcc(pb, "data");
4679 41 avio_wb32(pb, 1);
4680 41 avio_wb32(pb, 0);
4681 41 avio_write(pb, data, data_len);
4682 41 return size;
4683 } else {
4684 34 avio_wb16(pb, data_len); /* string length */
4685
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4686 26 lang = ff_mov_iso639_to_lang("und", 1);
4687 34 avio_wb16(pb, lang);
4688 34 avio_write(pb, data, data_len);
4689 34 return data_len + 4;
4690 }
4691 }
4692
4693 74 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4694 const char *value, int lang, int long_style)
4695 {
4696 74 int size = 0;
4697
2/4
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
✗ Branch 3 not taken.
74 if (value && value[0]) {
4698 74 int64_t pos = avio_tell(pb);
4699 74 avio_wb32(pb, 0); /* size */
4700 74 ffio_wfourcc(pb, name);
4701 74 mov_write_string_data_tag(pb, value, lang, long_style);
4702 74 size = update_size(pb, pos);
4703 }
4704 74 return size;
4705 }
4706
4707 1 static int mov_write_freeform_tag(AVIOContext *pb, const char *mean,
4708 const char *name, const char *data)
4709 {
4710
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!data || !data[0])
4711 ✗ return 0;
4712
4713 static const char stub_flags[4] = {0, 0, 0, 0};
4714
4715 1 int64_t entry_pos = avio_tell(pb);
4716 1 avio_wb32(pb, 0); /* size */
4717 1 ffio_wfourcc(pb, "----"); /* freeform */
4718
4719 1 size_t mean_len = strlen(mean);
4720 1 avio_wb32(pb, 12 + mean_len);
4721 1 ffio_wfourcc(pb, "mean");
4722 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4723 1 avio_write(pb, mean, mean_len);
4724
4725 1 size_t name_len = strlen(name);
4726 1 avio_wb32(pb, 12 + name_len);
4727 1 ffio_wfourcc(pb, "name");
4728 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4729 1 avio_write(pb, name, name_len);
4730
4731 1 mov_write_string_data_tag(pb, data, 0, 1);
4732
4733 1 return update_size(pb, entry_pos);
4734 }
4735
4736 4525 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4737 const char *tag, int *lang)
4738 {
4739 int l, len, len2;
4740 4525 AVDictionaryEntry *t, *t2 = NULL;
4741 char tag2[16];
4742
4743 4525 *lang = 0;
4744
4745
2/2
✓ Branch 1 taken 4462 times.
✓ Branch 2 taken 63 times.
4525 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4746 4462 return NULL;
4747
4748 63 len = strlen(t->key);
4749 63 snprintf(tag2, sizeof(tag2), "%s-", tag);
4750
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 55 times.
63 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4751 8 len2 = strlen(t2->key);
4752
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)
4753
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4754 8 *lang = l;
4755 8 return t;
4756 }
4757 }
4758 55 return t;
4759 }
4760
4761 4404 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4762 const char *name, const char *tag,
4763 int long_style)
4764 {
4765 int lang;
4766 4404 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4767
2/2
✓ Branch 0 taken 4341 times.
✓ Branch 1 taken 63 times.
4404 if (!t)
4768 4341 return 0;
4769 63 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4770 }
4771
4772 121 static int mov_write_custom_metadata(AVFormatContext *s, AVIOContext *pb,
4773 const char *mean, const char *name,
4774 const char *tag)
4775 {
4776 121 AVDictionaryEntry *t = av_dict_get(s->metadata, tag, NULL, 0);
4777
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 1 times.
121 if (!t)
4778 120 return 0;
4779 1 return mov_write_freeform_tag(pb, mean, name, t->value);
4780 }
4781
4782 /* iTunes bpm number */
4783 121 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4784 {
4785 121 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 int size = 0, tmpo = t ? atoi(t->value) : 0;
4787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 if (tmpo) {
4788 ✗ size = 26;
4789 ✗ avio_wb32(pb, size);
4790 ✗ ffio_wfourcc(pb, "tmpo");
4791 ✗ avio_wb32(pb, size-8); /* size */
4792 ✗ ffio_wfourcc(pb, "data");
4793 ✗ avio_wb32(pb, 0x15); //type specifier
4794 ✗ avio_wb32(pb, 0);
4795 ✗ avio_wb16(pb, tmpo); // data
4796 }
4797 121 return size;
4798 }
4799
4800 /* 3GPP TS 26.244 */
4801 121 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4802 {
4803 int lang;
4804 121 int64_t pos = avio_tell(pb);
4805 double latitude, longitude, altitude;
4806 int32_t latitude_fix, longitude_fix, altitude_fix;
4807 121 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4808 121 const char *ptr, *place = "";
4809 char *end;
4810 static const char *astronomical_body = "earth";
4811
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 if (!t)
4812 121 return 0;
4813
4814 ✗ ptr = t->value;
4815 ✗ latitude = strtod(ptr, &end);
4816 ✗ if (end == ptr) {
4817 ✗ av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4818 ✗ return 0;
4819 }
4820 ✗ ptr = end;
4821 ✗ longitude = strtod(ptr, &end);
4822 ✗ if (end == ptr) {
4823 ✗ av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4824 ✗ return 0;
4825 }
4826 ✗ ptr = end;
4827 ✗ altitude = strtod(ptr, &end);
4828 /* If no altitude was present, the default 0 should be fine */
4829 ✗ if (*end == '/')
4830 ✗ place = end + 1;
4831
4832 ✗ latitude_fix = (int32_t) ((1 << 16) * latitude);
4833 ✗ longitude_fix = (int32_t) ((1 << 16) * longitude);
4834 ✗ altitude_fix = (int32_t) ((1 << 16) * altitude);
4835
4836 ✗ avio_wb32(pb, 0); /* size */
4837 ✗ ffio_wfourcc(pb, "loci"); /* type */
4838 ✗ avio_wb32(pb, 0); /* version + flags */
4839 ✗ avio_wb16(pb, lang);
4840 ✗ avio_write(pb, place, strlen(place) + 1);
4841 ✗ avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4842 ✗ avio_wb32(pb, longitude_fix);
4843 ✗ avio_wb32(pb, latitude_fix);
4844 ✗ avio_wb32(pb, altitude_fix);
4845 ✗ avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4846 ✗ avio_w8(pb, 0); /* additional notes, null terminated string */
4847
4848 ✗ return update_size(pb, pos);
4849 }
4850
4851 /* iTunes track or disc number */
4852 242 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4853 AVFormatContext *s, int disc)
4854 {
4855
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 121 times.
242 AVDictionaryEntry *t = av_dict_get(s->metadata,
4856 disc ? "disc" : "track",
4857 NULL, 0);
4858
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 238 times.
242 int size = 0, track = t ? atoi(t->value) : 0;
4859
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 238 times.
242 if (track) {
4860 4 int tracks = 0;
4861 4 char *slash = strchr(t->value, '/');
4862
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (slash)
4863 3 tracks = atoi(slash + 1);
4864 4 avio_wb32(pb, 32); /* size */
4865
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4866 4 avio_wb32(pb, 24); /* size */
4867 4 ffio_wfourcc(pb, "data");
4868 4 avio_wb32(pb, 0); // 8 bytes empty
4869 4 avio_wb32(pb, 0);
4870 4 avio_wb16(pb, 0); // empty
4871 4 avio_wb16(pb, track); // track / disc number
4872 4 avio_wb16(pb, tracks); // total track / disc number
4873 4 avio_wb16(pb, 0); // empty
4874 4 size = 32;
4875 }
4876 242 return size;
4877 }
4878
4879 726 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4880 const char *name, const char *tag,
4881 int len)
4882 {
4883 726 AVDictionaryEntry *t = NULL;
4884 uint8_t num;
4885 726 int size = 24 + len;
4886
4887
3/4
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 484 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 242 times.
726 if (len != 1 && len != 4)
4888 ✗ return -1;
4889
4890
2/2
✓ Branch 1 taken 724 times.
✓ Branch 2 taken 2 times.
726 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4891 724 return 0;
4892 2 num = atoi(t->value);
4893
4894 2 avio_wb32(pb, size);
4895 2 ffio_wfourcc(pb, name);
4896 2 avio_wb32(pb, size - 8);
4897 2 ffio_wfourcc(pb, "data");
4898 2 avio_wb32(pb, 0x15);
4899 2 avio_wb32(pb, 0);
4900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4901 2 else avio_w8 (pb, num);
4902
4903 2 return size;
4904 }
4905
4906 121 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4907 {
4908 121 MOVMuxContext *mov = s->priv_data;
4909 121 int64_t pos = 0;
4910
4911
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 121 times.
305 for (int i = 0; i < mov->nb_streams; i++) {
4912 184 MOVTrack *trk = &mov->tracks[i];
4913
4914
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
184 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4915 182 continue;
4916
4917
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4918 1 pos = avio_tell(pb);
4919 1 avio_wb32(pb, 0);
4920 1 ffio_wfourcc(pb, "covr");
4921 }
4922 2 avio_wb32(pb, 16 + trk->cover_image->size);
4923 2 ffio_wfourcc(pb, "data");
4924 2 avio_wb32(pb, trk->tag);
4925 2 avio_wb32(pb , 0);
4926 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4927 }
4928
4929
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 120 times.
121 return pos ? update_size(pb, pos) : 0;
4930 }
4931
4932 /* iTunes meta data list */
4933 121 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4934 AVFormatContext *s)
4935 {
4936 121 int64_t pos = avio_tell(pb);
4937 121 avio_wb32(pb, 0); /* size */
4938 121 ffio_wfourcc(pb, "ilst");
4939 121 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4940 121 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4941 121 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4942 121 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4943 121 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4944 121 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4945
1/2
✓ Branch 1 taken 121 times.
✗ Branch 2 not taken.
121 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4946
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 110 times.
121 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4947 11 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4948 }
4949 121 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4950 121 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4951 121 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4952 121 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4953 121 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4954 121 mov_write_string_metadata(s, pb, "desc", "description",1);
4955 121 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4956 121 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4957 121 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4958 121 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4959 121 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4960 121 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4961 121 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4962 121 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4963 121 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4964 121 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4965 121 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4966 121 mov_write_covr(pb, s);
4967 121 mov_write_trkn_tag(pb, mov, s, 0); // track number
4968 121 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4969 121 mov_write_tmpo_tag(pb, s);
4970 121 mov_write_custom_metadata(s, pb, "com.apple.iTunes", "DISCSUBTITLE", "disc_subtitle");
4971 121 return update_size(pb, pos);
4972 }
4973
4974 ✗ static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4975 AVFormatContext *s)
4976 {
4977 ✗ avio_wb32(pb, 33); /* size */
4978 ✗ ffio_wfourcc(pb, "hdlr");
4979 ✗ avio_wb32(pb, 0);
4980 ✗ avio_wb32(pb, 0);
4981 ✗ ffio_wfourcc(pb, "mdta");
4982 ✗ avio_wb32(pb, 0);
4983 ✗ avio_wb32(pb, 0);
4984 ✗ avio_wb32(pb, 0);
4985 ✗ avio_w8(pb, 0);
4986 ✗ return 33;
4987 }
4988
4989 ✗ static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4990 AVFormatContext *s)
4991 {
4992 ✗ const AVDictionaryEntry *t = NULL;
4993 ✗ int64_t pos = avio_tell(pb);
4994 int64_t curpos, entry_pos;
4995 ✗ int count = 0;
4996
4997 ✗ avio_wb32(pb, 0); /* size */
4998 ✗ ffio_wfourcc(pb, "keys");
4999 ✗ avio_wb32(pb, 0);
5000 ✗ entry_pos = avio_tell(pb);
5001 ✗ avio_wb32(pb, 0); /* entry count */
5002
5003 ✗ while (t = av_dict_iterate(s->metadata, t)) {
5004 ✗ size_t key_len = strlen(t->key);
5005 ✗ avio_wb32(pb, key_len + 8);
5006 ✗ ffio_wfourcc(pb, "mdta");
5007 ✗ avio_write(pb, t->key, key_len);
5008 ✗ count += 1;
5009 }
5010 ✗ curpos = avio_tell(pb);
5011 ✗ avio_seek(pb, entry_pos, SEEK_SET);
5012 ✗ avio_wb32(pb, count); // rewrite entry count
5013 ✗ avio_seek(pb, curpos, SEEK_SET);
5014
5015 ✗ return update_size(pb, pos);
5016 }
5017
5018 ✗ static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
5019 AVFormatContext *s)
5020 {
5021 ✗ const AVDictionaryEntry *t = NULL;
5022 ✗ int64_t pos = avio_tell(pb);
5023 ✗ int count = 1; /* keys are 1-index based */
5024
5025 ✗ avio_wb32(pb, 0); /* size */
5026 ✗ ffio_wfourcc(pb, "ilst");
5027
5028 ✗ while (t = av_dict_iterate(s->metadata, t)) {
5029 ✗ int64_t entry_pos = avio_tell(pb);
5030 ✗ avio_wb32(pb, 0); /* size */
5031 ✗ avio_wb32(pb, count); /* key */
5032 ✗ mov_write_string_data_tag(pb, t->value, 0, 1);
5033 ✗ update_size(pb, entry_pos);
5034 ✗ count += 1;
5035 }
5036 ✗ return update_size(pb, pos);
5037 }
5038
5039 /* meta data tags */
5040 121 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
5041 AVFormatContext *s)
5042 {
5043 121 int size = 0;
5044 121 int64_t pos = avio_tell(pb);
5045 121 avio_wb32(pb, 0); /* size */
5046 121 ffio_wfourcc(pb, "meta");
5047 121 avio_wb32(pb, 0);
5048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
5049 ✗ mov_write_mdta_hdlr_tag(pb, mov, s);
5050 ✗ mov_write_mdta_keys_tag(pb, mov, s);
5051 ✗ mov_write_mdta_ilst_tag(pb, mov, s);
5052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 } else if (mov->mode == MODE_AVIF) {
5053 ✗ mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
5054 // We always write the primary item id as 1 since only one track is
5055 // supported for AVIF.
5056 ✗ mov_write_pitm_tag(pb, 1);
5057 ✗ mov_write_iloc_tag(pb, mov, s);
5058 ✗ mov_write_iinf_tag(pb, mov, s);
5059 ✗ if (mov->nb_streams > 1)
5060 ✗ mov_write_iref_tag(pb, mov, s);
5061 ✗ mov_write_iprp_tag(pb, mov, s);
5062 } else {
5063 /* iTunes metadata tag */
5064 121 mov_write_itunes_hdlr_tag(pb, mov, s);
5065 121 mov_write_ilst_tag(pb, mov, s);
5066 }
5067 121 size = update_size(pb, pos);
5068 121 return size;
5069 }
5070
5071 159 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
5072 const char *name, const char *key)
5073 {
5074 int len;
5075 AVDictionaryEntry *t;
5076
5077
1/2
✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
159 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
5078 159 return 0;
5079
5080 ✗ len = strlen(t->value);
5081 ✗ if (len > 0) {
5082 ✗ int size = len + 8;
5083 ✗ avio_wb32(pb, size);
5084 ✗ ffio_wfourcc(pb, name);
5085 ✗ avio_write(pb, t->value, len);
5086 ✗ return size;
5087 }
5088 ✗ return 0;
5089 }
5090
5091 ✗ static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
5092 {
5093 int val;
5094 ✗ while (*b) {
5095 ✗ GET_UTF8(val, *b++, return -1;)
5096 ✗ avio_wb16(pb, val);
5097 }
5098 ✗ avio_wb16(pb, 0x00);
5099 ✗ return 0;
5100 }
5101
5102 ✗ static uint16_t language_code(const char *str)
5103 {
5104 ✗ return (((str[0] - 0x60) & 0x1F) << 10) +
5105 ✗ (((str[1] - 0x60) & 0x1F) << 5) +
5106 ✗ (( str[2] - 0x60) & 0x1F);
5107 }
5108
5109 ✗ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
5110 const char *tag, const char *str)
5111 {
5112 ✗ int64_t pos = avio_tell(pb);
5113 ✗ AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
5114 ✗ if (!t || !utf8len(t->value))
5115 ✗ return 0;
5116 ✗ avio_wb32(pb, 0); /* size */
5117 ✗ ffio_wfourcc(pb, tag); /* type */
5118 ✗ avio_wb32(pb, 0); /* version + flags */
5119 ✗ if (!strcmp(tag, "yrrc"))
5120 ✗ avio_wb16(pb, atoi(t->value));
5121 else {
5122 ✗ avio_wb16(pb, language_code("eng")); /* language */
5123 ✗ avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
5124 ✗ if (!strcmp(tag, "albm") &&
5125 ✗ (t = av_dict_get(s->metadata, "track", NULL, 0)))
5126 ✗ avio_w8(pb, atoi(t->value));
5127 }
5128 ✗ return update_size(pb, pos);
5129 }
5130
5131 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
5132 {
5133 1 int64_t pos = avio_tell(pb);
5134 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
5135
5136 1 avio_wb32(pb, 0); // size
5137 1 ffio_wfourcc(pb, "chpl");
5138 1 avio_wb32(pb, 0x01000000); // version + flags
5139 1 avio_wb32(pb, 0); // unknown
5140 1 avio_w8(pb, nb_chapters);
5141
5142
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
5143 4 AVChapter *c = s->chapters[i];
5144 AVDictionaryEntry *t;
5145 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
5146
5147
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
5148
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
5149 4 avio_w8(pb, len);
5150 4 avio_write(pb, t->value, len);
5151 } else
5152 ✗ avio_w8(pb, 0);
5153 }
5154 1 return update_size(pb, pos);
5155 }
5156
5157 280 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
5158 AVFormatContext *s)
5159 {
5160 AVIOContext *pb_buf;
5161 int ret, size;
5162 uint8_t *buf;
5163
5164 280 ret = avio_open_dyn_buf(&pb_buf);
5165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 if (ret < 0)
5166 ✗ return ret;
5167
5168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 if (mov->mode & MODE_3GP) {
5169 ✗ mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
5170 ✗ mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
5171 ✗ mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
5172 ✗ mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
5173 ✗ mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
5174 ✗ mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
5175 ✗ mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
5176 ✗ mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
5177 ✗ mov_write_loci_tag(s, pb_buf);
5178
3/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
280 } 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
5179 159 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
5180 159 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
5181 159 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
5182 159 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
5183 159 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
5184 159 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
5185 // currently ignored by mov.c
5186 159 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
5187 // add support for libquicktime, this atom is also actually read by mov.c
5188 159 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
5189 159 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
5190 159 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
5191 159 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
5192 159 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
5193 159 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
5194 159 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
5195 159 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
5196 } else {
5197 /* iTunes meta data */
5198 121 mov_write_meta_tag(pb_buf, mov, s);
5199 121 mov_write_loci_tag(s, pb_buf);
5200 }
5201
5202
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
280 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
5203 1 mov_write_chpl_tag(pb_buf, s);
5204
5205
2/2
✓ Branch 1 taken 149 times.
✓ Branch 2 taken 131 times.
280 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
5206 149 avio_wb32(pb, size + 8);
5207 149 ffio_wfourcc(pb, "udta");
5208 149 avio_write(pb, buf, size);
5209 }
5210 280 ffio_free_dyn_buf(&pb_buf);
5211
5212 280 return 0;
5213 }
5214
5215 ✗ static void mov_write_psp_udta_tag(AVIOContext *pb,
5216 const char *str, const char *lang, int type)
5217 {
5218 ✗ int len = utf8len(str) + 1;
5219 ✗ if (len <= 0)
5220 ✗ return;
5221 ✗ avio_wb16(pb, len * 2 + 10); /* size */
5222 ✗ avio_wb32(pb, type); /* type */
5223 ✗ avio_wb16(pb, language_code(lang)); /* language */
5224 ✗ avio_wb16(pb, 0x01); /* ? */
5225 ✗ ascii_to_wc(pb, str);
5226 }
5227
5228 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5229 {
5230 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5231 int64_t pos, pos2;
5232
5233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5234 ✗ pos = avio_tell(pb);
5235 ✗ avio_wb32(pb, 0); /* size placeholder*/
5236 ✗ ffio_wfourcc(pb, "uuid");
5237 ✗ ffio_wfourcc(pb, "USMT");
5238 ✗ avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5239 ✗ avio_wb32(pb, 0xbb88695c);
5240 ✗ avio_wb32(pb, 0xfac9c740);
5241
5242 ✗ pos2 = avio_tell(pb);
5243 ✗ avio_wb32(pb, 0); /* size placeholder*/
5244 ✗ ffio_wfourcc(pb, "MTDT");
5245 ✗ avio_wb16(pb, 4);
5246
5247 // ?
5248 ✗ avio_wb16(pb, 0x0C); /* size */
5249 ✗ avio_wb32(pb, 0x0B); /* type */
5250 ✗ avio_wb16(pb, language_code("und")); /* language */
5251 ✗ avio_wb16(pb, 0x0); /* ? */
5252 ✗ avio_wb16(pb, 0x021C); /* data */
5253
5254 ✗ if (!(s->flags & AVFMT_FLAG_BITEXACT))
5255 ✗ mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5256 ✗ mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5257 ✗ mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5258
5259 ✗ update_size(pb, pos2);
5260 ✗ return update_size(pb, pos);
5261 }
5262
5263 1 return 0;
5264 }
5265
5266 372 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5267 {
5268 AVEncryptionInitInfo *info;
5269 372 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5270 372 st->codecpar->nb_coded_side_data,
5271 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5272
1/2
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
372 if (!sd)
5273 372 return 0;
5274
5275 ✗ info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5276 ✗ for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5277 int64_t pos;
5278
5279 ✗ if (!copy->data_size && !copy->num_key_ids)
5280 ✗ continue;
5281
5282 ✗ pos = avio_tell(pb);
5283 ✗ avio_wb32(pb, 0); /* size placeholder */
5284 ✗ ffio_wfourcc(pb, "pssh");
5285 ✗ avio_w8(pb, 1); /* version */
5286 ✗ avio_wb24(pb, 0);
5287 ✗ for (int i = 0; i < copy->system_id_size; i++)
5288 ✗ avio_w8(pb, copy->system_id[i]);
5289 ✗ avio_wb32(pb, copy->num_key_ids);
5290 ✗ for (int i = 0; i < copy->num_key_ids; i++)
5291 ✗ for (int j = 0; j < copy->key_id_size; j++)
5292 ✗ avio_w8(pb, copy->key_ids[i][j]);
5293 ✗ avio_wb32(pb, copy->data_size);
5294 ✗ avio_write(pb, copy->data, copy->data_size);
5295 ✗ update_size(pb, pos);
5296 }
5297
5298 ✗ av_encryption_init_info_free(info);
5299
5300 ✗ return 0;
5301 }
5302
5303 346 static void build_chunks(MOVTrack *trk)
5304 {
5305 int i;
5306 346 MOVIentry *chunk = &trk->cluster[0];
5307 346 uint64_t chunkSize = chunk->size;
5308 346 chunk->chunkNum = 1;
5309
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 288 times.
346 if (trk->chunkCount)
5310 58 return;
5311 288 trk->chunkCount = 1;
5312
2/2
✓ Branch 0 taken 18507 times.
✓ Branch 1 taken 288 times.
18795 for (i = 1; i<trk->entry; i++){
5313
2/2
✓ Branch 0 taken 16768 times.
✓ Branch 1 taken 1739 times.
18507 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5314
2/2
✓ Branch 0 taken 16766 times.
✓ Branch 1 taken 2 times.
16768 chunk->stsd_index == trk->cluster[i].stsd_index &&
5315
2/2
✓ Branch 0 taken 16121 times.
✓ Branch 1 taken 645 times.
16766 chunkSize + trk->cluster[i].size < (1<<20)){
5316 16121 chunkSize += trk->cluster[i].size;
5317 16121 chunk->samples_in_chunk += trk->cluster[i].entries;
5318 } else {
5319 2386 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5320 2386 chunk=&trk->cluster[i];
5321 2386 chunkSize = chunk->size;
5322 2386 trk->chunkCount++;
5323 }
5324 }
5325 }
5326
5327 /**
5328 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5329 * the stream ids are used as track ids.
5330 *
5331 * This assumes mov->tracks and s->streams are in the same order and
5332 * there are no gaps in either of them (so mov->tracks[n] refers to
5333 * s->streams[n]).
5334 *
5335 * As an exception, there can be more entries in
5336 * s->streams than in mov->tracks, in which case new track ids are
5337 * generated (starting after the largest found stream id).
5338 */
5339 281 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5340 {
5341 int i;
5342
5343
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 248 times.
281 if (mov->track_ids_ok)
5344 33 return 0;
5345
5346
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->use_stream_ids_as_track_ids) {
5347 1 int next_generated_track_id = 0;
5348
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5349 2 AVStream *st = mov->tracks[i].st;
5350
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5351 2 next_generated_track_id = st->id;
5352 }
5353
5354
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5355
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))
5356 ✗ continue;
5357
5358
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;
5359 }
5360 } else {
5361 247 int last_track_id = 0;
5362
2/2
✓ Branch 0 taken 317 times.
✓ Branch 1 taken 247 times.
564 for (i = 0; i < mov->nb_tracks; i++) {
5363
4/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 282 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 33 times.
317 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5364 2 continue;
5365
5366 315 last_track_id =
5367 315 mov->tracks[i].track_id = (mov->tracks[i].st
5368 312 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5369
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 3 times.
315 : FFMAX(i, last_track_id)) + 1;
5370 }
5371 }
5372
5373 248 mov->track_ids_ok = 1;
5374
5375 248 return 0;
5376 }
5377
5378 16 static int mov_find_tref_id(MOVMuxContext *mov, const MovTag *tag, uint32_t id)
5379 {
5380
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12 times.
19 for (int i = 0; i < tag->nb_id; i++) {
5381
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (tag->id[i] == id)
5382 4 return 1;
5383 }
5384 12 return 0;
5385 }
5386
5387 16 static int mov_add_tref_id(MOVMuxContext *mov, MovTag *tag, uint32_t id)
5388 {
5389 16 int ret = mov_find_tref_id(mov, tag, id);
5390
5391
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 if (!ret) {
5392 12 uint32_t *tmp = av_realloc_array(tag->id, tag->nb_id + 1, sizeof(*tag->id));
5393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!tmp)
5394 ✗ return AVERROR(ENOMEM);
5395 12 tag->id = tmp;
5396 12 tag->id[tag->nb_id++] = id;
5397 }
5398
5399 16 return 0;
5400 }
5401
5402 16 static MovTag *mov_find_tref_tag(MOVMuxContext *mov, const MOVTrack *trk, uint32_t name)
5403 {
5404
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 for (int i = 0; i < trk->nb_tref_tags; i++) {
5405 6 MovTag *entry = &trk->tref_tags[i];
5406
5407
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (entry->name == name)
5408 6 return entry;
5409 }
5410 10 return NULL;
5411 }
5412
5413 16 static MovTag *mov_add_tref_tag(MOVMuxContext *mov, MOVTrack *trk, uint32_t name)
5414 {
5415 16 MovTag *tag = mov_find_tref_tag(mov, trk, name);
5416
5417
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if (!tag) {
5418 10 MovTag *tmp = av_realloc_array(trk->tref_tags, trk->nb_tref_tags + 1,
5419 sizeof(*trk->tref_tags));
5420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!tmp)
5421 ✗ return NULL;
5422 10 trk->tref_tags = tmp;
5423 10 tag = &trk->tref_tags[trk->nb_tref_tags++];
5424 10 *tag = (MovTag){ .name = name };
5425 }
5426
5427 16 return tag;
5428 }
5429
5430 281 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5431 AVFormatContext *s)
5432 {
5433 int i;
5434 281 int64_t pos = avio_tell(pb);
5435 281 avio_wb32(pb, 0); /* size placeholder*/
5436 281 ffio_wfourcc(pb, "moov");
5437
5438 281 mov_setup_track_ids(mov, s);
5439
5440
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 281 times.
666 for (i = 0; i < mov->nb_tracks; i++) {
5441
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 346 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 37 times.
385 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5442 2 continue;
5443
5444 383 mov->tracks[i].time = mov->time;
5445
5446
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 37 times.
383 if (mov->tracks[i].entry)
5447 346 build_chunks(&mov->tracks[i]);
5448 }
5449
5450
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 280 times.
281 if (mov->chapter_track)
5451
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5452 1 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[i], MKTAG('c','h','a','p'));
5453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
5454 ✗ return AVERROR(ENOMEM);
5455
5456 1 int ret = mov_add_tref_id(mov, tag, mov->tracks[mov->chapter_track].track_id);
5457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
5458 ✗ return ret;
5459 }
5460
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 281 times.
666 for (i = 0; i < mov->nb_tracks; i++) {
5461 385 MOVTrack *track = &mov->tracks[i];
5462
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 383 times.
385 if (track->tag == MKTAG('r','t','p',' ')) {
5463 2 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('h','i','n','t'));
5464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
5465 ✗ return AVERROR(ENOMEM);
5466
5467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
5468 2 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
5470 ✗ return ret;
5471
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
383 } else if (track->tag == MKTAG('l','v','c','1') && track->nb_src_track) {
5472 ✗ MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('s','b','a','s'));
5473 ✗ if (!tag)
5474 ✗ return AVERROR(ENOMEM);
5475
5476 ✗ int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5477 ✗ if (ret < 0)
5478 ✗ return ret;
5479 } else {
5480
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 254 times.
383 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5481 129 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5482 129 track->st->codecpar->nb_coded_side_data,
5483 AV_PKT_DATA_FALLBACK_TRACK );
5484
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
129 if (sd && sd->size == sizeof(int)) {
5485 ✗ int *fallback = (int *)sd->data;
5486 ✗ if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5487 ✗ MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('f','a','l','l'));
5488 ✗ if (!tag)
5489 ✗ return AVERROR(ENOMEM);
5490
5491 ✗ int ret = mov_add_tref_id(mov, tag, mov->tracks[*fallback].track_id);
5492 ✗ if (ret < 0)
5493 ✗ return ret;
5494 }
5495 }
5496 }
5497
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 383 times.
396 for (int j = 0; j < track->nb_src_track; j++) {
5498 13 int src_trk = track->src_track[j];
5499 13 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[src_trk], track->tag);
5500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tag)
5501 ✗ return AVERROR(ENOMEM);
5502 13 int ret = mov_add_tref_id(mov, tag, track->track_id);
5503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (ret < 0)
5504 ✗ return ret;
5505 }
5506
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 357 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
383 if (mov->nb_meta_tmcd && track->nb_src_track) {
5507 /* Derive the duration from the first source track, matching
5508 * the convention used by get_pts_range() and the rtp/lvc1
5509 * branches above. The source may use a different timescale. */
5510 10 int src_trk = track->src_track[0];
5511 10 track->track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5512 10 track->timescale,
5513 10 mov->tracks[src_trk].timescale);
5514 }
5515 }
5516 }
5517
5518 281 mov_write_mvhd_tag(pb, mov);
5519
4/6
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 122 times.
281 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5520 ✗ mov_write_iods_tag(pb, mov);
5521
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 281 times.
666 for (i = 0; i < mov->nb_tracks; i++) {
5522
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 346 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 37 times.
385 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5524
2/2
✓ Branch 0 taken 370 times.
✓ Branch 1 taken 13 times.
383 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
383 if (ret < 0)
5526 ✗ return ret;
5527 }
5528 }
5529 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5530 * (mov->moov_written != 0)
5531 */
5532
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 212 times.
281 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5533
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
69 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
5534 67 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5535
5536
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 280 times.
281 if (mov->mode == MODE_PSP)
5537 1 mov_write_uuidusmt_tag(pb, s);
5538
1/2
✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
280 else if (mov->mode != MODE_AVIF)
5539 280 mov_write_udta_tag(pb, mov, s);
5540
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 281 times.
653 for (i = 0; i < mov->nb_streams; i++)
5541 372 mov_write_pssh_tag(pb, mov->tracks[i].st);
5542
5543 281 return update_size(pb, pos);
5544 }
5545
5546 ✗ static void param_write_int(AVIOContext *pb, const char *name, int value)
5547 {
5548 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5549 ✗ }
5550
5551 ✗ static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5552 {
5553 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5554 ✗ }
5555
5556 ✗ static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5557 {
5558 char buf[150];
5559 ✗ len = FFMIN(sizeof(buf) / 2 - 1, len);
5560 ✗ ff_data_to_hex(buf, value, len, 0);
5561 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5562 ✗ }
5563
5564 ✗ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5565 {
5566 ✗ int64_t pos = avio_tell(pb);
5567 int i;
5568
5569 static const AVUUID uuid = {
5570 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5571 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5572 };
5573
5574 ✗ avio_wb32(pb, 0);
5575 ✗ ffio_wfourcc(pb, "uuid");
5576 ✗ avio_write(pb, uuid, AV_UUID_LEN);
5577 ✗ avio_wb32(pb, 0);
5578
5579 ✗ avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5580 ✗ avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5581 ✗ avio_printf(pb, "<head>\n");
5582 ✗ if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5583 ✗ avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5584 LIBAVFORMAT_IDENT);
5585 ✗ avio_printf(pb, "</head>\n");
5586 ✗ avio_printf(pb, "<body>\n");
5587 ✗ avio_printf(pb, "<switch>\n");
5588
5589 ✗ mov_setup_track_ids(mov, s);
5590
5591 ✗ for (i = 0; i < mov->nb_tracks; i++) {
5592 ✗ MOVTrack *track = &mov->tracks[i];
5593 struct mpeg4_bit_rate_values bit_rates =
5594 ✗ calculate_mpeg4_bit_rates(track);
5595 const char *type;
5596 ✗ int track_id = track->track_id;
5597 ✗ char track_name_buf[32] = { 0 };
5598
5599 ✗ AVStream *st = track->st;
5600 ✗ AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5601
5602 ✗ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5603 ✗ type = "video";
5604 ✗ } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5605 ✗ type = "audio";
5606 } else {
5607 ✗ continue;
5608 }
5609
5610 ✗ avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5611 bit_rates.avg_bit_rate);
5612 ✗ param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5613 ✗ param_write_int(pb, "trackID", track_id);
5614 ✗ param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5615
5616 /* Build track name piece by piece: */
5617 /* 1. track type */
5618 ✗ av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5619 /* 2. track language, if available */
5620 ✗ if (lang)
5621 ✗ av_strlcatf(track_name_buf, sizeof(track_name_buf),
5622 "_%s", lang->value);
5623 /* 3. special type suffix */
5624 /* "_cc" = closed captions, "_ad" = audio_description */
5625 ✗ if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5626 ✗ av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5627 ✗ else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5628 ✗ av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5629
5630 ✗ param_write_string(pb, "trackName", track_name_buf);
5631
5632 ✗ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5633 ✗ if (track->par->codec_id == AV_CODEC_ID_H264) {
5634 uint8_t *ptr;
5635 ✗ int size = track->extradata_size[track->last_stsd_index];
5636 ✗ if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5637 &size)) {
5638 ✗ param_write_hex(pb, "CodecPrivateData",
5639 ✗ ptr ? ptr : track->extradata[track->last_stsd_index],
5640 size);
5641 ✗ av_free(ptr);
5642 }
5643 ✗ param_write_string(pb, "FourCC", "H264");
5644 ✗ } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5645 ✗ param_write_string(pb, "FourCC", "WVC1");
5646 ✗ param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5647 ✗ track->extradata_size[track->last_stsd_index]);
5648 }
5649 ✗ param_write_int(pb, "MaxWidth", track->par->width);
5650 ✗ param_write_int(pb, "MaxHeight", track->par->height);
5651 ✗ param_write_int(pb, "DisplayWidth", track->par->width);
5652 ✗ param_write_int(pb, "DisplayHeight", track->par->height);
5653 } else {
5654 ✗ if (track->par->codec_id == AV_CODEC_ID_AAC) {
5655 ✗ switch (track->par->profile) {
5656 ✗ case AV_PROFILE_AAC_HE_V2:
5657 ✗ param_write_string(pb, "FourCC", "AACP");
5658 ✗ break;
5659 ✗ case AV_PROFILE_AAC_HE:
5660 ✗ param_write_string(pb, "FourCC", "AACH");
5661 ✗ break;
5662 ✗ default:
5663 ✗ param_write_string(pb, "FourCC", "AACL");
5664 }
5665 ✗ } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5666 ✗ param_write_string(pb, "FourCC", "WMAP");
5667 }
5668 ✗ param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5669 ✗ track->extradata_size[track->last_stsd_index]);
5670 ✗ param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5671 ✗ track->par->codec_id));
5672 ✗ param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5673 ✗ param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5674 ✗ 0 : track->par->sample_rate);
5675 ✗ param_write_int(pb, "BitsPerSample", 16);
5676 ✗ param_write_int(pb, "PacketSize", track->par->block_align ?
5677 ✗ track->par->block_align : 4);
5678 }
5679 ✗ avio_printf(pb, "</%s>\n", type);
5680 }
5681 ✗ avio_printf(pb, "</switch>\n");
5682 ✗ avio_printf(pb, "</body>\n");
5683 ✗ avio_printf(pb, "</smil>\n");
5684
5685 ✗ return update_size(pb, pos);
5686 }
5687
5688 238 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5689 {
5690 238 avio_wb32(pb, 16);
5691 238 ffio_wfourcc(pb, "mfhd");
5692 238 avio_wb32(pb, 0);
5693 238 avio_wb32(pb, mov->fragments);
5694 238 return 0;
5695 }
5696
5697 13566 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5698 {
5699
2/2
✓ Branch 0 taken 7652 times.
✓ Branch 1 taken 5914 times.
13566 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5700 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5701 }
5702
5703 358 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5704 MOVTrack *track, int64_t moof_offset)
5705 {
5706 358 int64_t pos = avio_tell(pb);
5707 358 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5708 MOV_TFHD_BASE_DATA_OFFSET;
5709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 if (!track->entry) {
5710 ✗ flags |= MOV_TFHD_DURATION_IS_EMPTY;
5711 } else {
5712 358 flags |= MOV_TFHD_DEFAULT_FLAGS;
5713 }
5714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5715 ✗ flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5716
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 214 times.
358 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5717 144 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5718 144 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5719 }
5720 /* CMAF requires all values to be explicit in tfhd atoms */
5721
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 298 times.
358 if (mov->flags & FF_MOV_FLAG_CMAF)
5722 60 flags |= MOV_TFHD_STSD_ID;
5723
5724 /* Don't set a default sample size, the silverlight player refuses
5725 * to play files with that set. Don't set a default sample duration,
5726 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5727 * file format says it MUST NOT be set. */
5728
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 276 times.
358 if (track->mode == MODE_ISM)
5729 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5730 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5731
5732 358 avio_wb32(pb, 0); /* size placeholder */
5733 358 ffio_wfourcc(pb, "tfhd");
5734 358 avio_w8(pb, 0); /* version */
5735 358 avio_wb24(pb, flags);
5736
5737 358 avio_wb32(pb, track->track_id); /* track-id */
5738
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 226 times.
358 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5739 132 avio_wb64(pb, moof_offset);
5740
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 298 times.
358 if (flags & MOV_TFHD_STSD_ID) {
5741 60 avio_wb32(pb, 1);
5742 }
5743
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5744 276 track->default_duration = get_cluster_duration(track, 0);
5745 276 avio_wb32(pb, track->default_duration);
5746 }
5747
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5748
1/2
✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
276 track->default_size = track->entry ? track->cluster[0].size : 1;
5749 276 avio_wb32(pb, track->default_size);
5750 } else
5751 82 track->default_size = -1;
5752
5753
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5754 /* Set the default flags based on the second sample, if available.
5755 * If the first sample is different, that can be signaled via a separate field. */
5756
2/2
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 72 times.
358 if (track->entry > 1)
5757 286 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5758 else
5759 72 track->default_sample_flags =
5760 72 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5761
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 56 times.
72 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5762 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5763 358 avio_wb32(pb, track->default_sample_flags);
5764 }
5765
5766 358 return update_size(pb, pos);
5767 }
5768
5769 360 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5770 MOVTrack *track, int moof_size,
5771 int first, int end)
5772 {
5773 360 int64_t pos = avio_tell(pb);
5774 360 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5775 int i;
5776
5777
2/2
✓ Branch 0 taken 12740 times.
✓ Branch 1 taken 360 times.
13100 for (i = first; i < end; i++) {
5778
2/2
✓ Branch 1 taken 1838 times.
✓ Branch 2 taken 10902 times.
12740 if (get_cluster_duration(track, i) != track->default_duration)
5779 1838 flags |= MOV_TRUN_SAMPLE_DURATION;
5780
2/2
✓ Branch 0 taken 2956 times.
✓ Branch 1 taken 9784 times.
12740 if (track->cluster[i].size != track->default_size)
5781 2956 flags |= MOV_TRUN_SAMPLE_SIZE;
5782
4/4
✓ Branch 0 taken 12380 times.
✓ Branch 1 taken 360 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 12370 times.
12740 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5783 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5784 }
5785
3/4
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
360 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5786
2/2
✓ Branch 1 taken 176 times.
✓ Branch 2 taken 176 times.
352 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5787 176 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5788
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 260 times.
360 if (track->flags & MOV_TRACK_CTTS)
5789 100 flags |= MOV_TRUN_SAMPLE_CTS;
5790
5791 360 avio_wb32(pb, 0); /* size placeholder */
5792 360 ffio_wfourcc(pb, "trun");
5793
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 202 times.
360 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5794 158 avio_w8(pb, 1); /* version */
5795 else
5796 202 avio_w8(pb, 0); /* version */
5797 360 avio_wb24(pb, flags);
5798
5799 360 avio_wb32(pb, end - first); /* sample count */
5800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5801 ✗ !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5802 ✗ !mov->first_trun)
5803 ✗ avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5804 else
5805 360 avio_wb32(pb, moof_size + 8 + track->data_offset +
5806 360 track->cluster[first].pos); /* data offset */
5807
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 184 times.
360 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5808 176 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5809
5810
2/2
✓ Branch 0 taken 12740 times.
✓ Branch 1 taken 360 times.
13100 for (i = first; i < end; i++) {
5811
2/2
✓ Branch 0 taken 2030 times.
✓ Branch 1 taken 10710 times.
12740 if (flags & MOV_TRUN_SAMPLE_DURATION)
5812 2030 avio_wb32(pb, get_cluster_duration(track, i));
5813
2/2
✓ Branch 0 taken 3636 times.
✓ Branch 1 taken 9104 times.
12740 if (flags & MOV_TRUN_SAMPLE_SIZE)
5814 3636 avio_wb32(pb, track->cluster[i].size);
5815
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 12368 times.
12740 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5816 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5817
2/2
✓ Branch 0 taken 3162 times.
✓ Branch 1 taken 9578 times.
12740 if (flags & MOV_TRUN_SAMPLE_CTS)
5818 3162 avio_wb32(pb, track->cluster[i].cts);
5819 }
5820
5821 360 mov->first_trun = 0;
5822 360 return update_size(pb, pos);
5823 }
5824
5825 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5826 {
5827 82 int64_t pos = avio_tell(pb);
5828 static const uint8_t uuid[] = {
5829 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5830 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5831 };
5832
5833 82 avio_wb32(pb, 0); /* size placeholder */
5834 82 ffio_wfourcc(pb, "uuid");
5835 82 avio_write(pb, uuid, AV_UUID_LEN);
5836 82 avio_w8(pb, 1);
5837 82 avio_wb24(pb, 0);
5838 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5839 82 avio_wb64(pb, track->end_pts -
5840 82 (track->cluster[0].dts + track->cluster[0].cts));
5841
5842 82 return update_size(pb, pos);
5843 }
5844
5845 ✗ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5846 MOVTrack *track, int entry)
5847 {
5848 ✗ int n = track->nb_frag_info - 1 - entry, i;
5849 ✗ int size = 8 + 16 + 4 + 1 + 16*n;
5850 static const uint8_t uuid[] = {
5851 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5852 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5853 };
5854
5855 ✗ if (entry < 0)
5856 ✗ return 0;
5857
5858 ✗ avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5859 ✗ avio_wb32(pb, size);
5860 ✗ ffio_wfourcc(pb, "uuid");
5861 ✗ avio_write(pb, uuid, AV_UUID_LEN);
5862 ✗ avio_w8(pb, 1);
5863 ✗ avio_wb24(pb, 0);
5864 ✗ avio_w8(pb, n);
5865 ✗ for (i = 0; i < n; i++) {
5866 ✗ int index = entry + 1 + i;
5867 ✗ avio_wb64(pb, track->frag_info[index].time);
5868 ✗ avio_wb64(pb, track->frag_info[index].duration);
5869 }
5870 ✗ if (n < mov->ism_lookahead) {
5871 ✗ int free_size = 16 * (mov->ism_lookahead - n);
5872 ✗ avio_wb32(pb, free_size);
5873 ✗ ffio_wfourcc(pb, "free");
5874 ✗ ffio_fill(pb, 0, free_size - 8);
5875 }
5876
5877 ✗ return 0;
5878 }
5879
5880 178 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5881 MOVTrack *track)
5882 {
5883 178 int64_t pos = avio_tell(pb);
5884 int i;
5885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 178 times.
178 for (i = 0; i < mov->ism_lookahead; i++) {
5886 /* Update the tfrf tag for the last ism_lookahead fragments,
5887 * nb_frag_info - 1 is the next fragment to be written. */
5888 ✗ mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5889 }
5890 178 avio_seek(pb, pos, SEEK_SET);
5891 178 return 0;
5892 }
5893
5894 118 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5895 int size)
5896 {
5897 int i;
5898
2/2
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 118 times.
339 for (i = 0; i < mov->nb_tracks; i++) {
5899 221 MOVTrack *track = &mov->tracks[i];
5900 MOVFragmentInfo *info;
5901
6/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 178 times.
221 if ((tracks >= 0 && i != tracks) || !track->entry)
5902 43 continue;
5903 178 track->nb_frag_info++;
5904
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 106 times.
178 if (track->nb_frag_info >= track->frag_info_capacity) {
5905 72 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5906
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (av_reallocp_array(&track->frag_info,
5907 new_capacity,
5908 sizeof(*track->frag_info)))
5909 ✗ return AVERROR(ENOMEM);
5910 72 track->frag_info_capacity = new_capacity;
5911 }
5912 178 info = &track->frag_info[track->nb_frag_info - 1];
5913 178 info->offset = avio_tell(pb);
5914 178 info->size = size;
5915 // Try to recreate the original pts for the first packet
5916 // from the fields we have stored
5917 178 info->time = track->cluster[0].dts + track->cluster[0].cts;
5918 178 info->duration = track->end_pts -
5919 178 (track->cluster[0].dts + track->cluster[0].cts);
5920 // If the pts is less than zero, we will have trimmed
5921 // away parts of the media track using an edit list,
5922 // and the corresponding start presentation time is zero.
5923
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 170 times.
178 if (info->time < 0) {
5924 8 info->duration += info->time;
5925 8 info->time = 0;
5926 }
5927 178 info->tfrf_offset = 0;
5928 178 mov_write_tfrf_tags(pb, mov, track);
5929 }
5930 118 return 0;
5931 }
5932
5933 ✗ static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5934 {
5935 int i;
5936 ✗ for (i = 0; i < mov->nb_tracks; i++) {
5937 ✗ MOVTrack *track = &mov->tracks[i];
5938 ✗ if ((tracks >= 0 && i != tracks) || !track->entry)
5939 ✗ continue;
5940 ✗ if (track->nb_frag_info > max) {
5941 ✗ memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5942 ✗ track->nb_frag_info = max;
5943 }
5944 }
5945 ✗ }
5946
5947 276 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5948 {
5949 276 int64_t pos = avio_tell(pb);
5950
5951 276 avio_wb32(pb, 0); /* size */
5952 276 ffio_wfourcc(pb, "tfdt");
5953 276 avio_w8(pb, 1); /* version */
5954 276 avio_wb24(pb, 0);
5955 276 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5956 276 return update_size(pb, pos);
5957 }
5958
5959 358 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5960 MOVTrack *track, int64_t moof_offset,
5961 int moof_size)
5962 {
5963 358 int64_t pos = avio_tell(pb);
5964 358 int i, start = 0;
5965 358 avio_wb32(pb, 0); /* size placeholder */
5966 358 ffio_wfourcc(pb, "traf");
5967
5968 358 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5969
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (mov->mode != MODE_ISM)
5970 276 mov_write_tfdt_tag(pb, track);
5971
2/2
✓ Branch 0 taken 12382 times.
✓ Branch 1 taken 358 times.
12740 for (i = 1; i < track->entry; i++) {
5972
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12380 times.
12382 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5973 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5974 2 start = i;
5975 }
5976 }
5977 358 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5978
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 276 times.
358 if (mov->mode == MODE_ISM) {
5979 82 mov_write_tfxd_tag(pb, track);
5980
5981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5982 ✗ int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5983
5984 ✗ if (track->nb_frag_info > 0) {
5985 ✗ MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5986 ✗ if (!info->tfrf_offset)
5987 ✗ info->tfrf_offset = avio_tell(pb);
5988 }
5989 ✗ avio_wb32(pb, 8 + size);
5990 ✗ ffio_wfourcc(pb, "free");
5991 ✗ ffio_fill(pb, 0, size);
5992 }
5993 }
5994
5995
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
358 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5996 ✗ ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5997
5998 358 return update_size(pb, pos);
5999 }
6000
6001 238 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
6002 int tracks, int moof_size)
6003 {
6004 238 int64_t pos = avio_tell(pb);
6005 int i;
6006
6007 238 avio_wb32(pb, 0); /* size placeholder */
6008 238 ffio_wfourcc(pb, "moof");
6009 238 mov->first_trun = 1;
6010
6011 238 mov_write_mfhd_tag(pb, mov);
6012
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 238 times.
682 for (i = 0; i < mov->nb_tracks; i++) {
6013 444 MOVTrack *track = &mov->tracks[i];
6014
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 286 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 82 times.
444 if (tracks >= 0 && i != tracks)
6015 76 continue;
6016
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 358 times.
368 if (!track->entry)
6017 10 continue;
6018
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
358 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
6019 ✗ mov_write_pssh_tag(pb, track->st);
6020 358 mov_write_traf_tag(pb, mov, track, pos, moof_size);
6021 }
6022
6023 238 return update_size(pb, pos);
6024 }
6025
6026 78 static int mov_write_sidx_tag(AVIOContext *pb,
6027 MOVTrack *track, int ref_size, int total_sidx_size)
6028 {
6029 78 int64_t pos = avio_tell(pb), offset_pos, end_pos;
6030 int64_t presentation_time, duration, offset;
6031 unsigned starts_with_SAP;
6032 int i, entries;
6033
6034
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 if (track->entry) {
6035 78 entries = 1;
6036 78 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
6037 78 duration = track->end_pts -
6038 78 (track->cluster[0].dts + track->cluster[0].cts);
6039 78 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6040
6041 // pts<0 should be cut away using edts
6042
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 72 times.
78 if (presentation_time < 0) {
6043 6 duration += presentation_time;
6044 6 presentation_time = 0;
6045 }
6046 } else {
6047 ✗ entries = track->nb_frag_info;
6048 ✗ if (entries <= 0)
6049 ✗ return 0;
6050 ✗ presentation_time = track->frag_info[0].time;
6051 }
6052
6053 78 avio_wb32(pb, 0); /* size */
6054 78 ffio_wfourcc(pb, "sidx");
6055 78 avio_w8(pb, 1); /* version */
6056 78 avio_wb24(pb, 0);
6057 78 avio_wb32(pb, track->track_id); /* reference_ID */
6058 78 avio_wb32(pb, track->timescale); /* timescale */
6059 78 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
6060 78 offset_pos = avio_tell(pb);
6061 78 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
6062 78 avio_wb16(pb, 0); /* reserved */
6063
6064 78 avio_wb16(pb, entries); /* reference_count */
6065
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 78 times.
156 for (i = 0; i < entries; i++) {
6066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (!track->entry) {
6067 ✗ if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
6068 ✗ av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
6069 }
6070 ✗ duration = track->frag_info[i].duration;
6071 ✗ ref_size = track->frag_info[i].size;
6072 ✗ starts_with_SAP = 1;
6073 }
6074 78 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
6075 78 avio_wb32(pb, duration); /* subsegment_duration */
6076 78 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
6077 }
6078
6079 78 end_pos = avio_tell(pb);
6080 78 offset = pos + total_sidx_size - end_pos;
6081 78 avio_seek(pb, offset_pos, SEEK_SET);
6082 78 avio_wb64(pb, offset);
6083 78 avio_seek(pb, end_pos, SEEK_SET);
6084 78 return update_size(pb, pos);
6085 }
6086
6087 24 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
6088 int tracks, int ref_size)
6089 {
6090 int i, round, ret;
6091 AVIOContext *avio_buf;
6092 24 int total_size = 0;
6093
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 for (round = 0; round < 2; round++) {
6094 // First run one round to calculate the total size of all
6095 // sidx atoms.
6096 // This would be much simpler if we'd only write one sidx
6097 // atom, for the first track in the moof.
6098
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (round == 0) {
6099
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6100 ✗ return ret;
6101 } else {
6102 24 avio_buf = pb;
6103 }
6104
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 48 times.
126 for (i = 0; i < mov->nb_tracks; i++) {
6105 78 MOVTrack *track = &mov->tracks[i];
6106
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78 if (tracks >= 0 && i != tracks)
6107 ✗ continue;
6108 // When writing a sidx for the full file, entry is 0, but
6109 // we want to include all tracks. ref_size is 0 in this case,
6110 // since we read it from frag_info instead.
6111
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78 if (!track->entry && ref_size > 0)
6112 ✗ continue;
6113 78 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
6114 total_size);
6115 }
6116
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (round == 0) {
6117 24 total_size = ffio_close_null_buf(avio_buf);
6118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (total_size < 0)
6119 ✗ return total_size;
6120 }
6121 }
6122 24 return 0;
6123 }
6124
6125 ✗ static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
6126 {
6127 ✗ int64_t pos = avio_tell(pb), pts_us, ntp_ts;
6128 MOVTrack *first_track;
6129 ✗ int flags = 24;
6130
6131 /* PRFT should be associated with at most one track. So, choosing only the
6132 * first track. */
6133 ✗ if (tracks > 0)
6134 ✗ return 0;
6135 ✗ first_track = &(mov->tracks[0]);
6136
6137 ✗ if (!first_track->entry) {
6138 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
6139 ✗ return 0;
6140 }
6141
6142 ✗ if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
6143 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
6144 ✗ return 0;
6145 }
6146
6147 ✗ if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
6148 ✗ if (first_track->cluster[0].prft.wallclock) {
6149 /* Round the NTP time to whole milliseconds. */
6150 ✗ ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
6151 NTP_OFFSET_US);
6152 ✗ flags = first_track->cluster[0].prft.flags;
6153 } else
6154 ✗ ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
6155 ✗ } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
6156 ✗ pts_us = av_rescale_q(first_track->cluster[0].pts,
6157 ✗ first_track->st->time_base, AV_TIME_BASE_Q);
6158 ✗ ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
6159 } else {
6160 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
6161 ✗ mov->write_prft);
6162 ✗ return 0;
6163 }
6164
6165 ✗ avio_wb32(pb, 0); // Size place holder
6166 ✗ ffio_wfourcc(pb, "prft"); // Type
6167 ✗ avio_w8(pb, 1); // Version
6168 ✗ avio_wb24(pb, flags); // Flags
6169 ✗ avio_wb32(pb, first_track->track_id); // reference track ID
6170 ✗ avio_wb64(pb, ntp_ts); // NTP time stamp
6171 ✗ avio_wb64(pb, first_track->cluster[0].pts); //media time
6172 ✗ return update_size(pb, pos);
6173 }
6174
6175 119 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
6176 int64_t mdat_size)
6177 {
6178 AVIOContext *avio_buf;
6179 int ret, moof_size;
6180
6181
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
119 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6182 ✗ return ret;
6183 119 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
6184 119 moof_size = ffio_close_null_buf(avio_buf);
6185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (moof_size < 0)
6186 ✗ return moof_size;
6187
6188
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 94 times.
119 if (mov->flags & FF_MOV_FLAG_DASH &&
6189
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
25 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
6190 24 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
6191
6192
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
119 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
6193 ✗ mov_write_prft_tag(pb, mov, tracks);
6194
6195
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
6196
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 118 times.
119 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
6197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->ism_lookahead) {
6198
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
118 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
6199 ✗ return ret;
6200
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
6201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
6202 ✗ mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
6203 }
6204 }
6205
6206 119 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
6207 }
6208
6209 68 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
6210 {
6211 68 int64_t pos = avio_tell(pb);
6212 int i;
6213
6214 68 avio_wb32(pb, 0); /* size placeholder */
6215 68 ffio_wfourcc(pb, "tfra");
6216 68 avio_w8(pb, 1); /* version */
6217 68 avio_wb24(pb, 0);
6218
6219 68 avio_wb32(pb, track->track_id);
6220 68 avio_wb32(pb, 0); /* length of traf/trun/sample num */
6221 68 avio_wb32(pb, track->nb_frag_info);
6222
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 68 times.
240 for (i = 0; i < track->nb_frag_info; i++) {
6223 172 avio_wb64(pb, track->frag_info[i].time);
6224 172 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
6225 172 avio_w8(pb, 1); /* traf number */
6226 172 avio_w8(pb, 1); /* trun number */
6227 172 avio_w8(pb, 1); /* sample number */
6228 }
6229
6230 68 return update_size(pb, pos);
6231 }
6232
6233 39 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
6234 {
6235 AVIOContext *mfra_pb;
6236 int i, ret, sz;
6237 uint8_t *buf;
6238
6239 39 ret = avio_open_dyn_buf(&mfra_pb);
6240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0)
6241 ✗ return ret;
6242
6243 39 avio_wb32(mfra_pb, 0); /* size placeholder */
6244 39 ffio_wfourcc(mfra_pb, "mfra");
6245 /* An empty mfra atom is enough to indicate to the publishing point that
6246 * the stream has ended. */
6247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (mov->flags & FF_MOV_FLAG_ISML)
6248 ✗ goto done_mfra;
6249
6250
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 39 times.
111 for (i = 0; i < mov->nb_tracks; i++) {
6251 72 MOVTrack *track = &mov->tracks[i];
6252
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (track->nb_frag_info)
6253 68 mov_write_tfra_tag(mfra_pb, track);
6254 }
6255
6256 39 avio_wb32(mfra_pb, 16);
6257 39 ffio_wfourcc(mfra_pb, "mfro");
6258 39 avio_wb32(mfra_pb, 0); /* version + flags */
6259 39 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
6260
6261 39 done_mfra:
6262
6263 39 sz = update_size(mfra_pb, 0);
6264 39 ret = avio_get_dyn_buf(mfra_pb, &buf);
6265 39 avio_write(pb, buf, ret);
6266 39 ffio_free_dyn_buf(&mfra_pb);
6267
6268 39 return sz;
6269 }
6270
6271 206 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
6272 {
6273 206 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
6274
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 56 times.
206 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
6275
6276 206 mov->mdat_pos = avio_tell(pb);
6277 206 avio_wb32(pb, 0); /* size placeholder*/
6278 206 ffio_wfourcc(pb, "mdat");
6279 206 return 0;
6280 }
6281
6282 500 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
6283 int has_h264, int has_video, int write_minor)
6284 {
6285 500 MOVMuxContext *mov = s->priv_data;
6286 500 int minor = 0x200;
6287
6288
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
500 if (mov->major_brand && strlen(mov->major_brand) >= 4)
6289 ✗ ffio_wfourcc(pb, mov->major_brand);
6290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
500 else if (mov->mode == MODE_3GP) {
6291 ✗ ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
6292 ✗ minor = has_h264 ? 0x100 : 0x200;
6293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
500 } else if (mov->mode == MODE_AVIF) {
6294 ✗ ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
6295 ✗ minor = 0;
6296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
500 } else if (mov->mode & MODE_3G2) {
6297 ✗ ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
6298 ✗ minor = has_h264 ? 0x20000 : 0x10000;
6299
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 498 times.
500 } else if (mov->mode == MODE_PSP)
6300 2 ffio_wfourcc(pb, "MSNV");
6301
4/4
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 108 times.
498 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
6302
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 66 times.
74 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6303 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
6304
4/4
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 144 times.
490 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6305 30 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
6306
3/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
460 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6307 ✗ ffio_wfourcc(pb, "iso4");
6308
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 316 times.
460 else if (mov->mode == MODE_MP4)
6309 144 ffio_wfourcc(pb, "isom");
6310
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 314 times.
316 else if (mov->mode == MODE_IPOD)
6311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6312
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 304 times.
314 else if (mov->mode == MODE_ISM)
6313 10 ffio_wfourcc(pb, "isml");
6314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 304 times.
304 else if (mov->mode == MODE_F4V)
6315 ✗ ffio_wfourcc(pb, "f4v ");
6316 else
6317 304 ffio_wfourcc(pb, "qt ");
6318
6319
2/2
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 250 times.
500 if (write_minor)
6320 250 avio_wb32(pb, minor);
6321 500 }
6322
6323 250 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6324 {
6325 250 MOVMuxContext *mov = s->priv_data;
6326 250 int64_t pos = avio_tell(pb);
6327 250 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6328 250 int has_iamf = 0;
6329
6330 #if CONFIG_IAMFENC
6331
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 245 times.
250 for (int i = 0; i < s->nb_stream_groups; i++) {
6332 5 const AVStreamGroup *stg = s->stream_groups[i];
6333
6334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6335 ✗ stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6336 5 has_iamf = 1;
6337 5 break;
6338 }
6339 }
6340 #endif
6341
2/2
✓ Branch 0 taken 314 times.
✓ Branch 1 taken 250 times.
564 for (int i = 0; i < mov->nb_streams; i++) {
6342 314 AVStream *st = mov->tracks[i].st;
6343
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 312 times.
314 if (is_cover_image(st))
6344 2 continue;
6345
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 109 times.
312 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6346 203 has_video = 1;
6347
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 274 times.
312 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6348 38 has_h264 = 1;
6349
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 310 times.
312 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6350 2 has_av1 = 1;
6351
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 6 times.
312 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6352
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 4 times.
306 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6353
3/4
✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 300 times.
604 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6354 302 av_packet_side_data_get(st->codecpar->coded_side_data,
6355 302 st->codecpar->nb_coded_side_data,
6356 AV_PKT_DATA_DOVI_CONF))
6357 12 has_dolby = 1;
6358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 312 times.
312 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6359 ✗ has_id3 = 1;
6360 }
6361
6362 250 avio_wb32(pb, 0); /* size */
6363 250 ffio_wfourcc(pb, "ftyp");
6364
6365 // Write major brand
6366 250 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6367 // Write the major brand as the first compatible brand as well
6368 250 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6369
6370 // Write compatible brands, ensuring that we don't write the major brand as a
6371 // compatible brand a second time.
6372
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 245 times.
250 if (mov->mode == MODE_ISM) {
6373 5 ffio_wfourcc(pb, "piff");
6374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 } else if (mov->mode == MODE_AVIF) {
6375 const AVPixFmtDescriptor *pix_fmt_desc =
6376 ✗ av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6377 ✗ const int depth = pix_fmt_desc->comp[0].depth;
6378 ✗ if (mov->is_animated_avif) {
6379 // For animated AVIF, major brand is "avis". Add "avif" as a
6380 // compatible brand.
6381 ✗ ffio_wfourcc(pb, "avif");
6382 ✗ ffio_wfourcc(pb, "msf1");
6383 ✗ ffio_wfourcc(pb, "iso8");
6384 }
6385 ✗ ffio_wfourcc(pb, "mif1");
6386 ✗ ffio_wfourcc(pb, "miaf");
6387 ✗ if (depth == 8 || depth == 10) {
6388 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6389 // computing that is based on chroma subsampling type. 420 chroma
6390 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6391 ✗ if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6392 // 444 chroma subsampling.
6393 ✗ ffio_wfourcc(pb, "MA1A");
6394 } else {
6395 // 420 chroma subsampling.
6396 ✗ ffio_wfourcc(pb, "MA1B");
6397 }
6398 }
6399
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 152 times.
245 } else if (mov->mode != MODE_MOV) {
6400 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6401 // brand, if not already the major brand. This is compatible with users that
6402 // don't understand tfdt.
6403
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 2 times.
93 if (mov->mode == MODE_MP4) {
6404
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 89 times.
91 if (mov->flags & FF_MOV_FLAG_CMAF)
6405 2 ffio_wfourcc(pb, "cmfc");
6406
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 4 times.
91 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6407 33 ffio_wfourcc(pb, "iso6");
6408
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 89 times.
91 if (has_av1)
6409 2 ffio_wfourcc(pb, "av01");
6410
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 80 times.
91 if (has_dolby)
6411 11 ffio_wfourcc(pb, "dby1");
6412
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 86 times.
91 if (has_iamf)
6413 5 ffio_wfourcc(pb, "iamf");
6414 } else {
6415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6416 ✗ ffio_wfourcc(pb, "iso6");
6417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6418 ✗ ffio_wfourcc(pb, "iso5");
6419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6420 ✗ ffio_wfourcc(pb, "iso4");
6421 }
6422 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6423
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 17 times.
93 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6424 // write isom for mp4 only if it it's not the major brand already.
6425
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 72 times.
76 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6426 4 ffio_wfourcc(pb, "isom");
6427 76 ffio_wfourcc(pb, "iso2");
6428
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 52 times.
76 if (has_h264)
6429 24 ffio_wfourcc(pb, "avc1");
6430 }
6431 }
6432
6433
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 159 times.
250 if (mov->mode == MODE_MP4)
6434 91 ffio_wfourcc(pb, "mp41");
6435
6436
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
250 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6437 ✗ ffio_wfourcc(pb, "dash");
6438
6439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 250 times.
250 if (has_id3)
6440 ✗ ffio_wfourcc(pb, "aid3");
6441
6442 250 return update_size(pb, pos);
6443 }
6444
6445 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6446 {
6447 1 AVStream *video_st = s->streams[0];
6448 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6449 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6450 1 int audio_rate = audio_par->sample_rate;
6451 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6452
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 :
6453 0;
6454 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6455 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6456
6457
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) {
6458 ✗ av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6459 ✗ return AVERROR(EINVAL);
6460 }
6461
6462 1 avio_wb32(pb, 0x94); /* size */
6463 1 ffio_wfourcc(pb, "uuid");
6464 1 ffio_wfourcc(pb, "PROF");
6465
6466 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6467 1 avio_wb32(pb, 0xbb88695c);
6468 1 avio_wb32(pb, 0xfac9c740);
6469
6470 1 avio_wb32(pb, 0x0); /* ? */
6471 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6472
6473 1 avio_wb32(pb, 0x14); /* size */
6474 1 ffio_wfourcc(pb, "FPRF");
6475 1 avio_wb32(pb, 0x0); /* ? */
6476 1 avio_wb32(pb, 0x0); /* ? */
6477 1 avio_wb32(pb, 0x0); /* ? */
6478
6479 1 avio_wb32(pb, 0x2c); /* size */
6480 1 ffio_wfourcc(pb, "APRF"); /* audio */
6481 1 avio_wb32(pb, 0x0);
6482 1 avio_wb32(pb, 0x2); /* TrackID */
6483 1 ffio_wfourcc(pb, "mp4a");
6484 1 avio_wb32(pb, 0x20f);
6485 1 avio_wb32(pb, 0x0);
6486 1 avio_wb32(pb, audio_kbitrate);
6487 1 avio_wb32(pb, audio_kbitrate);
6488 1 avio_wb32(pb, audio_rate);
6489 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6490
6491 1 avio_wb32(pb, 0x34); /* size */
6492 1 ffio_wfourcc(pb, "VPRF"); /* video */
6493 1 avio_wb32(pb, 0x0);
6494 1 avio_wb32(pb, 0x1); /* TrackID */
6495
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6496 1 ffio_wfourcc(pb, "avc1");
6497 1 avio_wb16(pb, 0x014D);
6498 1 avio_wb16(pb, 0x0015);
6499 } else {
6500 ✗ ffio_wfourcc(pb, "mp4v");
6501 ✗ avio_wb16(pb, 0x0000);
6502 ✗ avio_wb16(pb, 0x0103);
6503 }
6504 1 avio_wb32(pb, 0x0);
6505 1 avio_wb32(pb, video_kbitrate);
6506 1 avio_wb32(pb, video_kbitrate);
6507 1 avio_wb32(pb, frame_rate);
6508 1 avio_wb32(pb, frame_rate);
6509 1 avio_wb16(pb, video_par->width);
6510 1 avio_wb16(pb, video_par->height);
6511 1 avio_wb32(pb, 0x010001); /* ? */
6512
6513 1 return 0;
6514 }
6515
6516 250 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6517 {
6518 250 MOVMuxContext *mov = s->priv_data;
6519 int i;
6520
6521 250 mov_write_ftyp_tag(pb,s);
6522
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 249 times.
250 if (mov->mode == MODE_PSP) {
6523 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6524
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6525 2 AVStream *st = mov->tracks[i].st;
6526
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6527 ✗ continue;
6528
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6529 1 video_streams_nb++;
6530
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6531 1 audio_streams_nb++;
6532 else
6533 ✗ other_streams_nb++;
6534 }
6535
6536
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) {
6537 ✗ av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6538 ✗ return AVERROR(EINVAL);
6539 }
6540 1 return mov_write_uuidprof_tag(pb, s);
6541 }
6542 249 return 0;
6543 }
6544
6545 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6546 {
6547 8 uint32_t c = -1;
6548 8 int i, closed_gop = 0;
6549
6550
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6551 368 c = (c << 8) + pkt->data[i];
6552
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6553 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6554
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6555 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6556
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
6557 8 *flags = MOV_SYNC_SAMPLE;
6558 else
6559 ✗ *flags = MOV_PARTIAL_SYNC_SAMPLE;
6560 8 break;
6561 }
6562 }
6563 8 return 0;
6564 }
6565
6566 ✗ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6567 {
6568 ✗ const uint8_t *start, *next, *end = pkt->data + pkt->size;
6569 ✗ int seq = 0, entry = 0;
6570 ✗ int key = pkt->flags & AV_PKT_FLAG_KEY;
6571 ✗ start = find_next_marker(pkt->data, end);
6572 ✗ for (next = start; next < end; start = next) {
6573 ✗ next = find_next_marker(start + 4, end);
6574 ✗ switch (AV_RB32(start)) {
6575 ✗ case VC1_CODE_SEQHDR:
6576 ✗ seq = 1;
6577 ✗ break;
6578 ✗ case VC1_CODE_ENTRYPOINT:
6579 ✗ entry = 1;
6580 ✗ break;
6581 ✗ case VC1_CODE_SLICE:
6582 ✗ trk->vc1_info.slices = 1;
6583 ✗ break;
6584 }
6585 }
6586 ✗ if (!trk->entry && trk->vc1_info.first_packet_seen)
6587 ✗ trk->vc1_info.first_frag_written = 1;
6588 ✗ if (!trk->entry && !trk->vc1_info.first_frag_written) {
6589 /* First packet in first fragment */
6590 ✗ trk->vc1_info.first_packet_seq = seq;
6591 ✗ trk->vc1_info.first_packet_entry = entry;
6592 ✗ trk->vc1_info.first_packet_seen = 1;
6593 ✗ } else if ((seq && !trk->vc1_info.packet_seq) ||
6594 ✗ (entry && !trk->vc1_info.packet_entry)) {
6595 int i;
6596 ✗ for (i = 0; i < trk->entry; i++)
6597 ✗ trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6598 ✗ trk->has_keyframes = 0;
6599 ✗ if (seq)
6600 ✗ trk->vc1_info.packet_seq = 1;
6601 ✗ if (entry)
6602 ✗ trk->vc1_info.packet_entry = 1;
6603 ✗ if (!trk->vc1_info.first_frag_written) {
6604 /* First fragment */
6605 ✗ if ((!seq || trk->vc1_info.first_packet_seq) &&
6606 ✗ (!entry || trk->vc1_info.first_packet_entry)) {
6607 /* First packet had the same headers as this one, readd the
6608 * sync sample flag. */
6609 ✗ trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6610 ✗ trk->has_keyframes = 1;
6611 }
6612 }
6613 }
6614 ✗ if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6615 ✗ key = seq && entry;
6616 ✗ else if (trk->vc1_info.packet_seq)
6617 ✗ key = seq;
6618 ✗ else if (trk->vc1_info.packet_entry)
6619 ✗ key = entry;
6620 ✗ if (key) {
6621 ✗ trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6622 ✗ trk->has_keyframes++;
6623 }
6624 ✗ }
6625
6626 ✗ static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6627 {
6628 int length;
6629
6630 ✗ if (pkt->size < 8)
6631 ✗ return;
6632
6633 ✗ length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6634 ✗ if (length < 8 || length > pkt->size)
6635 ✗ return;
6636
6637 ✗ if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6638 ✗ trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6639 ✗ trk->has_keyframes++;
6640 }
6641
6642 ✗ return;
6643 }
6644
6645 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6646 {
6647 89 MOVMuxContext *mov = s->priv_data;
6648 int ret, buf_size;
6649 uint8_t *buf;
6650 int i, offset;
6651
6652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if (!track->mdat_buf)
6653 ✗ return 0;
6654
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!mov->mdat_buf) {
6655
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6656 ✗ return ret;
6657 }
6658 89 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6659
6660 89 offset = avio_tell(mov->mdat_buf);
6661 89 avio_write(mov->mdat_buf, buf, buf_size);
6662 89 ffio_reset_dyn_buf(track->mdat_buf);
6663
6664
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 89 times.
177 for (i = track->entries_flushed; i < track->entry; i++)
6665 88 track->cluster[i].pos += offset;
6666 89 track->entries_flushed = track->entry;
6667 89 return 0;
6668 }
6669
6670 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6671 {
6672 28 MOVMuxContext *mov = s->priv_data;
6673 28 AVPacket *squashed_packet = mov->pkt;
6674 28 int ret = AVERROR_BUG;
6675
6676
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6677 28 case AV_CODEC_ID_TTML: {
6678 28 int had_packets = !!track->squashed_packet_queue.head;
6679
6680
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = ff_mov_generate_squashed_ttml_packet(s, track, squashed_packet)) < 0) {
6681 ✗ goto finish_squash;
6682 }
6683
6684 // We have generated a padding packet (no actual input packets in
6685 // queue) and its duration is zero. Skipping writing it.
6686
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
28 if (!had_packets && squashed_packet->duration == 0) {
6687 ✗ goto finish_squash;
6688 }
6689
6690 28 track->end_reliable = 1;
6691 28 break;
6692 }
6693 ✗ default:
6694 ✗ ret = AVERROR(EINVAL);
6695 ✗ goto finish_squash;
6696 }
6697
6698 28 squashed_packet->stream_index = track->st->index;
6699
6700 28 ret = mov_write_single_packet(s, squashed_packet);
6701
6702 28 finish_squash:
6703 28 av_packet_unref(squashed_packet);
6704
6705 28 return ret;
6706 }
6707
6708 399 static int mov_write_squashed_packets(AVFormatContext *s)
6709 {
6710 399 MOVMuxContext *mov = s->priv_data;
6711
6712
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 399 times.
975 for (int i = 0; i < mov->nb_streams; i++) {
6713 576 MOVTrack *track = &mov->tracks[i];
6714 576 int ret = AVERROR_BUG;
6715
6716
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 546 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
576 if (track->squash_fragment_samples_to_one && !track->entry) {
6717
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6718 ✗ av_log(s, AV_LOG_ERROR,
6719 "Failed to write squashed packet for %s stream with "
6720 "index %d and track id %d. Error: %s\n",
6721 ✗ avcodec_get_name(track->st->codecpar->codec_id),
6722 ✗ track->st->index, track->track_id,
6723 ✗ av_err2str(ret));
6724 ✗ return ret;
6725 }
6726 }
6727 }
6728
6729 399 return 0;
6730 }
6731
6732 189 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6733 int64_t ref_pos)
6734 {
6735 int i;
6736
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 187 times.
189 if (!track->entry)
6737 2 return 0;
6738
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 179 times.
187 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6739
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6740 124 track->cluster[i].pos += ref_pos + track->data_offset;
6741
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6742 // First flush. Chunking for this fragment may already have been
6743 // done, either if we didn't use empty_moov, or if we did use
6744 // delay_moov. In either case, reset chunking here.
6745
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6746 63 track->cluster[i].chunkNum = 0;
6747 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6748 }
6749 }
6750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6751 8 track->entry_written + track->entry,
6752 sizeof(*track->cluster)))
6753 ✗ return AVERROR(ENOMEM);
6754 8 memcpy(&track->cluster_written[track->entry_written],
6755 8 track->cluster, track->entry * sizeof(*track->cluster));
6756 8 track->entry_written += track->entry;
6757 }
6758 187 track->entry = 0;
6759 187 track->entries_flushed = 0;
6760 187 track->end_reliable = 0;
6761 187 return 0;
6762 }
6763
6764 151 static int mov_flush_fragment(AVFormatContext *s, int force)
6765 {
6766 151 MOVMuxContext *mov = s->priv_data;
6767 151 int i, first_track = -1;
6768 151 int64_t mdat_size = 0, mdat_start = 0;
6769 int ret;
6770 151 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6771
6772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6773 ✗ return 0;
6774
6775 // Check if we have any tracks that require squashing.
6776 // In that case, we'll have to write the packet here.
6777
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 151 times.
151 if ((ret = mov_write_squashed_packets(s)) < 0)
6778 ✗ return ret;
6779
6780 // Try to fill in the duration of the last packet in each stream
6781 // from queued packets in the interleave queues. If the flushing
6782 // of fragments was triggered automatically by an AVPacket, we
6783 // already have reliable info for the end of that track, but other
6784 // tracks may need to be filled in.
6785
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 151 times.
417 for (i = 0; i < mov->nb_streams; i++) {
6786 266 MOVTrack *track = &mov->tracks[i];
6787
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 90 times.
266 if (!track->end_reliable) {
6788 176 const AVPacket *pkt = ff_interleaved_peek(s, i);
6789
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 170 times.
176 if (pkt) {
6790 int64_t offset, dts, pts;
6791 6 ff_get_muxer_ts_offset(s, i, &offset);
6792 6 pts = pkt->pts + offset;
6793 6 dts = pkt->dts + offset;
6794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6795 ✗ dts += track->dts_shift;
6796 6 track->track_duration = dts - track->start_dts;
6797
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6798 6 track->end_pts = pts;
6799 else
6800 ✗ track->end_pts = dts;
6801
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
6802 6 track->elst_end_pts = track->end_pts;
6803 }
6804 }
6805 }
6806
6807
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 151 times.
423 for (i = 0; i < mov->nb_tracks; i++) {
6808 272 MOVTrack *track = &mov->tracks[i];
6809
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 185 times.
272 if (track->entry <= 1)
6810 87 continue;
6811 // Sample durations are calculated as the diff of dts values,
6812 // but for the last sample in a fragment, we don't know the dts
6813 // of the first sample in the next fragment, so we have to rely
6814 // on what was set as duration in the AVPacket. Not all callers
6815 // set this though, so we might want to replace it with an
6816 // estimate if it currently is zero.
6817
2/2
✓ Branch 1 taken 183 times.
✓ Branch 2 taken 2 times.
185 if (get_cluster_duration(track, track->entry - 1) != 0)
6818 183 continue;
6819 // Use the duration (i.e. dts diff) of the second last sample for
6820 // the last one. This is a wild guess (and fatal if it turns out
6821 // to be too long), but probably the best we can do - having a zero
6822 // duration is bad as well.
6823 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6824 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6825
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6826 2 av_log(s, AV_LOG_WARNING,
6827 "Estimating the duration of the last packet in a "
6828 "fragment, consider setting the duration field in "
6829 "AVPacket instead.\n");
6830 2 mov->missing_duration_warned = 1;
6831 }
6832 }
6833
6834
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 122 times.
151 if (!mov->moov_written) {
6835 29 int64_t pos = avio_tell(s->pb);
6836 uint8_t *buf;
6837 int buf_size, moov_size;
6838
6839
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 22 times.
73 for (i = 0; i < mov->nb_tracks; i++)
6840
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 44 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
51 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6841 7 break;
6842 /* Don't write the initial moov unless all tracks have data */
6843
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
29 if (i < mov->nb_tracks && !force)
6844 4 return 0;
6845
6846 25 moov_size = get_moov_size(s);
6847
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 25 times.
71 for (i = 0; i < mov->nb_tracks; i++)
6848 46 mov->tracks[i].data_offset = pos + moov_size + 8;
6849
6850 25 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6851
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6852
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6853 20 mov_write_identification(s->pb, s);
6854
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6855 ✗ return ret;
6856
6857
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6859 ✗ mov->reserved_header_pos = avio_tell(s->pb);
6860 20 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6861 20 mov->moov_written = 1;
6862 20 return 0;
6863 }
6864
6865
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (mov->mdat_buf) {
6866 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6867 4 avio_wb32(s->pb, buf_size + 8);
6868 4 ffio_wfourcc(s->pb, "mdat");
6869 4 avio_write(s->pb, buf, buf_size);
6870 4 ffio_reset_dyn_buf(mov->mdat_buf);
6871 }
6872
6873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6874 ✗ mov->reserved_header_pos = avio_tell(s->pb);
6875
6876 5 mov->moov_written = 1;
6877 5 mov->mdat_size = 0;
6878
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (i = 0; i < mov->nb_tracks; i++)
6879 10 mov_finish_fragment(mov, &mov->tracks[i], 0);
6880 5 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6881 5 return 0;
6882 }
6883
6884
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 120 times.
122 if (mov->frag_interleave) {
6885
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6886 4 MOVTrack *track = &mov->tracks[i];
6887 int ret;
6888
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6889 ✗ return ret;
6890 }
6891
6892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6893 ✗ return 0;
6894 2 mdat_size = avio_tell(mov->mdat_buf);
6895 }
6896
6897
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 122 times.
342 for (i = 0; i < mov->nb_tracks; i++) {
6898 220 MOVTrack *track = &mov->tracks[i];
6899
4/4
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 171 times.
220 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6900 49 track->data_offset = 0;
6901 else
6902 171 track->data_offset = mdat_size;
6903
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 110 times.
220 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6904 110 has_video = 1;
6905
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 if (first_video_track) {
6906
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 16 times.
110 if (track->entry)
6907 94 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6908 110 first_video_track = 0;
6909 }
6910 }
6911
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 179 times.
220 if (!track->entry)
6912 41 continue;
6913
1/2
✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
179 if (track->mdat_buf)
6914 179 mdat_size += avio_tell(track->mdat_buf);
6915
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 77 times.
179 if (first_track < 0)
6916 102 first_track = i;
6917 }
6918
6919
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 102 times.
122 if (!mdat_size)
6920 20 return 0;
6921
6922
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
102 avio_write_marker(s->pb,
6923 102 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6924
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 7 times.
102 (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);
6925
6926
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 102 times.
289 for (i = first_track; i < mov->nb_tracks; i++) {
6927 187 MOVTrack *track = &mov->tracks[i];
6928 187 int buf_size, write_moof = 1, moof_tracks = -1;
6929 uint8_t *buf;
6930
6931
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 179 times.
187 if (!track->entry)
6932 8 continue;
6933
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 138 times.
179 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6934 41 mdat_size = avio_tell(track->mdat_buf);
6935 41 moof_tracks = i;
6936 } else {
6937 138 write_moof = i == first_track;
6938 }
6939
6940
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 60 times.
179 if (write_moof) {
6941 119 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6942
6943 119 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6944 119 mov->fragments++;
6945
6946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (track->cenc.aes_ctr)
6947 ✗ ff_mov_cenc_flush(&track->cenc);
6948
6949 119 avio_wb32(s->pb, mdat_size + 8);
6950 119 ffio_wfourcc(s->pb, "mdat");
6951 119 mdat_start = avio_tell(s->pb);
6952 }
6953
6954 179 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6955
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 3 times.
179 if (!mov->frag_interleave) {
6956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176 times.
176 if (!track->mdat_buf)
6957 ✗ continue;
6958 176 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6959 176 avio_write(s->pb, buf, buf_size);
6960 176 ffio_reset_dyn_buf(track->mdat_buf);
6961 } else {
6962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!mov->mdat_buf)
6963 ✗ continue;
6964 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6965 3 avio_write(s->pb, buf, buf_size);
6966 3 ffio_reset_dyn_buf(mov->mdat_buf);
6967 }
6968 }
6969
6970 102 mov->mdat_size = 0;
6971
6972 102 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6973 102 return 0;
6974 }
6975
6976 97 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6977 {
6978 97 MOVMuxContext *mov = s->priv_data;
6979 97 int had_moov = mov->moov_written;
6980 97 int ret = mov_flush_fragment(s, force);
6981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (ret < 0)
6982 ✗ return ret;
6983 // If using delay_moov, the first flush only wrote the moov,
6984 // not the actual moof+mdat pair, thus flush once again.
6985
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
97 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6986 10 ret = mov_flush_fragment(s, force);
6987 97 return ret;
6988 }
6989
6990 46171 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6991 {
6992 int64_t ref;
6993 uint64_t duration;
6994
6995
2/2
✓ Branch 0 taken 45373 times.
✓ Branch 1 taken 798 times.
46171 if (trk->entry) {
6996 45373 ref = trk->cluster[trk->entry - 1].dts;
6997
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 606 times.
798 } else if ( trk->start_dts != AV_NOPTS_VALUE
6998
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 8 times.
192 && !trk->frag_discont) {
6999 184 ref = trk->start_dts + trk->track_duration;
7000 } else
7001 614 ref = pkt->dts; // Skip tests for the first packet
7002
7003
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 42116 times.
46171 if (trk->dts_shift != AV_NOPTS_VALUE) {
7004 /* With negative CTS offsets we have set an offset to the DTS,
7005 * reverse this for the check. */
7006 4055 ref -= trk->dts_shift;
7007 }
7008
7009 46171 duration = pkt->dts - ref;
7010
2/4
✓ Branch 0 taken 46171 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46171 times.
46171 if (pkt->dts < ref || duration >= INT_MAX) {
7011 ✗ av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
7012 duration, pkt->dts, pkt->stream_index);
7013
7014 ✗ pkt->dts = ref + 1;
7015 ✗ pkt->pts = AV_NOPTS_VALUE;
7016 }
7017
7018
2/4
✓ Branch 0 taken 46171 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46171 times.
46171 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
7019 ✗ av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
7020 ✗ return AVERROR(EINVAL);
7021 }
7022 46171 return 0;
7023 }
7024
7025 6 int ff_mov_set_fragment_end_hint(AVFormatContext *s, int stream_index,
7026 const AVPacket *pkt, AVRational src_time_base)
7027 {
7028 6 MOVMuxContext *mov = s->priv_data;
7029 AVStream *st;
7030 MOVTrack *track;
7031 int64_t offset, dts, pts, candidate_duration;
7032
7033
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
7034
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 stream_index < 0 || stream_index >= s->nb_streams ||
7035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 pkt->dts == AV_NOPTS_VALUE)
7036 ✗ return 0;
7037
7038 6 st = s->streams[stream_index];
7039 6 track = st->priv_data;
7040
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!track->entry || track->start_dts == AV_NOPTS_VALUE)
7041 ✗ return 0;
7042
7043
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (ff_get_muxer_ts_offset(s, stream_index, &offset) < 0)
7044 ✗ return 0;
7045
7046 6 dts = av_rescale_q(pkt->dts, src_time_base, st->time_base) + offset;
7047 12 pts = pkt->pts == AV_NOPTS_VALUE
7048 ? AV_NOPTS_VALUE
7049
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 : av_rescale_q(pkt->pts, src_time_base, st->time_base) + offset;
7050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
7051 ✗ dts += track->dts_shift;
7052
7053 6 candidate_duration = dts - track->start_dts;
7054
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (dts <= track->cluster[track->entry - 1].dts ||
7055
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 candidate_duration < 0 || candidate_duration >= track->track_duration)
7056 6 return 0;
7057
7058 ✗ track->track_duration = candidate_duration;
7059 ✗ track->end_pts = pts != AV_NOPTS_VALUE ? pts : dts;
7060 ✗ if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7061 ✗ track->elst_end_pts = track->end_pts;
7062 ✗ track->end_reliable = 1;
7063
7064 ✗ return 1;
7065 }
7066
7067 23104 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7068 {
7069 23104 MOVMuxContext *mov = s->priv_data;
7070 23104 AVIOContext *pb = s->pb;
7071 MOVTrack *trk;
7072 AVCodecParameters *par;
7073 AVProducerReferenceTime *prft;
7074 23104 unsigned int samples_in_chunk = 0;
7075 int64_t duration;
7076 23104 int size = pkt->size, ret = 0, offset = 0;
7077 size_t prft_size;
7078 23104 uint8_t *reformatted_data = NULL;
7079
7080
2/2
✓ Branch 0 taken 23058 times.
✓ Branch 1 taken 46 times.
23104 if (pkt->stream_index < s->nb_streams)
7081 23058 trk = s->streams[pkt->stream_index]->priv_data;
7082 else // Timecode or chapter
7083 46 trk = &mov->tracks[pkt->stream_index];
7084 23104 par = trk->par;
7085
7086 23104 ret = check_pkt(s, trk, pkt);
7087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23104 times.
23104 if (ret < 0)
7088 ✗ return ret;
7089
7090
2/2
✓ Branch 0 taken 22483 times.
✓ Branch 1 taken 621 times.
23104 if (pkt->pts != AV_NOPTS_VALUE &&
7091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22483 times.
22483 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
7092 ✗ av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
7093 ✗ return AVERROR_PATCHWELCOME;
7094 }
7095
7096
3/4
✓ Branch 0 taken 16496 times.
✓ Branch 1 taken 6608 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16496 times.
23104 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
7097 int ret;
7098
4/4
✓ Branch 0 taken 2176 times.
✓ Branch 1 taken 4432 times.
✓ Branch 2 taken 1938 times.
✓ Branch 3 taken 238 times.
6608 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
7099
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 6282 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
6370 if (mov->frag_interleave && mov->fragments > 0) {
7100
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
7101
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
7102 ✗ return ret;
7103 }
7104 }
7105
7106
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 6297 times.
6370 if (!trk->mdat_buf) {
7107
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
73 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
7108 ✗ return ret;
7109 }
7110 6370 pb = trk->mdat_buf;
7111 } else {
7112
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
7113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
7114 ✗ return ret;
7115 }
7116 238 pb = mov->mdat_buf;
7117 }
7118 }
7119
7120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23104 times.
23104 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
7121 /* We must find out how many AMR blocks there are in one packet */
7122 static const uint16_t packed_size[16] =
7123 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
7124 ✗ int len = 0;
7125
7126 ✗ while (len < size && samples_in_chunk < 100) {
7127 ✗ len += packed_size[(pkt->data[len] >> 3) & 0x0F];
7128 ✗ samples_in_chunk++;
7129 }
7130 ✗ if (samples_in_chunk > 1) {
7131 ✗ av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
7132 ✗ return -1;
7133 }
7134
1/2
✓ Branch 0 taken 23104 times.
✗ Branch 1 not taken.
23104 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
7135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23104 times.
23104 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
7136 ✗ samples_in_chunk = trk->par->frame_size;
7137
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 21690 times.
23104 } else if (trk->sample_size)
7138 1414 samples_in_chunk = size / trk->sample_size;
7139 else
7140 21690 samples_in_chunk = 1;
7141
7142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23104 times.
23104 if (samples_in_chunk < 1) {
7143 ✗ av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
7144 ✗ return AVERROR_PATCHWELCOME;
7145 }
7146
7147 /* copy extradata if it exists */
7148
3/4
✓ Branch 0 taken 7413 times.
✓ Branch 1 taken 15691 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7413 times.
23104 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
7149 ✗ !TAG_IS_AVCI(trk->tag) &&
7150 ✗ (par->codec_id != AV_CODEC_ID_DNXHD)) {
7151 ✗ trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
7152 ✗ if (!trk->extradata[0]) {
7153 ✗ ret = AVERROR(ENOMEM);
7154 ✗ goto err;
7155 }
7156 ✗ trk->extradata_size[0] = par->extradata_size;
7157 }
7158
7159
2/2
✓ Branch 0 taken 22989 times.
✓ Branch 1 taken 115 times.
23104 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
7160
2/2
✓ Branch 0 taken 20375 times.
✓ Branch 1 taken 2614 times.
22989 par->codec_id == AV_CODEC_ID_H264 ||
7161
2/2
✓ Branch 0 taken 20003 times.
✓ Branch 1 taken 372 times.
20375 par->codec_id == AV_CODEC_ID_HEVC ||
7162
2/2
✓ Branch 0 taken 19993 times.
✓ Branch 1 taken 10 times.
20003 par->codec_id == AV_CODEC_ID_VVC ||
7163
1/2
✓ Branch 0 taken 19993 times.
✗ Branch 1 not taken.
19993 par->codec_id == AV_CODEC_ID_VP9 ||
7164
2/2
✓ Branch 0 taken 19693 times.
✓ Branch 1 taken 300 times.
19993 par->codec_id == AV_CODEC_ID_EVC ||
7165
1/2
✓ Branch 0 taken 19693 times.
✗ Branch 1 not taken.
19693 par->codec_id == AV_CODEC_ID_LCEVC ||
7166
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19693 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3387 times.
23104 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
7167
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)) {
7168 /* copy frame to create needed atoms */
7169 24 trk->extradata_size[0] = size;
7170 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
7171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
7172 ✗ ret = AVERROR(ENOMEM);
7173 ✗ goto err;
7174 }
7175 24 memcpy(trk->extradata[0], pkt->data, size);
7176 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7177 }
7178
7179 23104 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
7180
4/6
✓ Branch 0 taken 23104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 23101 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
23104 if (pkt->size && sd && sd->size > 0) {
7181 int i;
7182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < trk->stsd_count; i++) {
7183
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
7184 1 break;
7185 }
7186
7187
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (i < trk->stsd_count)
7188 1 trk->last_stsd_index = i;
7189
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (trk->stsd_count <= INT_MAX - 1) {
7190 2 int new_count = trk->stsd_count + 1;
7191 2 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
7192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata)
7193 ✗ return AVERROR(ENOMEM);
7194 2 trk->extradata = extradata;
7195
7196 2 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
7197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata_size)
7198 ✗ return AVERROR(ENOMEM);
7199 2 trk->extradata_size = extradata_size;
7200
7201 2 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
7202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->extradata[trk->stsd_count])
7203 ✗ return AVERROR(ENOMEM);
7204
7205 2 trk->extradata_size[trk->stsd_count] = sd->size;
7206 2 trk->last_stsd_index = trk->stsd_count;
7207 2 trk->stsd_count = new_count;
7208 } else
7209 ✗ return AVERROR(ENOMEM);
7210 }
7211
7212
3/4
✓ Branch 0 taken 8186 times.
✓ Branch 1 taken 14918 times.
✓ Branch 2 taken 8186 times.
✗ Branch 3 not taken.
23104 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
7213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8186 times.
8186 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
7214 ✗ if (!trk->st->nb_frames) {
7215 ✗ av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
7216 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
7217 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
7218 ✗ return -1;
7219 }
7220 ✗ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
7221 }
7222
3/4
✓ Branch 0 taken 2614 times.
✓ Branch 1 taken 20490 times.
✓ Branch 2 taken 2614 times.
✗ Branch 3 not taken.
23104 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
7223
16/30
✓ Branch 0 taken 515 times.
✓ Branch 1 taken 2099 times.
✓ Branch 2 taken 515 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 515 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 515 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 515 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 515 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 515 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 515 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 515 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 515 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 515 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 515 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 515 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 515 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 515 times.
✗ Branch 29 not taken.
2614 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
7224 /* from x264 or from bytestream H.264 */
7225 /* NAL reformatting needed */
7226
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 515 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
515 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7227 ✗ ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
7228 &size);
7229 ✗ if (ret < 0)
7230 ✗ return ret;
7231 ✗ avio_write(pb, reformatted_data, size);
7232 } else {
7233
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 498 times.
515 if (trk->cenc.aes_ctr) {
7234 17 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (size < 0) {
7236 ✗ ret = size;
7237 ✗ goto err;
7238 }
7239 } else {
7240 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7241 }
7242 }
7243
3/4
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 22217 times.
✓ Branch 2 taken 372 times.
✗ Branch 3 not taken.
22589 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7244
3/4
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 355 times.
✓ Branch 3 taken 17 times.
727 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7245 /* extradata is Annex B, assume the bitstream is too and convert it */
7246 355 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
7247
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
355 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7248 ✗ ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
7249 &size, filter_ps, NULL);
7250 ✗ if (ret < 0)
7251 ✗ return ret;
7252 ✗ avio_write(pb, reformatted_data, size);
7253 } else {
7254
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 354 times.
355 if (trk->cenc.aes_ctr) {
7255 1 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (size < 0) {
7257 ✗ ret = size;
7258 ✗ goto err;
7259 }
7260 } else {
7261 354 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
7262 }
7263 }
7264
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 22224 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
22234 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7265
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7266 /* extradata is Annex B, assume the bitstream is too and convert it */
7267
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) {
7268 ✗ ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
7269 &size, 0, NULL);
7270 ✗ if (ret < 0)
7271 ✗ return ret;
7272 ✗ avio_write(pb, reformatted_data, size);
7273 } else {
7274 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
7275 }
7276
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22224 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22224 } else if (par->codec_id == AV_CODEC_ID_LCEVC && trk->extradata_size[trk->last_stsd_index] > 0 &&
7277 ✗ *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1) {
7278 /* extradata is Annex B, assume the bitstream is too and convert it */
7279 ✗ if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7280 ✗ ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size);
7281 ✗ if (ret < 0)
7282 ✗ return ret;
7283 ✗ avio_write(pb, reformatted_data, size);
7284 } else {
7285 ✗ if (trk->cenc.aes_ctr) {
7286 ✗ size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7287 ✗ if (size < 0) {
7288 ✗ ret = size;
7289 ✗ goto err;
7290 }
7291 } else {
7292 ✗ size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7293 }
7294 }
7295
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 22196 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 24 times.
22224 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
7296
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) {
7297 ✗ ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
7298 &size, &offset);
7299 ✗ if (ret < 0)
7300 ✗ return ret;
7301 ✗ avio_write(pb, reformatted_data, size);
7302 } else {
7303 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
7304
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]) {
7305 ✗ mov->avif_extent_length[pkt->stream_index] = size;
7306 }
7307 }
7308
7309
2/2
✓ Branch 0 taken 21597 times.
✓ Branch 1 taken 623 times.
22220 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
7310
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 20483 times.
21597 par->codec_id == AV_CODEC_ID_EAC3) {
7311 1737 size = handle_eac3(mov, pkt, trk);
7312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (size < 0)
7313 ✗ return size;
7314
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1736 times.
1737 else if (!size)
7315 1 goto end;
7316 1736 avio_write(pb, pkt->data, size);
7317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20483 times.
20483 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
7318 ✗ size = 8;
7319
7320 ✗ for (int i = 0; i < pkt->size; i += 3) {
7321 ✗ if (pkt->data[i] == 0xFC) {
7322 ✗ size += 2;
7323 }
7324 }
7325 ✗ avio_wb32(pb, size);
7326 ✗ ffio_wfourcc(pb, "cdat");
7327 ✗ for (int i = 0; i < pkt->size; i += 3) {
7328 ✗ if (pkt->data[i] == 0xFC) {
7329 ✗ avio_w8(pb, pkt->data[i + 1]);
7330 ✗ avio_w8(pb, pkt->data[i + 2]);
7331 }
7332 }
7333
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20480 times.
20483 } else if (par->codec_id == AV_CODEC_ID_APV) {
7334 3 ff_isom_parse_apvc(trk->apv, pkt, s);
7335 3 avio_wb32(s->pb, pkt->size);
7336 3 size += 4;
7337
7338 3 avio_write(s->pb, pkt->data, pkt->size);
7339 } else {
7340
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 20447 times.
20480 if (trk->cenc.aes_ctr) {
7341 33 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
7342 33 int extradata_size = trk->extradata_size[trk->last_stsd_index];
7343
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
38 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
7344 5 int nal_size_length = (extradata[4] & 0x3) + 1;
7345 5 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7346
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
32 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
7347 4 int nal_size_length = (extradata[21] & 0x3) + 1;
7348 4 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 } else if(par->codec_id == AV_CODEC_ID_VVC) {
7350 ✗ ret = AVERROR_PATCHWELCOME;
7351
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if(par->codec_id == AV_CODEC_ID_AV1) {
7352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 av_assert0(size == pkt->size);
7353 24 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
7354
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (ret > 0) {
7355 24 size = ret;
7356 24 ret = 0;
7357 }
7358 } else {
7359 ✗ ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
7360 }
7361
7362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
7363 ✗ goto err;
7364 }
7365 } else {
7366 20447 avio_write(pb, pkt->data, size);
7367 }
7368 }
7369
7370
2/2
✓ Branch 0 taken 314 times.
✓ Branch 1 taken 22789 times.
23103 if (trk->entry >= trk->cluster_capacity) {
7371 314 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
7372 314 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
7373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
314 if (!cluster) {
7374 ✗ ret = AVERROR(ENOMEM);
7375 ✗ goto err;
7376 }
7377 314 trk->cluster = cluster;
7378 314 trk->cluster_capacity = new_capacity;
7379 }
7380
7381 23103 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7382 23103 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7383 23103 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7384 23103 trk->cluster[trk->entry].chunkNum = 0;
7385 23103 trk->cluster[trk->entry].size = size;
7386 23103 trk->cluster[trk->entry].entries = samples_in_chunk;
7387 23103 trk->cluster[trk->entry].dts = pkt->dts;
7388 23103 trk->cluster[trk->entry].pts = pkt->pts;
7389
2/2
✓ Branch 0 taken 23075 times.
✓ Branch 1 taken 28 times.
23103 if (!trk->squash_fragment_samples_to_one &&
7390
4/4
✓ Branch 0 taken 399 times.
✓ Branch 1 taken 22676 times.
✓ Branch 2 taken 103 times.
✓ Branch 3 taken 296 times.
23075 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7391
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 4 times.
103 if (!trk->frag_discont) {
7392 /* First packet of a new fragment. We already wrote the duration
7393 * of the last packet of the previous fragment based on track_duration,
7394 * which might not exactly match our dts. Therefore adjust the dts
7395 * of this packet to be what the previous packets duration implies. */
7396 99 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7397 /* We also may have written the pts and the corresponding duration
7398 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7399 * the next fragment. This means the cts of the first sample must
7400 * be the same in all fragments, unless end_pts was updated by
7401 * the packet causing the fragment to be written. */
7402
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 83 times.
99 if ((mov->flags & FF_MOV_FLAG_DASH &&
7403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7404
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 61 times.
83 mov->mode == MODE_ISM)
7405 38 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7406 } else {
7407 /* New fragment, but discontinuous from previous fragments.
7408 * Pretend the duration sum of the earlier fragments is
7409 * pkt->dts - trk->start_dts. */
7410 4 trk->end_pts = trk->elst_end_pts = AV_NOPTS_VALUE;
7411 4 trk->frag_discont = 0;
7412 }
7413 }
7414
7415
6/6
✓ Branch 0 taken 427 times.
✓ Branch 1 taken 22676 times.
✓ Branch 2 taken 300 times.
✓ Branch 3 taken 127 times.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 263 times.
23103 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7416
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 15 times.
37 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7417 /* Not using edit lists and shifting the first track to start from zero.
7418 * If the other streams start from a later timestamp, we won't be able
7419 * to signal the difference in starting time without an edit list.
7420 * Thus move the timestamp for this first sample to 0, increasing
7421 * its duration instead. */
7422 22 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7423 }
7424
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 22825 times.
23103 if (trk->start_dts == AV_NOPTS_VALUE) {
7425 278 trk->start_dts = pkt->dts;
7426
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 272 times.
278 if (trk->frag_discont) {
7427
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7428 /* Pretend the whole stream started at pts=0, with earlier fragments
7429 * already written. If the stream started at pts=0, the duration sum
7430 * of earlier fragments would have been pkt->pts. */
7431 4 trk->start_dts = pkt->dts - pkt->pts;
7432 } else {
7433 /* Pretend the whole stream started at dts=0, with earlier fragments
7434 * already written, with a duration summing up to pkt->dts. */
7435 2 trk->start_dts = 0;
7436 }
7437 6 trk->frag_discont = 0;
7438
4/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 50 times.
272 } else if (pkt->dts && mov->moov_written)
7439 2 av_log(s, AV_LOG_WARNING,
7440 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7441 "already has been written. Set the delay_moov flag to handle "
7442 "this case.\n",
7443 pkt->stream_index, pkt->dts);
7444 }
7445
7446 23103 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
7447
5/6
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 23063 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 1 times.
23142 if (sd && sd->size >= 10 && trk->par->frame_size) {
7448
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
39 duration = FFMAX(av_rescale_q(trk->par->frame_size, (AVRational){ 1, trk->par->sample_rate },
7449 trk->st->time_base), pkt->duration);
7450
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (mov->use_editlist)
7451 39 pkt->duration = duration;
7452 39 duration -= av_rescale_q(AV_RL32(sd->data + 4), (AVRational){ 1, trk->par->sample_rate },
7453 39 trk->st->time_base);
7454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (duration < 0)
7455 ✗ return AVERROR_INVALIDDATA;
7456 } else
7457 23064 duration = pkt->duration;
7458
7459 23103 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7460 23103 trk->last_sample_is_subtitle_end = 0;
7461
7462
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 22482 times.
23103 if (pkt->pts == AV_NOPTS_VALUE) {
7463 621 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7464 621 pkt->pts = pkt->dts;
7465 }
7466
2/2
✓ Branch 0 taken 1401 times.
✓ Branch 1 taken 21702 times.
23103 if (pkt->dts != pkt->pts)
7467 1401 trk->flags |= MOV_TRACK_CTTS;
7468 23103 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7469 23103 trk->cluster[trk->entry].flags = 0;
7470
6/6
✓ Branch 0 taken 22803 times.
✓ Branch 1 taken 300 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 22735 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 63 times.
23103 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7471 305 trk->start_cts = pkt->pts - pkt->dts;
7472
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 22799 times.
23103 if (trk->end_pts == AV_NOPTS_VALUE)
7473 304 trk->end_pts = trk->cluster[trk->entry].dts +
7474 304 trk->cluster[trk->entry].cts + duration;
7475 else
7476 22799 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7477 trk->cluster[trk->entry].cts +
7478 duration);
7479
2/2
✓ Branch 0 taken 23100 times.
✓ Branch 1 taken 3 times.
23103 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7480 23100 trk->elst_end_pts = trk->end_pts;
7481
7482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23103 times.
23103 if (par->codec_id == AV_CODEC_ID_VC1) {
7483 ✗ mov_parse_vc1_frame(pkt, trk);
7484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23103 times.
23103 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7485 ✗ mov_parse_truehd_frame(pkt, trk);
7486
2/2
✓ Branch 0 taken 17051 times.
✓ Branch 1 taken 6052 times.
23103 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7487
4/4
✓ Branch 0 taken 6267 times.
✓ Branch 1 taken 10784 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6258 times.
17051 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7488
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7489 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7491 ✗ trk->flags |= MOV_TRACK_STPS;
7492 } else {
7493 17043 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7494 }
7495
1/2
✓ Branch 0 taken 17051 times.
✗ Branch 1 not taken.
17051 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7496 17051 trk->has_keyframes++;
7497 }
7498
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 23096 times.
23103 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7499 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7500 7 trk->has_disposable++;
7501 }
7502
7503 23103 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7504
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23103 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23103 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7505 ✗ memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7506 else
7507 23103 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7508
7509 23103 trk->entry++;
7510 23103 trk->sample_count += samples_in_chunk;
7511 23103 mov->mdat_size += size;
7512
7513
3/4
✓ Branch 0 taken 23021 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
23103 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7514 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7516 : NULL, size);
7517
7518 23104 end:
7519 23104 err:
7520
7521
1/2
✓ Branch 0 taken 23104 times.
✗ Branch 1 not taken.
23104 if (pkt->data != reformatted_data)
7522 23104 av_free(reformatted_data);
7523 23104 return ret;
7524 }
7525
7526 23067 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7527 {
7528 23067 MOVMuxContext *mov = s->priv_data;
7529 23067 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7530 23067 AVCodecParameters *par = trk->par;
7531 23067 int64_t frag_duration = 0;
7532 23067 int size = pkt->size;
7533
7534 23067 int ret = check_pkt(s, trk, pkt);
7535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23067 times.
23067 if (ret < 0)
7536 ✗ return ret;
7537
7538
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 23062 times.
23067 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7539
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7540 10 mov->tracks[i].frag_discont = 1;
7541 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7542 }
7543
7544
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 21055 times.
23067 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7545
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7546 15 trk->dts_shift = pkt->pts - pkt->dts;
7547 2012 pkt->dts += trk->dts_shift;
7548 }
7549
7550
1/2
✓ Branch 0 taken 23067 times.
✗ Branch 1 not taken.
23067 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7551
2/2
✓ Branch 0 taken 14879 times.
✓ Branch 1 taken 8188 times.
23067 trk->par->codec_id == AV_CODEC_ID_AAC ||
7552
2/2
✓ Branch 0 taken 14851 times.
✓ Branch 1 taken 28 times.
14879 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7553
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 14791 times.
14851 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7554 size_t side_size;
7555 8276 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7556 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7557
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8270 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
8276 if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
7558 6 void *newextra = av_malloc(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7560 ✗ return AVERROR(ENOMEM);
7561 6 memset((uint8_t*)newextra + side_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7562 6 memcpy(newextra, side, side_size);
7563 6 av_free(trk->extradata[trk->last_stsd_index]);
7564 6 trk->extradata[trk->last_stsd_index] = newextra;
7565 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7566 }
7567 }
7568
7569
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23058 times.
23067 if (!pkt->size) {
7570
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) {
7571 4 trk->start_dts = pkt->dts;
7572
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7573 4 trk->start_cts = pkt->pts - pkt->dts;
7574 else
7575 ✗ trk->start_cts = 0;
7576 }
7577
7578 9 return 0; /* Discard 0 sized packets */
7579 }
7580
7581
4/4
✓ Branch 0 taken 22692 times.
✓ Branch 1 taken 366 times.
✓ Branch 2 taken 22668 times.
✓ Branch 3 taken 24 times.
23058 if (trk->entry && pkt->stream_index < mov->nb_streams)
7582 22668 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7583 22668 s->streams[pkt->stream_index]->time_base,
7584 22668 AV_TIME_BASE_Q);
7585
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 22797 times.
23058 if ((mov->max_fragment_duration &&
7586
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7587
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23054 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23054 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7588
2/2
✓ Branch 0 taken 4885 times.
✓ Branch 1 taken 18169 times.
23054 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7589
2/2
✓ Branch 0 taken 2311 times.
✓ Branch 1 taken 2574 times.
4885 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7590
4/4
✓ Branch 0 taken 2284 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 2234 times.
✓ Branch 3 taken 50 times.
2311 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7591
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 23003 times.
23004 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7592
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (frag_duration >= mov->min_fragment_duration) {
7593
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1 times.
55 if (trk->entry) {
7594 // Set the duration of this track to line up with the next
7595 // sample in this track. This avoids relying on AVPacket
7596 // duration, but only helps for this particular track, not
7597 // for the other ones that are flushed at the same time.
7598 //
7599 // If we have trk->entry == 0, no fragment will be written
7600 // for this track, and we can't adjust the track end here.
7601 54 trk->track_duration = pkt->dts - trk->start_dts;
7602
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (pkt->pts != AV_NOPTS_VALUE)
7603 54 trk->end_pts = pkt->pts;
7604 else
7605 ✗ trk->end_pts = pkt->dts;
7606
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7607 54 trk->elst_end_pts = trk->end_pts;
7608 54 trk->end_reliable = 1;
7609 }
7610 55 mov_auto_flush_fragment(s, 0);
7611 }
7612 }
7613
7614 23058 return ff_mov_write_packet(s, pkt);
7615 }
7616
7617 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7618 int stream_index,
7619 int64_t dts) {
7620 3 MOVMuxContext *mov = s->priv_data;
7621 3 AVPacket *end = mov->pkt;
7622 3 uint8_t data[2] = {0};
7623 int ret;
7624
7625 3 end->size = sizeof(data);
7626 3 end->data = data;
7627 3 end->pts = dts;
7628 3 end->dts = dts;
7629 3 end->duration = 0;
7630 3 end->stream_index = stream_index;
7631
7632 3 ret = mov_write_single_packet(s, end);
7633 3 av_packet_unref(end);
7634
7635 3 return ret;
7636 }
7637
7638 #if CONFIG_IAMFENC
7639 300 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7640 {
7641 uint8_t *data;
7642 int ret;
7643
7644
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 240 times.
300 if (pkt->stream_index == trk->first_iamf_idx) {
7645 60 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (ret < 0)
7647 ✗ return ret;
7648 }
7649
7650 300 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7651 300 s->streams[pkt->stream_index]->id, pkt);
7652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (ret < 0)
7653 ✗ return ret;
7654
7655
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (pkt->stream_index != trk->last_iamf_idx)
7656 240 return AVERROR(EAGAIN);
7657
7658 60 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7659 60 trk->iamf_buf = NULL;
7660
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
60 if (!ret) {
7661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7662 // Either all or none of the packets for a single
7663 // IA Sample may be empty.
7664 ✗ av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7665 "stream #%d\n", pkt->stream_index);
7666 ✗ ret = AVERROR_INVALIDDATA;
7667 }
7668 5 av_free(data);
7669 5 return ret;
7670 }
7671
7672 55 av_buffer_unref(&pkt->buf);
7673 55 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (!pkt->buf) {
7675 ✗ av_free(data);
7676 ✗ return AVERROR(ENOMEM);
7677 }
7678 55 pkt->data = data;
7679 55 pkt->size = ret;
7680 55 pkt->stream_index = trk->first_iamf_idx;
7681
7682 55 return avio_open_dyn_buf(&trk->iamf_buf);
7683 }
7684 #endif
7685
7686 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7687 {
7688 2 int64_t pos = avio_tell(pb);
7689 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7690 2 const char *value = "";
7691
7692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7693
7694 2 avio_write_marker(pb,
7695 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7696 AVIO_DATA_MARKER_BOUNDARY_POINT);
7697
7698 2 avio_wb32(pb, 0); /* size */
7699 2 ffio_wfourcc(pb, "emsg");
7700 2 avio_w8(pb, 1); /* version */
7701 2 avio_wb24(pb, 0);
7702 2 avio_wb32(pb, st->time_base.den); /* timescale */
7703 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7704 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7705 2 avio_wb32(pb, 0); /* id */
7706 /* null terminated UTF8 strings */
7707 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7708 2 avio_write(pb, value, strlen(value) + 1);
7709 2 avio_write(pb, pkt->data, pkt->size);
7710
7711 2 return update_size(pb, pos);
7712 }
7713
7714 23472 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7715 {
7716 23472 MOVMuxContext *mov = s->priv_data;
7717 MOVTrack *trk;
7718
7719
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 23428 times.
23472 if (!pkt) {
7720 44 mov_flush_fragment(s, 1);
7721 44 return 1;
7722 }
7723
7724
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23426 times.
23428 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7725 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7726 2 return 0;
7727 }
7728
7729 23426 trk = s->streams[pkt->stream_index]->priv_data;
7730
7731 #if CONFIG_IAMFENC
7732
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 23126 times.
23426 if (trk->iamf) {
7733 300 int ret = mov_build_iamf_packet(s, trk, pkt);
7734
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (ret < 0) {
7735
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if (ret == AVERROR(EAGAIN))
7736 240 return 0;
7737 ✗ av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7738 ✗ "for stream #%d\n", trk->st->index);
7739 ✗ return ret;
7740 }
7741 }
7742 #endif
7743
7744
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 23184 times.
23186 if (is_cover_image(trk->st)) {
7745 int ret;
7746
7747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7748 ✗ if (trk->st->nb_frames == 1)
7749 ✗ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7750 ✗ " ignoring.\n", pkt->stream_index);
7751 ✗ return 0;
7752 }
7753
7754
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7755 ✗ return ret;
7756
7757 2 return 0;
7758 } else {
7759 int i;
7760
7761
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23175 times.
23184 if (!pkt->size)
7762 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7763
7764 /*
7765 * Subtitles require special handling.
7766 *
7767 * 1) For full compliance, every track must have a sample at
7768 * dts == 0, which is rarely true for subtitles. So, as soon
7769 * as we see any packet with dts > 0, write an empty subtitle
7770 * at dts == 0 for any subtitle track with no samples in it.
7771 *
7772 * 2) For each subtitle track, check if the current packet's
7773 * dts is past the duration of the last subtitle sample. If
7774 * so, we now need to write an end sample for that subtitle.
7775 *
7776 * This must be done conditionally to allow for subtitles that
7777 * immediately replace each other, in which case an end sample
7778 * is not needed, and is, in fact, actively harmful.
7779 *
7780 * 3) See mov_write_trailer for how the final end sample is
7781 * handled.
7782 */
7783
2/2
✓ Branch 0 taken 39169 times.
✓ Branch 1 taken 23175 times.
62344 for (i = 0; i < mov->nb_tracks; i++) {
7784 39169 MOVTrack *trk = &mov->tracks[i];
7785 int ret;
7786
7787
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39166 times.
39169 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7788
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7789
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)) {
7790 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7791
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7792 2 trk->last_sample_is_subtitle_end = 1;
7793 }
7794 }
7795
7796
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 23027 times.
23175 if (trk->squash_fragment_samples_to_one) {
7797 /*
7798 * If the track has to have its samples squashed into one sample,
7799 * we just take it into the track's queue.
7800 * This will then be utilized as the samples get written in either
7801 * mov_flush_fragment or when the mux is finalized in
7802 * mov_write_trailer.
7803 */
7804 148 int ret = AVERROR_BUG;
7805
7806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7807 ✗ av_log(s, AV_LOG_ERROR,
7808 "Packets without a valid presentation timestamp are "
7809 "not supported with packet squashing!\n");
7810 ✗ return AVERROR(EINVAL);
7811 }
7812
7813 /* The following will reset pkt and is only allowed to be used
7814 * because we return immediately. afterwards. */
7815
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = ff_packet_list_put(&trk->squashed_packet_queue,
7816 pkt, NULL, 0)) < 0) {
7817 ✗ return ret;
7818 }
7819
7820 148 return 0;
7821 }
7822
7823
7824
4/4
✓ Branch 0 taken 7939 times.
✓ Branch 1 taken 15088 times.
✓ Branch 2 taken 3917 times.
✓ Branch 3 taken 4022 times.
23027 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7825 3917 AVPacket *opkt = pkt;
7826 int reshuffle_ret, ret;
7827
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3892 times.
3917 if (trk->is_unaligned_qt_rgb) {
7828
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;
7829 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7830 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7832 ✗ return reshuffle_ret;
7833 } else
7834 3892 reshuffle_ret = 0;
7835
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3679 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3917 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7836 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7838 ✗ goto fail;
7839
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7840 5 trk->pal_done++;
7841
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 3087 times.
3912 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7842
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7843
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7844 ✗ ret = av_packet_make_writable(pkt);
7845 ✗ if (ret < 0)
7846 ✗ goto fail;
7847 ✗ for (i = 0; i < pkt->size; i++)
7848 ✗ pkt->data[i] = ~pkt->data[i];
7849 }
7850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3917 times.
3917 if (reshuffle_ret) {
7851 ✗ ret = mov_write_single_packet(s, pkt);
7852 ✗ fail:
7853 ✗ if (reshuffle_ret)
7854 ✗ av_packet_free(&pkt);
7855 ✗ return ret;
7856 }
7857 }
7858
7859 23027 return mov_write_single_packet(s, pkt);
7860 }
7861 }
7862
7863 // QuickTime chapters involve an additional text track with the chapter names
7864 // as samples, and a tref pointing from the other tracks to the chapter one.
7865 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7866 {
7867 static const uint8_t stub_header[] = {
7868 // TextSampleEntry
7869 0x00, 0x00, 0x00, 0x01, // displayFlags
7870 0x00, 0x00, // horizontal + vertical justification
7871 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7872 // BoxRecord
7873 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7874 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7875 // StyleRecord
7876 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7877 0x00, 0x01, // fontID
7878 0x00, 0x00, // fontStyleFlags + fontSize
7879 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7880 // FontTableBox
7881 0x00, 0x00, 0x00, 0x0D, // box size
7882 'f', 't', 'a', 'b', // box atom name
7883 0x00, 0x01, // entry count
7884 // FontRecord
7885 0x00, 0x01, // font ID
7886 0x00, // font name length
7887 };
7888 1 MOVMuxContext *mov = s->priv_data;
7889 1 MOVTrack *track = &mov->tracks[tracknum];
7890 1 AVPacket *pkt = mov->pkt;
7891 int i, len;
7892 int ret;
7893
7894 1 track->mode = mov->mode;
7895 1 track->tag = MKTAG('t','e','x','t');
7896 1 track->timescale = mov->movie_timescale;
7897 1 track->par = avcodec_parameters_alloc();
7898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7899 ✗ return AVERROR(ENOMEM);
7900 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7901 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7903 ✗ return ret;
7904 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7905
7906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7907 ✗ track->stsd_count = 1;
7908 ✗ track->extradata = av_calloc(1, sizeof(*track->extradata));
7909 ✗ track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7910 ✗ if (!track->extradata || !track->extradata_size)
7911 ✗ return AVERROR(ENOMEM);
7912 }
7913
7914 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7916 ✗ return AVERROR(ENOMEM);
7917 1 track->extradata_size[0] = sizeof(stub_header);
7918
7919 1 pkt->stream_index = tracknum;
7920 1 pkt->flags = AV_PKT_FLAG_KEY;
7921
7922
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7923 4 AVChapter *c = s->chapters[i];
7924 AVDictionaryEntry *t;
7925
7926 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7927 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7928 4 pkt->duration = end - pkt->dts;
7929
7930
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7931 static const char encd[12] = {
7932 0x00, 0x00, 0x00, 0x0C,
7933 'e', 'n', 'c', 'd',
7934 0x00, 0x00, 0x01, 0x00 };
7935 4 len = strlen(t->value);
7936 4 pkt->size = len + 2 + 12;
7937 4 pkt->data = av_malloc(pkt->size);
7938
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7939 ✗ av_packet_unref(pkt);
7940 ✗ return AVERROR(ENOMEM);
7941 }
7942 4 AV_WB16(pkt->data, len);
7943 4 memcpy(pkt->data + 2, t->value, len);
7944 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7945 4 ff_mov_write_packet(s, pkt);
7946 4 av_freep(&pkt->data);
7947 }
7948 }
7949
7950 1 av_packet_unref(mov->pkt);
7951
7952 1 return 0;
7953 }
7954
7955
7956 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7957 {
7958 int ret;
7959
7960 /* compute the frame number */
7961 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7962 13 return ret;
7963 }
7964
7965 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7966 {
7967 6 MOVMuxContext *mov = s->priv_data;
7968 6 MOVTrack *track = &mov->tracks[index];
7969 6 AVStream *src_st = mov->tracks[src_index].st;
7970 uint8_t data[4];
7971 6 AVPacket *pkt = mov->pkt;
7972 6 AVRational rate = src_st->avg_frame_rate;
7973 int ret;
7974
7975 /* tmcd track based on video stream */
7976 6 track->mode = mov->mode;
7977 6 track->tag = MKTAG('t','m','c','d');
7978 6 track->src_track = av_malloc(sizeof(*track->src_track));
7979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->src_track)
7980 ✗ return AVERROR(ENOMEM);
7981 6 *track->src_track = src_index;
7982 6 track->nb_src_track = 1;
7983
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7984 3 track->timescale = tc.fps * 1000;
7985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (tc.rate.den == 1001)
7986 ✗ track->timescale = tc.rate.num;
7987 else
7988 3 track->timescale = tc.fps;
7989
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7990 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7991
7992 /* set st to src_st for metadata access*/
7993 6 track->st = src_st;
7994
7995 /* encode context: tmcd data stream */
7996 6 track->par = avcodec_parameters_alloc();
7997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7998 ✗ return AVERROR(ENOMEM);
7999 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
8000 6 track->par->codec_tag = track->tag;
8001 6 track->st->avg_frame_rate = rate;
8002
8003 /* the tmcd track just contains one packet with the frame number */
8004 6 pkt->data = data;
8005 6 pkt->stream_index = index;
8006 6 pkt->flags = AV_PKT_FLAG_KEY;
8007 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){ 1, track->timescale });
8008 6 pkt->size = 4;
8009 6 AV_WB32(pkt->data, tc.start);
8010 6 ret = ff_mov_write_packet(s, pkt);
8011 6 av_packet_unref(pkt);
8012 6 return ret;
8013 }
8014
8015 /*
8016 * st->disposition controls the "enabled" flag in the tkhd tag.
8017 * QuickTime will not play a track if it is not enabled. So make sure
8018 * that one track of each type (audio, video, subtitle) is enabled.
8019 *
8020 * Subtitles are special. For audio and video, setting "enabled" also
8021 * makes the track "default" (i.e. it is rendered when played). For
8022 * subtitles, an "enabled" subtitle is not rendered by default, but
8023 * if no subtitle is enabled, the subtitle menu in QuickTime will be
8024 * empty!
8025 */
8026 248 static void enable_tracks(AVFormatContext *s)
8027 {
8028 248 MOVMuxContext *mov = s->priv_data;
8029 int i;
8030 int enabled[AVMEDIA_TYPE_NB];
8031 int first[AVMEDIA_TYPE_NB];
8032
8033
2/2
✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 248 times.
1488 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8034 1240 enabled[i] = 0;
8035 1240 first[i] = -1;
8036 }
8037
8038
2/2
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 248 times.
558 for (i = 0; i < mov->nb_streams; i++) {
8039 310 AVStream *st = mov->tracks[i].st;
8040
8041
1/2
✓ Branch 0 taken 310 times.
✗ Branch 1 not taken.
310 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
8042
3/4
✓ Branch 0 taken 310 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 308 times.
620 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
8043 310 is_cover_image(st))
8044 2 continue;
8045
8046
2/2
✓ Branch 0 taken 293 times.
✓ Branch 1 taken 15 times.
308 if (first[st->codecpar->codec_type] < 0)
8047 293 first[st->codecpar->codec_type] = i;
8048
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 271 times.
308 if (st->disposition & AV_DISPOSITION_DEFAULT) {
8049 37 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
8050 37 enabled[st->codecpar->codec_type]++;
8051 }
8052 }
8053
8054
2/2
✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 248 times.
1488 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8055
2/2
✓ Branch 0 taken 744 times.
✓ Branch 1 taken 496 times.
1240 switch (i) {
8056 744 case AVMEDIA_TYPE_VIDEO:
8057 case AVMEDIA_TYPE_AUDIO:
8058 case AVMEDIA_TYPE_SUBTITLE:
8059
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 743 times.
744 if (enabled[i] > 1)
8060 1 mov->per_stream_grouping = 1;
8061
4/4
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 259 times.
✓ Branch 3 taken 453 times.
744 if (!enabled[i] && first[i] >= 0)
8062 259 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
8063 744 break;
8064 }
8065 }
8066 248 }
8067
8068 248 static void mov_free(AVFormatContext *s)
8069 {
8070 248 MOVMuxContext *mov = s->priv_data;
8071
8072
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 248 times.
579 for (int i = 0; i < s->nb_streams; i++)
8073 331 s->streams[i]->priv_data = NULL;
8074
8075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (!mov->tracks)
8076 ✗ return;
8077
8078
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->chapter_track) {
8079 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
8080 }
8081
8082
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 248 times.
567 for (int i = 0; i < mov->nb_tracks; i++) {
8083 319 MOVTrack *const track = &mov->tracks[i];
8084
8085
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 317 times.
319 if (track->tag == MKTAG('r','t','p',' '))
8086 2 ff_mov_close_hinting(track);
8087
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 308 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
317 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
8088 6 av_freep(&track->par);
8089 319 av_freep(&track->cluster);
8090 319 av_freep(&track->cluster_written);
8091 319 av_freep(&track->frag_info);
8092 319 av_packet_free(&track->cover_image);
8093
8094
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 309 times.
319 if (track->eac3_priv) {
8095 10 struct eac3_info *info = track->eac3_priv;
8096 10 av_packet_free(&info->pkt);
8097 10 av_freep(&track->eac3_priv);
8098 }
8099
2/2
✓ Branch 0 taken 321 times.
✓ Branch 1 taken 319 times.
640 for (int j = 0; j < track->stsd_count; j++)
8100 321 av_freep(&track->extradata[j]);
8101 319 av_freep(&track->extradata);
8102 319 av_freep(&track->extradata_size);
8103
8104
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 319 times.
329 for (int i = 0; i < track->nb_tref_tags; i++)
8105 10 av_freep(&track->tref_tags[i].id);
8106 319 av_freep(&track->tref_tags);
8107 319 av_freep(&track->src_track);
8108
8109 319 ff_mov_cenc_free(&track->cenc);
8110 319 ffio_free_dyn_buf(&track->mdat_buf);
8111
8112 #if CONFIG_IAMFENC
8113 319 ffio_free_dyn_buf(&track->iamf_buf);
8114
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 314 times.
319 if (track->iamf)
8115 5 ff_iamf_uninit_context(track->iamf);
8116 319 av_freep(&track->iamf);
8117 #endif
8118 319 ff_isom_close_apvc(&track->apv);
8119
8120 319 ff_packet_list_free(&track->squashed_packet_queue);
8121 }
8122
8123 248 av_freep(&mov->tracks);
8124 248 ffio_free_dyn_buf(&mov->mdat_buf);
8125 }
8126
8127 ✗ static uint32_t rgb_to_yuv(uint32_t rgb)
8128 {
8129 uint8_t r, g, b;
8130 int y, cb, cr;
8131
8132 ✗ r = (rgb >> 16) & 0xFF;
8133 ✗ g = (rgb >> 8) & 0xFF;
8134 ✗ b = (rgb ) & 0xFF;
8135
8136 ✗ y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
8137 ✗ cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
8138 ✗ cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
8139
8140 ✗ return (y << 16) | (cr << 8) | cb;
8141 }
8142
8143 ✗ static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
8144 AVStream *st)
8145 {
8146 ✗ int i, width = 720, height = 480;
8147 ✗ int have_palette = 0, have_size = 0;
8148 uint32_t palette[16];
8149 ✗ char *cur = st->codecpar->extradata;
8150
8151 ✗ while (cur && *cur) {
8152 ✗ if (strncmp("palette:", cur, 8) == 0) {
8153 int i, count;
8154 ✗ count = sscanf(cur + 8,
8155 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8156 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8157 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8158 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
8159 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
8160 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
8161 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
8162 &palette[12], &palette[13], &palette[14], &palette[15]);
8163
8164 ✗ for (i = 0; i < count; i++) {
8165 ✗ palette[i] = rgb_to_yuv(palette[i]);
8166 }
8167 ✗ have_palette = 1;
8168 ✗ } else if (!strncmp("size:", cur, 5)) {
8169 ✗ sscanf(cur + 5, "%dx%d", &width, &height);
8170 ✗ have_size = 1;
8171 }
8172 ✗ if (have_palette && have_size)
8173 ✗ break;
8174 ✗ cur += strcspn(cur, "\n\r");
8175 ✗ cur += strspn(cur, "\n\r");
8176 }
8177 ✗ if (have_palette) {
8178 ✗ track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
8179 ✗ if (!track->extradata[track->last_stsd_index])
8180 ✗ return AVERROR(ENOMEM);
8181 ✗ for (i = 0; i < 16; i++) {
8182 ✗ AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
8183 }
8184 ✗ memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8185 ✗ track->extradata_size[track->last_stsd_index] = 16 * 4;
8186 }
8187 ✗ st->codecpar->width = width;
8188 ✗ st->codecpar->height = track->height = height;
8189
8190 ✗ return 0;
8191 }
8192
8193 #if CONFIG_IAMFENC
8194 248 static int mov_init_iamf_track(AVFormatContext *s)
8195 {
8196 248 MOVMuxContext *mov = s->priv_data;
8197 MOVTrack *track;
8198 IAMFContext *iamf;
8199 248 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
8200 248 int nb_audio_elements = 0, nb_mix_presentations = 0;
8201 int ret;
8202
8203
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 248 times.
258 for (int i = 0; i < s->nb_stream_groups; i++) {
8204 10 const AVStreamGroup *stg = s->stream_groups[i];
8205
8206
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8207 5 nb_audio_elements++;
8208
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
8209 5 nb_mix_presentations++;
8210 }
8211
8212
3/4
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 243 times.
✗ Branch 3 not taken.
248 if (!nb_audio_elements && !nb_mix_presentations)
8213 243 return 0;
8214
8215
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) {
8216 ✗ av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
8217 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
8218 ✗ return AVERROR(EINVAL);
8219 }
8220
8221 5 iamf = av_mallocz(sizeof(*iamf));
8222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
8223 ✗ return AVERROR(ENOMEM);
8224
8225
8226
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8227 10 const AVStreamGroup *stg = s->stream_groups[i];
8228
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
8229 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
8230
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8231 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
8232 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
8233 }
8234
8235 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
8236 5 break;
8237 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
8238 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
8239 5 break;
8240 ✗ default:
8241 ✗ av_assert0(0);
8242 }
8243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
8244 ✗ ff_iamf_uninit_context(iamf);
8245 ✗ av_free(iamf);
8246 ✗ return ret;
8247 }
8248 }
8249
8250 5 track = &mov->tracks[first_iamf_idx];
8251 5 track->iamf = iamf;
8252 5 track->first_iamf_idx = first_iamf_idx;
8253 5 track->last_iamf_idx = last_iamf_idx;
8254 5 track->tag = MKTAG('i','a','m','f');
8255
8256
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8257 10 AVStreamGroup *stg = s->stream_groups[i];
8258
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8259 5 continue;
8260
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
8261 25 stg->streams[j]->priv_data = track;
8262 }
8263
8264 5 ret = avio_open_dyn_buf(&track->iamf_buf);
8265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
8266 ✗ return ret;
8267
8268 5 return 0;
8269 }
8270 #endif
8271
8272 248 static int mov_init(AVFormatContext *s)
8273 {
8274 248 MOVMuxContext *mov = s->priv_data;
8275 248 int has_iamf = 0;
8276 int i, ret;
8277
8278 248 mov->fc = s;
8279 248 mov->pkt = ffformatcontext(s)->pkt;
8280
8281 /* Default mode == MP4 */
8282 248 mov->mode = MODE_MP4;
8283
8284 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
8285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
8286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
8287
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 97 times.
248 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
8288
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
8289
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
8290
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 90 times.
95 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
8291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
8292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
8293 #undef IS_MODE
8294
8295
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 228 times.
248 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
8296 20 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
8297
8298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (mov->mode == MODE_AVIF)
8299 ✗ mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
8300
8301 /* Set the FRAGMENT flag if any of the fragmentation methods are
8302 * enabled. */
8303
3/4
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
248 if (mov->max_fragment_duration || mov->max_fragment_size ||
8304
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 212 times.
246 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
8305 FF_MOV_FLAG_FRAG_KEYFRAME |
8306 FF_MOV_FLAG_FRAG_CUSTOM |
8307 FF_MOV_FLAG_FRAG_EVERY_FRAME))
8308 36 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8309
8310
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 246 times.
248 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
8311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
8312 ✗ av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
8313 ✗ return AVERROR(EINVAL);
8314 }
8315
8316 /* Set other implicit flags immediately */
8317
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 246 times.
248 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8318 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8319
8320
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 243 times.
248 if (mov->mode == MODE_ISM)
8321 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
8322 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8323
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 234 times.
248 if (mov->flags & FF_MOV_FLAG_DASH)
8324 14 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8325 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
8326
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 246 times.
248 if (mov->flags & FF_MOV_FLAG_CMAF)
8327 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8328 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8329
8330
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 211 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 3 times.
248 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
8331 34 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
8332 34 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
8333 }
8334
8335
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
248 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
8336 ✗ av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
8337 ✗ mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
8338 }
8339
8340
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 245 times.
248 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8341 3 mov->reserved_moov_size = -1;
8342 }
8343
8344
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 7 times.
248 if (mov->use_editlist < 0) {
8345 241 mov->use_editlist = 1;
8346
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 206 times.
241 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8347
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 18 times.
35 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8348 // If we can avoid needing an edit list by shifting the
8349 // tracks, prefer that over (trying to) write edit lists
8350 // in fragmented output.
8351
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
8352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
8353 16 mov->use_editlist = 0;
8354 }
8355 }
8356
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 211 times.
248 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8357
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
8358 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
8359
8360
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
248 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist)
8361 ✗ mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8362
8363
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 226 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 1 times.
248 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
8364
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
21 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
8365 13 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
8366
8367 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
8368 * if the latter is set that's enough and omit_tfhd_offset doesn't
8369 * add anything extra on top of that. */
8370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
8371 ✗ mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
8372 ✗ mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
8373
8374
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->frag_interleave &&
8375
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)) {
8376 ✗ av_log(s, AV_LOG_ERROR,
8377 "Sample interleaving in fragments is mutually exclusive with "
8378 "omit_tfhd_offset and separate_moof\n");
8379 ✗ return AVERROR(EINVAL);
8380 }
8381
8382 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8383 * is enabled, we don't support non-seekable output at all. */
8384
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 219 times.
248 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
8385
2/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
8386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 mov->mode == MODE_AVIF)) {
8387 ✗ av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
8388 ✗ return AVERROR(EINVAL);
8389 }
8390
8391 /* AVIF output must have at most two video streams (one for YUV and one for
8392 * alpha). */
8393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (mov->mode == MODE_AVIF) {
8394 ✗ if (s->nb_streams > 2) {
8395 ✗ av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
8396 ✗ return AVERROR(EINVAL);
8397 }
8398 ✗ if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
8399 ✗ (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
8400 ✗ av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
8401 ✗ return AVERROR(EINVAL);
8402 }
8403 ✗ if (s->nb_streams > 1) {
8404 const AVPixFmtDescriptor *pixdesc =
8405 ✗ av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
8406 ✗ if (pixdesc->nb_components != 1) {
8407 ✗ av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8408 ✗ return AVERROR(EINVAL);
8409 }
8410 }
8411 ✗ s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
8412 }
8413
8414
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 248 times.
258 for (i = 0; i < s->nb_stream_groups; i++) {
8415 10 AVStreamGroup *stg = s->stream_groups[i];
8416
8417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_LCEVC) {
8418 ✗ if (stg->nb_streams != 2) {
8419 ✗ av_log(s, AV_LOG_ERROR, "Exactly two Streams are supported for Stream Groups of type LCEVC\n");
8420 ✗ return AVERROR(EINVAL);
8421 }
8422 ✗ AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8423 ✗ if (lcevc->el_index > 1)
8424 ✗ return AVERROR(EINVAL);
8425 ✗ AVStream *st = stg->streams[lcevc->el_index];
8426 ✗ if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) {
8427 ✗ av_log(s, AV_LOG_ERROR, "Stream #%u is not an LCEVC stream\n", lcevc->el_index);
8428 ✗ return AVERROR(EINVAL);
8429 }
8430 }
8431
8432 #if CONFIG_IAMFENC
8433
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8434 5 continue;
8435
8436
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8437 25 AVStream *st = stg->streams[j];
8438
8439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8440 ✗ av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8441 "IAMF Audio Element\n", j);
8442 ✗ return AVERROR(EINVAL);
8443 }
8444 25 st->priv_data = st;
8445 }
8446 5 has_iamf = 1;
8447
8448
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
8449 5 mov->nb_tracks++;
8450 #endif
8451 }
8452
8453
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 248 times.
579 for (i = 0; i < s->nb_streams; i++) {
8454 331 AVStream *st = s->streams[i];
8455
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 306 times.
331 if (st->priv_data)
8456 25 continue;
8457 // Don't produce a track in the output file for timed ID3 streams.
8458
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 305 times.
306 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8459 // Leave priv_data set to NULL for these AVStreams that don't
8460 // have a corresponding track.
8461 1 continue;
8462 }
8463 305 st->priv_data = st;
8464 305 mov->nb_tracks++;
8465 }
8466
8467 248 mov->nb_streams = mov->nb_tracks;
8468
8469
4/4
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 241 times.
248 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8470 1 mov->chapter_track = mov->nb_tracks++;
8471
8472
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8473
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8474
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8475 2 mov->nb_tracks++;
8476 }
8477
8478
1/2
✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
248 if (mov->write_btrt < 0) {
8479 248 mov->write_btrt = mov->mode == MODE_MP4;
8480 }
8481
8482
6/6
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 94 times.
✓ Branch 3 taken 151 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 90 times.
248 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8483
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8484 244 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8485 NULL, 0);
8486
8487 /* +1 tmcd track for each video stream with a timecode */
8488
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 244 times.
568 for (i = 0; i < s->nb_streams; i++) {
8489 324 AVStream *st = s->streams[i];
8490 324 AVDictionaryEntry *t = global_tcr;
8491
4/4
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 6 times.
324 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8492
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 193 times.
194 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8493 AVTimecode tc;
8494 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8495
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8496 7 mov->nb_meta_tmcd++;
8497 }
8498 }
8499
8500 /* check if there is already a tmcd track to remux */
8501
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 237 times.
244 if (mov->nb_meta_tmcd) {
8502
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8503 13 AVStream *st = s->streams[i];
8504
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8505 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8506 "so timecode metadata are now ignored\n");
8507 3 mov->nb_meta_tmcd = 0;
8508 }
8509 }
8510 }
8511
8512 244 mov->nb_tracks += mov->nb_meta_tmcd;
8513 }
8514
8515 // Reserve an extra stream for chapters for the case where chapters
8516 // are written in the trailer
8517 248 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (!mov->tracks)
8519 ✗ return AVERROR(ENOMEM);
8520
8521
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 248 times.
567 for (i = 0; i < mov->nb_tracks; i++) {
8522 319 MOVTrack *track = &mov->tracks[i];
8523
8524 319 track->stsd_count = 1;
8525 319 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8526 319 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8527
2/4
✓ Branch 0 taken 319 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 319 times.
319 if (!track->extradata || !track->extradata_size)
8528 ✗ return AVERROR(ENOMEM);
8529 }
8530
8531
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
248 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8532
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8533 5 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8534
8535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8536 ✗ av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8537 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8538 ✗ return AVERROR(EINVAL);
8539 }
8540
8541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8542 ✗ av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8543 mov->encryption_kid_len, CENC_KID_SIZE);
8544 ✗ return AVERROR(EINVAL);
8545 }
8546 } else {
8547 ✗ av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8548 mov->encryption_scheme_str);
8549 ✗ return AVERROR(EINVAL);
8550 }
8551 }
8552
8553 #if CONFIG_IAMFENC
8554 248 ret = mov_init_iamf_track(s);
8555
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (ret < 0)
8556 ✗ return ret;
8557 #endif
8558
8559
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 248 times.
579 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8560 331 AVStream *st = s->streams[j];
8561
8562
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 305 times.
331 if (st != st->priv_data) {
8563
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8564 5 i += has_iamf--;
8565 26 continue;
8566 }
8567 305 st->priv_data = &mov->tracks[i++];
8568 }
8569
8570 248 AVRational movie_timescale = (AVRational) { 0, 1 };
8571
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 248 times.
579 for (i = 0; i < s->nb_streams; i++) {
8572 331 AVStream *st= s->streams[i];
8573 331 MOVTrack *track = st->priv_data;
8574
8575
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 330 times.
331 if (!track)
8576 1 continue;
8577
8578
2/2
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 20 times.
330 if (!track->st) {
8579 310 track->st = st;
8580 310 track->par = st->codecpar;
8581 }
8582
8583 330 movie_timescale = av_gcd_q(movie_timescale, st->time_base, INT_MAX, (AVRational){1,0});
8584 }
8585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (!movie_timescale.den)
8586 ✗ movie_timescale = MOV_TIMESCALE_Q;
8587
8588
1/2
✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
248 if (!mov->movie_timescale)
8589 248 mov->movie_timescale = FFMAX(movie_timescale.den, MOV_TIMESCALE);
8590
8591
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 248 times.
579 for (i = 0; i < s->nb_streams; i++) {
8592 331 AVStream *st= s->streams[i];
8593 331 MOVTrack *track = st->priv_data;
8594 331 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8595
8596
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 330 times.
331 if (!track)
8597 1 continue;
8598
8599
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 299 times.
330 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8600
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 172 times.
330 if (track->language < 0)
8601 158 track->language = 32767; // Unspecified Macintosh language code
8602 330 track->mode = mov->mode;
8603
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 25 times.
330 if (!track->tag)
8604 305 track->tag = mov_find_codec_tag(s, track);
8605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
330 if (!track->tag) {
8606 ✗ av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8607 "codec not currently supported in container\n",
8608 ✗ avcodec_get_name(st->codecpar->codec_id), i);
8609 ✗ return AVERROR(EINVAL);
8610 }
8611 /* If hinting of this track is enabled by a later hint track,
8612 * this is updated. */
8613 330 track->hint_track = -1;
8614 330 track->start_dts = AV_NOPTS_VALUE;
8615 330 track->start_cts = AV_NOPTS_VALUE;
8616 330 track->end_pts = AV_NOPTS_VALUE;
8617 330 track->dts_shift = AV_NOPTS_VALUE;
8618
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 127 times.
330 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8619
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
203 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8620
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
203 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8621
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
203 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8622 ✗ if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8623 ✗ av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8624 ✗ return AVERROR(EINVAL);
8625 }
8626 ✗ track->height = track->tag >> 24 == 'n' ? 486 : 576;
8627 }
8628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 if (mov->video_track_timescale) {
8629 ✗ track->timescale = mov->video_track_timescale;
8630 ✗ if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8631 ✗ av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8632 } else {
8633 203 track->timescale = st->time_base.den;
8634
2/2
✓ Branch 0 taken 1594 times.
✓ Branch 1 taken 203 times.
1797 while(track->timescale < 10000)
8635 1594 track->timescale *= 2;
8636 }
8637
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
203 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8638 ✗ av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8639 ✗ return AVERROR(EINVAL);
8640 }
8641
4/4
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 131 times.
203 if (track->mode == MODE_MOV && track->timescale > 100000)
8642 5 av_log(s, AV_LOG_WARNING,
8643 "WARNING codec timebase is very high. If duration is too long,\n"
8644 "file may not be playable by quicktime. Specify a shorter timebase\n"
8645 "or choose different container.\n");
8646
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 67 times.
203 if (track->mode == MODE_MOV &&
8647
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 119 times.
136 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8648
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8649 1 enum AVPixelFormat pix_fmt = track->par->format;
8650
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)
8651 ✗ pix_fmt = AV_PIX_FMT_MONOWHITE;
8652 1 track->is_unaligned_qt_rgb =
8653 ✗ pix_fmt == AV_PIX_FMT_RGB24 ||
8654 ✗ pix_fmt == AV_PIX_FMT_BGR24 ||
8655 ✗ pix_fmt == AV_PIX_FMT_PAL8 ||
8656 ✗ pix_fmt == AV_PIX_FMT_GRAY8 ||
8657
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 ||
8658 pix_fmt == AV_PIX_FMT_MONOBLACK;
8659 }
8660
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
203 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8661 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8662 ✗ return AVERROR(EINVAL);
8663
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 201 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8664
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8665 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8666 ✗ return AVERROR(EINVAL);
8667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8668 /* altref frames handling is not defined in the spec as of version v1.0,
8669 * so just forbid muxing VP8 streams altogether until a new version does */
8670 ✗ av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8671 ✗ return AVERROR_PATCHWELCOME;
8672
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 202 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8673 1 ret = ff_isom_init_apvc(&track->apv, s);
8674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8675 ✗ return ret;
8676 }
8677
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 201 times.
203 if (is_cover_image(st)) {
8678 2 track->cover_image = av_packet_alloc();
8679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8680 ✗ return AVERROR(ENOMEM);
8681 }
8682
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 9 times.
127 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8683 118 track->timescale = st->codecpar->sample_rate;
8684
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 84 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 26 times.
118 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8685 8 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8686 8 track->audio_vbr = 1;
8687
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8688
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8690 ✗ if (!st->codecpar->block_align) {
8691 ✗ av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8692 ✗ return AVERROR(EINVAL);
8693 }
8694 ✗ track->sample_size = st->codecpar->block_align;
8695
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 26 times.
110 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8696 84 track->audio_vbr = 1;
8697 }else{
8698 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8699 26 st->codecpar->ch_layout.nb_channels;
8700 }
8701
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8703 ✗ track->audio_vbr = 1;
8704 }
8705
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 31 times.
118 if (track->mode != MODE_MOV &&
8706
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
87 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8707 ✗ if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8708 ✗ av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8709 ✗ i, track->par->sample_rate);
8710 ✗ return AVERROR(EINVAL);
8711 } else {
8712 ✗ av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8713 ✗ i, track->par->sample_rate);
8714 }
8715 }
8716
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 25 times.
118 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8717
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
93 track->par->codec_id == AV_CODEC_ID_OPUS) {
8719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8720 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8721 ✗ return AVERROR(EINVAL);
8722 }
8723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8724 ✗ s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8725 ✗ av_log(s, AV_LOG_ERROR,
8726 "%s in MP4 support is experimental, add "
8727 "'-strict %d' if you want to use it.\n",
8728 ✗ avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8729 ✗ return AVERROR_EXPERIMENTAL;
8730 }
8731 }
8732
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8733 5 track->timescale = st->time_base.den;
8734
8735
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8736 /* 14496-30 requires us to use a single sample per fragment
8737 for TTML, for which we define a per-track flag.
8738
8739 We set the flag in case we are receiving TTML paragraphs
8740 from the input, in other words in case we are not doing
8741 stream copy. */
8742 4 track->squash_fragment_samples_to_one =
8743 4 ff_is_ttml_stream_paragraph_based(track->par);
8744
8745
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8746
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8748 ✗ av_log(s, AV_LOG_ERROR,
8749 "ISMV style TTML support with the 'dfxp' tag in "
8750 "non-ISMV formats is not officially supported. Add "
8751 "'-strict unofficial' if you want to use it.\n");
8752 ✗ return AVERROR_EXPERIMENTAL;
8753 }
8754 }
8755
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8756 4 track->timescale = st->time_base.den;
8757
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->tag == MKTAG('t','m','c','d') &&
8758
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->extradata_size >= 8)
8759 3 track->timecode_flags = AV_RB32(st->codecpar->extradata + 4);
8760 } else {
8761 ✗ track->timescale = mov->movie_timescale;
8762 }
8763
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
330 if (!track->height)
8764 330 track->height = st->codecpar->height;
8765 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8766 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8767 for video tracks, so if user-set, it isn't overwritten */
8768
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 323 times.
330 if (mov->mode == MODE_ISM &&
8769
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8770
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !mov->video_track_timescale))) {
8771 7 track->timescale = 10000000;
8772 }
8773
8774 330 avpriv_set_pts_info(st, 64, 1, track->timescale);
8775
8776
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 325 times.
330 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8777 5 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8778
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8779
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8780
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8781
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret)
8782 ✗ return ret;
8783 }
8784 }
8785
8786
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 248 times.
258 for (i = 0; i < s->nb_stream_groups; i++) {
8787 10 AVStreamGroup *stg = s->stream_groups[i];
8788
8789
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 switch (stg->type) {
8790 ✗ case AV_STREAM_GROUP_PARAMS_LCEVC: {
8791 ✗ AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8792 ✗ AVStream *st = stg->streams[lcevc->el_index];
8793 ✗ MOVTrack *track = st->priv_data;
8794
8795 ✗ for (int j = 0; j < mov->nb_tracks; j++) {
8796 ✗ MOVTrack *trk = &mov->tracks[j];
8797
8798 ✗ if (trk->st == stg->streams[!lcevc->el_index]) {
8799 ✗ track->src_track = av_malloc(sizeof(*track->src_track));
8800 ✗ if (!track->src_track)
8801 ✗ return AVERROR(ENOMEM);
8802 ✗ *track->src_track = j;
8803 ✗ track->nb_src_track = 1;
8804 ✗ break;
8805 }
8806 }
8807
8808 ✗ track->par->width = lcevc->width;
8809 ✗ track->par->height = track->height = lcevc->height;
8810 ✗ break;
8811 }
8812 ✗ case AV_STREAM_GROUP_PARAMS_TREF: {
8813 ✗ const AVStreamGroupTREF *tref = stg->params.tref;
8814 MOVTrack *track;
8815
8816 ✗ if (tref->metadata_index >= stg->nb_streams)
8817 ✗ return AVERROR(EINVAL);
8818
8819 ✗ track = stg->streams[tref->metadata_index]->priv_data;
8820 ✗ for (int j = 0; j < stg->nb_streams; j++) {
8821 ✗ const AVStream *st2 = stg->streams[j];
8822 ✗ int index = -1;
8823
8824 ✗ if (j == tref->metadata_index)
8825 ✗ continue;
8826
8827 ✗ for (int k = 0; k < mov->nb_tracks; k++) {
8828 ✗ if (mov->tracks[k].st != st2)
8829 ✗ continue;
8830 ✗ index = k;
8831 ✗ break;
8832 }
8833 ✗ if (index < 0)
8834 ✗ return AVERROR(EINVAL);
8835
8836 ✗ int *tmp = av_realloc(track->src_track,
8837 ✗ (track->nb_src_track + 1) * sizeof(*track->src_track));
8838 ✗ if (!tmp)
8839 ✗ return AVERROR(ENOMEM);
8840 ✗ track->src_track = tmp;
8841 ✗ track->src_track[track->nb_src_track++] = index;
8842 }
8843 ✗ break;
8844 }
8845 10 default:
8846 10 break;
8847 }
8848 }
8849
8850 /* fill src_track for tmcd tracks not covered by stream groups or
8851 * created by this muxer, retaining the old behavior of src_track
8852 * being arbitrarily 0. */
8853
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 248 times.
579 for (i = 0; i < s->nb_streams; i++) {
8854 331 AVStream *st = s->streams[i];
8855 331 MOVTrack *track = st->priv_data;
8856
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 328 times.
331 if (st->codecpar->codec_tag != MKTAG('t','m','c','d') ||
8857
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 track->nb_src_track)
8858 328 continue;
8859
8860 3 track->src_track = av_malloc(sizeof(*track->src_track));
8861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!track->src_track)
8862 ✗ return AVERROR(ENOMEM);
8863 3 *track->src_track = 0;
8864 3 track->nb_src_track = 1;
8865 }
8866
8867 248 enable_tracks(s);
8868 248 return 0;
8869 }
8870
8871 248 static int mov_write_header(AVFormatContext *s)
8872 {
8873 248 AVIOContext *pb = s->pb;
8874 248 MOVMuxContext *mov = s->priv_data;
8875 248 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8876
8877
4/4
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 241 times.
248 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8878 1 nb_tracks++;
8879
8880
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8881 1 hint_track = nb_tracks;
8882
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8883
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8884 2 nb_tracks++;
8885 }
8886 }
8887
8888
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 242 times.
248 if (mov->nb_meta_tmcd)
8889 6 tmcd_track = nb_tracks;
8890
8891
2/2
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 248 times.
558 for (int i = 0; i < mov->nb_streams; i++) {
8892 310 MOVTrack *track = &mov->tracks[i];
8893 310 AVStream *st = track->st;
8894
8895 /* copy extradata if it exists */
8896
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 164 times.
310 if (st->codecpar->extradata_size) {
8897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
146 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8898 ✗ mov_create_dvd_sub_decoder_specific_info(track, st);
8899
15/30
✓ Branch 0 taken 146 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 146 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 146 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 146 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 146 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 146 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 146 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 146 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 146 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 146 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 146 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 146 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 146 times.
✗ Branch 29 not taken.
146 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8900 146 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8901 292 track->extradata[track->last_stsd_index] =
8902 146 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
146 if (!track->extradata[track->last_stsd_index]) {
8904 ✗ return AVERROR(ENOMEM);
8905 }
8906 146 memcpy(track->extradata[track->last_stsd_index],
8907 146 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8908 146 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8909 0, AV_INPUT_BUFFER_PADDING_SIZE);
8910 }
8911 }
8912
8913
4/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 14 times.
408 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8914 98 av_channel_layout_compare(&track->par->ch_layout,
8915 98 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8916 296 continue;
8917
8918
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
46 for (int j = 0; j < mov->nb_streams; j++) {
8919 32 AVStream *stj= mov->tracks[j].st;
8920 32 MOVTrack *trackj= &mov->tracks[j];
8921
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 18 times.
32 if (j == i)
8922 14 continue;
8923
8924
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
18 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8925
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 ||
8926 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8927 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8928 )
8929 4 track->mono_as_fc = -1;
8930
8931
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
29 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8932 11 av_channel_layout_compare(&trackj->par->ch_layout,
8933 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8934
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
8935 )
8936 7 track->mono_as_fc++;
8937
8938
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
29 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8939 11 av_channel_layout_compare(&trackj->par->ch_layout,
8940 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8941 ✗ trackj->language != track->language ||
8942 ✗ trackj->tag != track->tag
8943 )
8944 18 continue;
8945 ✗ track->multichannel_as_mono++;
8946 }
8947 }
8948
8949
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 228 times.
248 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8951
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 228 times.
228 if ((ret = mov_write_identification(pb, s)) < 0)
8952 ✗ return ret;
8953 }
8954
8955
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 245 times.
248 if (mov->reserved_moov_size){
8956 3 mov->reserved_header_pos = avio_tell(pb);
8957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8958 ✗ avio_skip(pb, mov->reserved_moov_size);
8959 }
8960
8961
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 206 times.
248 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8962 /* If no fragmentation options have been set, set a default. */
8963
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 35 times.
42 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8964 FF_MOV_FLAG_FRAG_CUSTOM |
8965 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8966
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
7 !mov->max_fragment_duration && !mov->max_fragment_size)
8967 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8968
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8969 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8970
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8971 2 mov->mdat_pos = avio_tell(pb);
8972 // The free/wide header that later will be converted into an
8973 // mdat, covering the initial moov and all the fragments.
8974 2 avio_wb32(pb, 0);
8975
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8976 // Write an ftyp atom, hidden in a free/wide. This is neither
8977 // exposed while the file is written, as fragmented, nor when the
8978 // file is finalized into non-fragmented form. However, this allows
8979 // accessing a pristine, sequential ftyp+moov init segment, even
8980 // after the file is finalized. It also allows dumping the whole
8981 // contents of the mdat box, to get the fragmented form of the
8982 // file.
8983
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_identification(pb, s)) < 0)
8984 ✗ return ret;
8985 2 update_size(pb, mov->mdat_pos);
8986 }
8987
1/2
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
206 } else if (mov->mode != MODE_AVIF) {
8988
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 203 times.
206 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8989 3 mov->reserved_header_pos = avio_tell(pb);
8990 206 mov_write_mdat_tag(pb, mov);
8991 }
8992
8993 248 ff_parse_creation_time_metadata(s, &mov->time, 1);
8994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (mov->time)
8995 ✗ mov->time += 0x7C25B080; // 1970 based -> 1904 based
8996
8997
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->chapter_track)
8998
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8999 ✗ return ret;
9000
9001
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
248 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
9002
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
9003
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
9004
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
9005 ✗ return ret;
9006 2 hint_track++;
9007 }
9008 }
9009 }
9010
9011
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 242 times.
248 if (mov->nb_meta_tmcd) {
9012 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
9013 "timecode", NULL, 0);
9014 /* Initialize the tmcd tracks */
9015
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
9016 8 AVStream *st = mov->tracks[i].st;
9017 8 t = global_tcr;
9018
9019
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
9020 AVTimecode tc;
9021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
9022 ✗ t = av_dict_get(st->metadata, "timecode", NULL, 0);
9023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
9024 ✗ continue;
9025
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
9026 ✗ continue;
9027
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
9028 ✗ return ret;
9029 6 tmcd_track++;
9030 }
9031 }
9032 }
9033
9034 248 avio_flush(pb);
9035
9036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (mov->flags & FF_MOV_FLAG_ISML)
9037 ✗ mov_write_isml_manifest(pb, mov, s);
9038
9039
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 211 times.
248 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
9040
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 20 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
9041
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9042 ✗ return ret;
9043 17 mov->moov_written = 1;
9044
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
9045 ✗ mov->reserved_header_pos = avio_tell(pb);
9046 }
9047
9048 248 return 0;
9049 }
9050
9051 31 static int get_moov_size(AVFormatContext *s)
9052 {
9053 int ret;
9054 AVIOContext *moov_buf;
9055 31 MOVMuxContext *mov = s->priv_data;
9056
9057
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
9058 ✗ return ret;
9059
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
9060 ✗ return ret;
9061 31 return ffio_close_null_buf(moov_buf);
9062 }
9063
9064 ✗ static int get_sidx_size(AVFormatContext *s)
9065 {
9066 int ret;
9067 AVIOContext *buf;
9068 ✗ MOVMuxContext *mov = s->priv_data;
9069
9070 ✗ if ((ret = ffio_open_null_buf(&buf)) < 0)
9071 ✗ return ret;
9072 ✗ mov_write_sidx_tags(buf, mov, -1, 0);
9073 ✗ return ffio_close_null_buf(buf);
9074 }
9075
9076 /*
9077 * This function gets the moov size if moved to the top of the file: the chunk
9078 * offset table can switch between stco (32-bit entries) to co64 (64-bit
9079 * entries) when the moov is moved to the beginning, so the size of the moov
9080 * would change. It also updates the chunk offset tables.
9081 */
9082 3 static int compute_moov_size(AVFormatContext *s)
9083 {
9084 int i, moov_size, moov_size2;
9085 3 MOVMuxContext *mov = s->priv_data;
9086
9087 3 moov_size = get_moov_size(s);
9088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9089 ✗ return moov_size;
9090
9091
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
9092 8 mov->tracks[i].data_offset += moov_size;
9093
9094 3 moov_size2 = get_moov_size(s);
9095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
9096 ✗ return moov_size2;
9097
9098 /* if the size changed, we just switched from stco to co64 and need to
9099 * update the offsets */
9100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
9101 ✗ for (i = 0; i < mov->nb_tracks; i++)
9102 ✗ mov->tracks[i].data_offset += moov_size2 - moov_size;
9103
9104 3 return moov_size2;
9105 }
9106
9107 ✗ static int compute_sidx_size(AVFormatContext *s)
9108 {
9109 int i, sidx_size;
9110 ✗ MOVMuxContext *mov = s->priv_data;
9111
9112 ✗ sidx_size = get_sidx_size(s);
9113 ✗ if (sidx_size < 0)
9114 ✗ return sidx_size;
9115
9116 ✗ for (i = 0; i < mov->nb_tracks; i++)
9117 ✗ mov->tracks[i].data_offset += sidx_size;
9118
9119 ✗ return sidx_size;
9120 }
9121
9122 3 static int shift_data(AVFormatContext *s)
9123 {
9124 int moov_size;
9125 3 MOVMuxContext *mov = s->priv_data;
9126
9127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
9128 ✗ moov_size = compute_sidx_size(s);
9129 else
9130 3 moov_size = compute_moov_size(s);
9131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9132 ✗ return moov_size;
9133
9134 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
9135 }
9136
9137 208 static void mov_write_mdat_size(AVFormatContext *s)
9138 {
9139 208 MOVMuxContext *mov = s->priv_data;
9140 208 AVIOContext *pb = s->pb;
9141
9142 /* Write size of mdat tag */
9143
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 if (mov->mdat_size + 8 <= UINT32_MAX) {
9144 208 avio_seek(pb, mov->mdat_pos, SEEK_SET);
9145 208 avio_wb32(pb, mov->mdat_size + 8);
9146
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 206 times.
208 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
9147 2 ffio_wfourcc(pb, "mdat"); // overwrite the original free/wide into a mdat
9148 } else {
9149 /* overwrite 'wide' placeholder atom */
9150 ✗ avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
9151 /* special value: real atom size will be 64 bit value after
9152 * tag field */
9153 ✗ avio_wb32(pb, 1);
9154 ✗ ffio_wfourcc(pb, "mdat");
9155 ✗ avio_wb64(pb, mov->mdat_size + 16);
9156 }
9157 208 }
9158
9159 248 static int mov_write_trailer(AVFormatContext *s)
9160 {
9161 248 MOVMuxContext *mov = s->priv_data;
9162 248 AVIOContext *pb = s->pb;
9163 248 int res = 0;
9164 int i;
9165 int64_t moov_pos;
9166
9167 /*
9168 * Before actually writing the trailer, make sure that there are no
9169 * dangling subtitles, that need a terminating sample.
9170 */
9171
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 248 times.
567 for (i = 0; i < mov->nb_tracks; i++) {
9172 319 MOVTrack *trk = &mov->tracks[i];
9173
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 318 times.
319 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
9174
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
9175 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
9176 1 trk->last_sample_is_subtitle_end = 1;
9177 }
9178 }
9179
9180 //Also check for a buffered EAC3 packet
9181
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 248 times.
567 for (i = 0; i < mov->nb_tracks; i++) {
9182 319 MOVTrack *trk = &mov->tracks[i];
9183
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 4 times.
319 if (trk->par->codec_id != AV_CODEC_ID_EAC3)
9184 315 continue;
9185 4 struct eac3_info *info = trk->eac3_priv;
9186
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 if (!info || !info->pkt || !info->pkt->size)
9187 4 continue;
9188
9189 ✗ av_packet_move_ref(mov->pkt, info->pkt);
9190 ✗ info->eof = 1;
9191 ✗ res = mov_write_single_packet(s, mov->pkt);
9192 ✗ if (res < 0)
9193 ✗ return res;
9194
9195 ✗ av_packet_unref(mov->pkt);
9196 }
9197
9198 // Check if we have any tracks that require squashing.
9199 // In that case, we'll have to write the packet here.
9200
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
248 if ((res = mov_write_squashed_packets(s)) < 0)
9201 ✗ return res;
9202
9203 // If there were no chapters when the header was written, but there
9204 // are chapters now, write them in the trailer. This only works
9205 // when we are not doing fragments.
9206
4/4
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 205 times.
✓ Branch 3 taken 42 times.
248 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
9207
3/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
205 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
9208 ✗ mov->chapter_track = mov->nb_tracks++;
9209 ✗ if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9210 ✗ return res;
9211 }
9212 }
9213
9214
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 206 times.
248 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
9215
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9216
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 206 times.
208 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9217 2 mov_auto_flush_fragment(s, 1);
9218 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
9219
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
9220 4 MOVTrack *track = &mov->tracks[i];
9221 4 track->data_offset = 0;
9222 4 av_free(track->cluster);
9223 4 track->cluster = track->cluster_written;
9224 4 track->entry = track->entry_written;
9225 4 track->cluster_written = NULL;
9226 4 track->entry_written = 0;
9227 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
9228 }
9229 // Clear the empty_moov flag, as we do want the moov to include
9230 // all the samples at this point.
9231 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
9232 }
9233
9234 208 moov_pos = avio_tell(pb);
9235
9236
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 2 times.
208 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
9237 206 mov_write_mdat_size(s);
9238
9239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
9240
9241
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 205 times.
208 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
9242 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
9243 3 res = shift_data(s);
9244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
9245 ✗ return res;
9246 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9247
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9248 ✗ return res;
9249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 } else if (mov->reserved_moov_size > 0) {
9250 int64_t size;
9251 ✗ if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9252 ✗ return res;
9253 ✗ size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
9254 ✗ if (size < 8){
9255 ✗ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
9256 ✗ return AVERROR(EINVAL);
9257 }
9258 ✗ avio_wb32(pb, size);
9259 ✗ ffio_wfourcc(pb, "free");
9260 ✗ ffio_fill(pb, 0, size - 8);
9261 ✗ avio_seek(pb, moov_pos, SEEK_SET);
9262 } else {
9263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 205 times.
205 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9264 ✗ return res;
9265 }
9266
9267
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 206 times.
208 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9268 // With hybrid fragmentation, only write the mdat size (hiding
9269 // the original moov and all the fragments within the mdat)
9270 // after we've successfully written the complete moov, to avoid
9271 // risk for an unreadable file if writing the final moov fails.
9272 2 mov_write_mdat_size(s);
9273 }
9274
9275 208 res = 0;
9276 } else {
9277 40 mov_auto_flush_fragment(s, 1);
9278
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 40 times.
113 for (i = 0; i < mov->nb_tracks; i++)
9279 73 mov->tracks[i].data_offset = 0;
9280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
9281 int64_t end;
9282 ✗ av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
9283 ✗ res = shift_data(s);
9284 ✗ if (res < 0)
9285 ✗ return res;
9286 ✗ end = avio_tell(pb);
9287 ✗ avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9288 ✗ mov_write_sidx_tags(pb, mov, -1, 0);
9289 ✗ avio_seek(pb, end, SEEK_SET);
9290 }
9291
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1 times.
40 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
9292 39 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
9293 39 res = mov_write_mfra_tag(pb, mov);
9294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (res < 0)
9295 ✗ return res;
9296 }
9297 }
9298
9299 248 return res;
9300 }
9301
9302 264 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
9303 const AVPacket *pkt)
9304 {
9305 264 int ret = 1;
9306
9307
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 247 times.
264 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
9308
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
9309 ✗ ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
9310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
9311 ✗ ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
9312 }
9313
9314 264 return ret;
9315 }
9316
9317 #if CONFIG_AVIF_MUXER
9318 ✗ static int avif_write_trailer(AVFormatContext *s)
9319 {
9320 ✗ AVIOContext *pb = s->pb;
9321 ✗ MOVMuxContext *mov = s->priv_data;
9322 int64_t pos_backup, extent_offsets[2];
9323 uint8_t *buf;
9324 int buf_size, moov_size;
9325
9326 ✗ if (mov->moov_written) return 0;
9327
9328 ✗ mov->is_animated_avif = s->streams[0]->nb_frames > 1;
9329 ✗ if (mov->is_animated_avif && mov->nb_streams > 1) {
9330 // For animated avif with alpha channel, we need to write a tref tag
9331 // with type "auxl".
9332 ✗ MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[1], MKTAG('a', 'u', 'x', 'l'));
9333 ✗ if (!tag)
9334 ✗ return AVERROR(ENOMEM);
9335
9336 ✗ int ret = mov_add_tref_id(mov, tag, 1);
9337 ✗ if (ret < 0)
9338 ✗ return ret;
9339 }
9340 ✗ mov_write_identification(pb, s);
9341 ✗ mov_write_meta_tag(pb, mov, s);
9342
9343 ✗ moov_size = get_moov_size(s);
9344 ✗ for (int i = 0; i < mov->nb_tracks; i++)
9345 ✗ mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
9346
9347 ✗ if (mov->is_animated_avif) {
9348 int ret;
9349 ✗ if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9350 ✗ return ret;
9351 }
9352
9353 ✗ buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
9354 ✗ avio_wb32(pb, buf_size + 8);
9355 ✗ ffio_wfourcc(pb, "mdat");
9356
9357 // The offset for the YUV planes is the starting position of mdat.
9358 ✗ extent_offsets[0] = avio_tell(pb);
9359 // The offset for alpha plane is YUV offset + YUV size.
9360 ✗ extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
9361
9362 ✗ avio_write(pb, buf, buf_size);
9363
9364 // write extent offsets.
9365 ✗ pos_backup = avio_tell(pb);
9366 ✗ for (int i = 0; i < mov->nb_streams; i++) {
9367 ✗ if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
9368 ✗ av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
9369 ✗ return AVERROR_INVALIDDATA;
9370 }
9371 ✗ avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
9372 ✗ avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
9373 }
9374 ✗ avio_seek(pb, pos_backup, SEEK_SET);
9375
9376 ✗ return 0;
9377 }
9378 #endif
9379
9380 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
9381 static const AVCodecTag codec_3gp_tags[] = {
9382 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
9383 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9384 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9385 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9386 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
9387 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
9388 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9389 { AV_CODEC_ID_NONE, 0 },
9390 };
9391 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
9392 #endif
9393
9394 static const AVCodecTag codec_mp4_tags[] = {
9395 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
9396 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
9397 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
9398 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
9399 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
9400 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
9401 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
9402 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
9403 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
9404 { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') },
9405 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
9406 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
9407 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
9408 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
9409 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
9410 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
9411 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
9412 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
9413 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
9414 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
9415 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
9416 { AV_CODEC_ID_AV1, MKTAG('d', 'a', 'v', '1') },
9417 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
9418 { AV_CODEC_ID_APPLE_APAC, MKTAG('a', 'p', 'a', 'c') },
9419 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
9420 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
9421 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
9422 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
9423 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
9424 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
9425 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
9426 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
9427 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
9428 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
9429 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
9430 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
9431 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
9432 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
9433 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
9434 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
9435 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
9436 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
9437 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
9438 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
9439
9440 /* ISO/IEC 23003-5 integer formats */
9441 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
9442 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
9443 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
9444 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
9445 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
9446 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
9447 /* ISO/IEC 23003-5 floating-point formats */
9448 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
9449 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
9450 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
9451 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
9452
9453 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
9454
9455 { AV_CODEC_ID_NONE, 0 },
9456 };
9457 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
9458 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
9459 #endif
9460
9461 static const AVCodecTag codec_ism_tags[] = {
9462 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
9463 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
9464 { AV_CODEC_ID_NONE , 0 },
9465 };
9466
9467 static const AVCodecTag codec_ipod_tags[] = {
9468 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9469 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9470 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9471 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
9472 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
9473 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9474 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
9475 { AV_CODEC_ID_NONE, 0 },
9476 };
9477
9478 static const AVCodecTag codec_f4v_tags[] = {
9479 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
9480 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9481 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9482 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
9483 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
9484 { AV_CODEC_ID_NONE, 0 },
9485 };
9486
9487 #if CONFIG_AVIF_MUXER
9488
9489 static const AVOption avif_options[] = {
9490 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
9491 { "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 },
9492 { NULL },
9493 };
9494 static const AVCodecTag codec_avif_tags[] = {
9495 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
9496 { AV_CODEC_ID_NONE, 0 },
9497 };
9498 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
9499
9500 static const AVClass mov_avif_muxer_class = {
9501 .class_name = "avif muxer",
9502 .item_name = av_default_item_name,
9503 .option = avif_options,
9504 .version = LIBAVUTIL_VERSION_INT,
9505 };
9506 #endif
9507
9508 #if CONFIG_MOV_MUXER
9509 const FFOutputFormat ff_mov_muxer = {
9510 .p.name = "mov",
9511 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
9512 .p.extensions = "mov",
9513 .priv_data_size = sizeof(MOVMuxContext),
9514 .p.audio_codec = AV_CODEC_ID_AAC,
9515 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9516 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9517 .init = mov_init,
9518 .write_header = mov_write_header,
9519 .write_packet = mov_write_packet,
9520 .write_trailer = mov_write_trailer,
9521 .deinit = mov_free,
9522 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9523 .p.codec_tag = (const AVCodecTag* const []){
9524 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
9525 },
9526 .check_bitstream = mov_check_bitstream,
9527 .p.priv_class = &mov_isobmff_muxer_class,
9528 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9529 };
9530 #endif
9531 #if CONFIG_TGP_MUXER
9532 const FFOutputFormat ff_tgp_muxer = {
9533 .p.name = "3gp",
9534 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9535 .p.extensions = "3gp",
9536 .priv_data_size = sizeof(MOVMuxContext),
9537 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9538 .p.video_codec = AV_CODEC_ID_H263,
9539 .init = mov_init,
9540 .write_header = mov_write_header,
9541 .write_packet = mov_write_packet,
9542 .write_trailer = mov_write_trailer,
9543 .deinit = mov_free,
9544 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9545 .p.codec_tag = codec_3gp_tags_list,
9546 .check_bitstream = mov_check_bitstream,
9547 .p.priv_class = &mov_isobmff_muxer_class,
9548 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9549 };
9550 #endif
9551 #if CONFIG_MP4_MUXER
9552 const FFOutputFormat ff_mp4_muxer = {
9553 .p.name = "mp4",
9554 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9555 .p.mime_type = "video/mp4",
9556 .p.extensions = "mp4",
9557 .priv_data_size = sizeof(MOVMuxContext),
9558 .p.audio_codec = AV_CODEC_ID_AAC,
9559 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9560 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9561 .init = mov_init,
9562 .write_header = mov_write_header,
9563 .write_packet = mov_write_packet,
9564 .write_trailer = mov_write_trailer,
9565 .deinit = mov_free,
9566 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9567 .p.codec_tag = mp4_codec_tags_list,
9568 .check_bitstream = mov_check_bitstream,
9569 .p.priv_class = &mov_isobmff_muxer_class,
9570 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9571 };
9572 #endif
9573 #if CONFIG_PSP_MUXER
9574 const FFOutputFormat ff_psp_muxer = {
9575 .p.name = "psp",
9576 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9577 .p.extensions = "mp4,psp",
9578 .priv_data_size = sizeof(MOVMuxContext),
9579 .p.audio_codec = AV_CODEC_ID_AAC,
9580 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9581 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9582 .init = mov_init,
9583 .write_header = mov_write_header,
9584 .write_packet = mov_write_packet,
9585 .write_trailer = mov_write_trailer,
9586 .deinit = mov_free,
9587 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9588 .p.codec_tag = mp4_codec_tags_list,
9589 .check_bitstream = mov_check_bitstream,
9590 .p.priv_class = &mov_isobmff_muxer_class,
9591 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9592 };
9593 #endif
9594 #if CONFIG_TG2_MUXER
9595 const FFOutputFormat ff_tg2_muxer = {
9596 .p.name = "3g2",
9597 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9598 .p.extensions = "3g2",
9599 .priv_data_size = sizeof(MOVMuxContext),
9600 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9601 .p.video_codec = AV_CODEC_ID_H263,
9602 .init = mov_init,
9603 .write_header = mov_write_header,
9604 .write_packet = mov_write_packet,
9605 .write_trailer = mov_write_trailer,
9606 .deinit = mov_free,
9607 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9608 .p.codec_tag = codec_3gp_tags_list,
9609 .check_bitstream = mov_check_bitstream,
9610 .p.priv_class = &mov_isobmff_muxer_class,
9611 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9612 };
9613 #endif
9614 #if CONFIG_IPOD_MUXER
9615 const FFOutputFormat ff_ipod_muxer = {
9616 .p.name = "ipod",
9617 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9618 .p.mime_type = "video/mp4",
9619 .p.extensions = "m4v,m4a,m4b",
9620 .priv_data_size = sizeof(MOVMuxContext),
9621 .p.audio_codec = AV_CODEC_ID_AAC,
9622 .p.video_codec = AV_CODEC_ID_H264,
9623 .init = mov_init,
9624 .write_header = mov_write_header,
9625 .write_packet = mov_write_packet,
9626 .write_trailer = mov_write_trailer,
9627 .deinit = mov_free,
9628 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9629 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9630 .check_bitstream = mov_check_bitstream,
9631 .p.priv_class = &mov_isobmff_muxer_class,
9632 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9633 };
9634 #endif
9635 #if CONFIG_ISMV_MUXER
9636 const FFOutputFormat ff_ismv_muxer = {
9637 .p.name = "ismv",
9638 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9639 .p.mime_type = "video/mp4",
9640 .p.extensions = "ismv,isma",
9641 .priv_data_size = sizeof(MOVMuxContext),
9642 .p.audio_codec = AV_CODEC_ID_AAC,
9643 .p.video_codec = AV_CODEC_ID_H264,
9644 .init = mov_init,
9645 .write_header = mov_write_header,
9646 .write_packet = mov_write_packet,
9647 .write_trailer = mov_write_trailer,
9648 .deinit = mov_free,
9649 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9650 .p.codec_tag = (const AVCodecTag* const []){
9651 codec_mp4_tags, codec_ism_tags, 0 },
9652 .check_bitstream = mov_check_bitstream,
9653 .p.priv_class = &mov_isobmff_muxer_class,
9654 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9655 };
9656 #endif
9657 #if CONFIG_F4V_MUXER
9658 const FFOutputFormat ff_f4v_muxer = {
9659 .p.name = "f4v",
9660 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9661 .p.mime_type = "application/f4v",
9662 .p.extensions = "f4v",
9663 .priv_data_size = sizeof(MOVMuxContext),
9664 .p.audio_codec = AV_CODEC_ID_AAC,
9665 .p.video_codec = AV_CODEC_ID_H264,
9666 .init = mov_init,
9667 .write_header = mov_write_header,
9668 .write_packet = mov_write_packet,
9669 .write_trailer = mov_write_trailer,
9670 .deinit = mov_free,
9671 .p.flags = AVFMT_GLOBALHEADER,
9672 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9673 .check_bitstream = mov_check_bitstream,
9674 .p.priv_class = &mov_isobmff_muxer_class,
9675 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9676 };
9677 #endif
9678 #if CONFIG_AVIF_MUXER
9679 const FFOutputFormat ff_avif_muxer = {
9680 .p.name = "avif",
9681 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9682 .p.mime_type = "image/avif",
9683 .p.extensions = "avif",
9684 .priv_data_size = sizeof(MOVMuxContext),
9685 .p.video_codec = AV_CODEC_ID_AV1,
9686 .init = mov_init,
9687 .write_header = mov_write_header,
9688 .write_packet = mov_write_packet,
9689 .write_trailer = avif_write_trailer,
9690 .deinit = mov_free,
9691 .p.flags = AVFMT_GLOBALHEADER,
9692 .p.codec_tag = codec_avif_tags_list,
9693 .p.priv_class = &mov_avif_muxer_class,
9694 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9695 };
9696 #endif
9697