FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2026-09-20 19:44:24
Exec Total Coverage
Lines: 3983 5850 68.1%
Functions: 189 242 78.1%
Branches: 2384 4045 58.9%

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/get_bits.h"
47
48 #include "libavcodec/internal.h"
49 #include "libavcodec/put_bits.h"
50 #include "libavcodec/vc1_common.h"
51 #include "libavcodec/raw.h"
52 #include "internal.h"
53 #include "libavutil/avstring.h"
54 #include "libavutil/channel_layout.h"
55 #include "libavutil/csp.h"
56 #include "libavutil/intfloat.h"
57 #include "libavutil/mathematics.h"
58 #include "libavutil/mem.h"
59 #include "libavutil/opt.h"
60 #include "libavutil/dict.h"
61 #include "libavutil/pixdesc.h"
62 #include "libavutil/stereo3d.h"
63 #include "libavutil/timecode.h"
64 #include "libavutil/dovi_meta.h"
65 #include "libavutil/uuid.h"
66 #include "hevc.h"
67 #include "rtpenc.h"
68 #include "nal.h"
69 #include "mov_chan.h"
70 #include "movenc_ttml.h"
71 #include "mux.h"
72 #include "rawutils.h"
73 #include "ttmlenc.h"
74 #include "version.h"
75 #include "vpcc.h"
76 #include "vvc.h"
77
78 static const AVOption options[] = {
79 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
80 { "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},
81 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
82 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "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 },
84 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
85 { "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 },
86 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
87 { "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},
88 { "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},
89 { "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},
90 { "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},
91 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
92 { "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" },
93 { "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" },
94 { "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" },
95 { "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" },
96 { "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" },
97 { "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" },
98 { "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" },
99 { "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" },
100 { "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" },
101 { "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" },
102 { "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" },
103 { "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" },
104 { "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" },
105 { "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 },
106 { "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" },
107 { "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" },
108 { "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" },
109 { "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" },
110 { "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" },
111 { "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" },
112 { "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" },
113 { "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" },
114 { "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" },
115 { "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" },
116 { "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" },
117 { "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},
118 { "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},
119 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
120 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
121 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
122 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "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},
124 { "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},
125 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
126 { "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"},
127 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
128 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
129 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
130 { NULL },
131 };
132
133 static const AVClass mov_isobmff_muxer_class = {
134 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
135 .item_name = av_default_item_name,
136 .option = options,
137 .version = LIBAVUTIL_VERSION_INT,
138 };
139
140 static int get_moov_size(AVFormatContext *s);
141 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
142
143 30 static int utf8len(const uint8_t *b)
144 {
145 30 int len = 0;
146 int val;
147
2/2
✓ Branch 0 taken 569 times.
✓ Branch 1 taken 30 times.
599 while (*b) {
148
3/8
✓ Branch 0 taken 569 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 569 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 569 times.
569 GET_UTF8(val, *b++, return -1;)
149 569 len++;
150 }
151 30 return len;
152 }
153
154 //FIXME support 64 bit variant with wide placeholders
155 7272 static int64_t update_size(AVIOContext *pb, int64_t pos)
156 {
157 7272 int64_t curpos = avio_tell(pb);
158 7272 avio_seek(pb, pos, SEEK_SET);
159 7272 avio_wb32(pb, curpos - pos); /* rewrite size */
160 7272 avio_seek(pb, curpos, SEEK_SET);
161
162 7272 return curpos - pos;
163 }
164
165 382 static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version)
166 {
167 382 int64_t curpos = avio_tell(pb);
168 382 avio_seek(pb, pos, SEEK_SET);
169 382 avio_wb32(pb, curpos - pos); /* rewrite size */
170 382 avio_skip(pb, 4);
171 382 avio_w8(pb, version); /* rewrite version */
172 382 avio_seek(pb, curpos, SEEK_SET);
173
174 382 return curpos - pos;
175 }
176
177 382 static int co64_required(const MOVTrack *track)
178 {
179
3/4
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 275 times.
382 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
180 return 1;
181 382 return 0;
182 }
183
184 24509 static int is_cover_image(const AVStream *st)
185 {
186 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
187 * is encoded as sparse video track */
188
3/4
✓ Branch 0 taken 24509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24497 times.
24509 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
189 }
190
191 6 static int rtp_hinting_needed(const AVStream *st)
192 {
193 /* Add hint tracks for each real audio and video stream */
194
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
195 return 0;
196
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
197
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
198 }
199
200 /* Chunk offset atom */
201 382 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
202 {
203 int i;
204 382 int mode64 = co64_required(track); // use 32 bit size variant if possible
205 382 int64_t pos = avio_tell(pb);
206 382 avio_wb32(pb, 0); /* size */
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (mode64)
208 ffio_wfourcc(pb, "co64");
209 else
210 382 ffio_wfourcc(pb, "stco");
211 382 avio_wb32(pb, 0); /* version & flags */
212 382 avio_wb32(pb, track->chunkCount); /* entry count */
213
2/2
✓ Branch 0 taken 17321 times.
✓ Branch 1 taken 382 times.
17703 for (i = 0; i < track->entry; i++) {
214
2/2
✓ Branch 0 taken 14351 times.
✓ Branch 1 taken 2970 times.
17321 if (!track->cluster[i].chunkNum)
215 14351 continue;
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2970 times.
2970 if (mode64 == 1)
217 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
218 else
219 2970 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
220 }
221 382 return update_size(pb, pos);
222 }
223
224 /* Sample size atom */
225 382 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
226 {
227 382 int equalChunks = 1;
228 382 int i, j, entries = 0, tst = -1, oldtst = -1;
229
230 382 int64_t pos = avio_tell(pb);
231 382 avio_wb32(pb, 0); /* size */
232 382 ffio_wfourcc(pb, "stsz");
233 382 avio_wb32(pb, 0); /* version & flags */
234
235
2/2
✓ Branch 0 taken 17321 times.
✓ Branch 1 taken 382 times.
17703 for (i = 0; i < track->entry; i++) {
236 17321 tst = track->cluster[i].size / track->cluster[i].entries;
237
4/4
✓ Branch 0 taken 17046 times.
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 11935 times.
✓ Branch 3 taken 5111 times.
17321 if (oldtst != -1 && tst != oldtst)
238 11935 equalChunks = 0;
239 17321 oldtst = tst;
240 17321 entries += track->cluster[i].entries;
241 }
242
4/4
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 107 times.
502 if (equalChunks && track->entry) {
243
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;
244 120 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
245 120 avio_wb32(pb, sSize); // sample size
246 120 avio_wb32(pb, entries); // sample count
247 } else {
248 262 avio_wb32(pb, 0); // sample size
249 262 avio_wb32(pb, entries); // sample count
250
2/2
✓ Branch 0 taken 13256 times.
✓ Branch 1 taken 262 times.
13518 for (i = 0; i < track->entry; i++) {
251
2/2
✓ Branch 0 taken 13256 times.
✓ Branch 1 taken 13256 times.
26512 for (j = 0; j < track->cluster[i].entries; j++) {
252 13256 avio_wb32(pb, track->cluster[i].size /
253 13256 track->cluster[i].entries);
254 }
255 }
256 }
257 382 return update_size(pb, pos);
258 }
259
260 /* Sample to chunk atom */
261 382 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
262 {
263 382 int index = 0, oldidx = -1, oldval = -1, i;
264 int64_t entryPos, curpos;
265
266 382 int64_t pos = avio_tell(pb);
267 382 avio_wb32(pb, 0); /* size */
268 382 ffio_wfourcc(pb, "stsc");
269 382 avio_wb32(pb, 0); // version & flags
270 382 entryPos = avio_tell(pb);
271 382 avio_wb32(pb, track->chunkCount); // entry count
272
2/2
✓ Branch 0 taken 17321 times.
✓ Branch 1 taken 382 times.
17703 for (i = 0; i < track->entry; i++) {
273
2/2
✓ Branch 0 taken 2133 times.
✓ Branch 1 taken 15188 times.
17321 if ((oldval != track->cluster[i].samples_in_chunk ||
274
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2131 times.
✓ Branch 2 taken 839 times.
✓ Branch 3 taken 14351 times.
17321 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
275 839 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
276 839 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
277 839 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
278 839 oldval = track->cluster[i].samples_in_chunk;
279 839 oldidx = track->cluster[i].stsd_index;
280 839 index++;
281 }
282 }
283 382 curpos = avio_tell(pb);
284 382 avio_seek(pb, entryPos, SEEK_SET);
285 382 avio_wb32(pb, index); // rewrite size
286 382 avio_seek(pb, curpos, SEEK_SET);
287
288 382 return update_size(pb, pos);
289 }
290
291 /* Sync sample atom */
292 68 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
293 {
294 int64_t curpos, entryPos;
295 68 int i, index = 0;
296 68 int64_t pos = avio_tell(pb);
297 68 avio_wb32(pb, 0); // size
298
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
299 68 avio_wb32(pb, 0); // version & flags
300 68 entryPos = avio_tell(pb);
301 68 avio_wb32(pb, track->entry); // entry count
302
2/2
✓ Branch 0 taken 3478 times.
✓ Branch 1 taken 68 times.
3546 for (i = 0; i < track->entry; i++) {
303
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 3253 times.
3478 if (track->cluster[i].flags & flag) {
304 225 avio_wb32(pb, i + 1);
305 225 index++;
306 }
307 }
308 68 curpos = avio_tell(pb);
309 68 avio_seek(pb, entryPos, SEEK_SET);
310 68 avio_wb32(pb, index); // rewrite size
311 68 avio_seek(pb, curpos, SEEK_SET);
312 68 return update_size(pb, pos);
313 }
314
315 /* Sample dependency atom */
316 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
317 {
318 int i;
319 uint8_t leading, dependent, reference, redundancy;
320 3 int64_t pos = avio_tell(pb);
321 3 avio_wb32(pb, 0); // size
322 3 ffio_wfourcc(pb, "sdtp");
323 3 avio_wb32(pb, 0); // version & flags
324
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
325 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
326 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
327
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
328 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
329 }
330
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
331 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
332 }
333 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
334 13 (reference << 2) | redundancy);
335 }
336 3 return update_size(pb, pos);
337 }
338
339 #if CONFIG_IAMFENC
340 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
341 {
342 AVIOContext *dyn_bc;
343 5 int64_t pos = avio_tell(pb);
344 5 uint8_t *dyn_buf = NULL;
345 int dyn_size;
346 5 int ret = avio_open_dyn_buf(&dyn_bc);
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
348 return ret;
349
350 5 avio_wb32(pb, 0);
351 5 ffio_wfourcc(pb, "iacb");
352 5 avio_w8(pb, 1); // configurationVersion
353
354 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0) {
356 ffio_free_dyn_buf(&dyn_bc);
357 return ret;
358 }
359
360 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
361 5 ffio_write_leb(pb, dyn_size);
362 5 avio_write(pb, dyn_buf, dyn_size);
363 5 av_free(dyn_buf);
364
365 5 return update_size(pb, pos);
366 }
367 #endif
368
369 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
370 {
371 avio_wb32(pb, 0x11); /* size */
372 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
373 else ffio_wfourcc(pb, "damr");
374 ffio_wfourcc(pb, "FFMP");
375 avio_w8(pb, 0); /* decoder version */
376
377 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
378 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
379 avio_w8(pb, 0x01); /* Frames per sample */
380 return 0x11;
381 }
382
383 struct eac3_info {
384 AVPacket *pkt;
385 uint8_t eof;
386 uint8_t ec3_done;
387 uint8_t num_blocks;
388
389 /* Layout of the EC3SpecificBox */
390 /* maximum bitrate */
391 uint16_t data_rate;
392 int8_t ac3_bit_rate_code;
393 /* number of independent substreams */
394 uint8_t num_ind_sub;
395 struct {
396 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
397 uint8_t fscod;
398 /* bit stream identification 5 bits */
399 uint8_t bsid;
400 /* one bit reserved */
401 /* audio service mixing (not supported yet) 1 bit */
402 /* bit stream mode 3 bits */
403 uint8_t bsmod;
404 /* audio coding mode 3 bits */
405 uint8_t acmod;
406 /* sub woofer on 1 bit */
407 uint8_t lfeon;
408 /* 3 bits reserved */
409 /* number of dependent substreams associated with this substream 4 bits */
410 uint8_t num_dep_sub;
411 /* channel locations of the dependent substream(s), if any, 9 bits */
412 uint16_t chan_loc;
413 /* if there is no dependent substream, then one bit reserved instead */
414 } substream[1]; /* TODO: support 8 independent substreams */
415 /* indicates the decoding complexity, 8 bits */
416 uint8_t complexity_index_type_a;
417 };
418
419 7 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
420 {
421 7 struct eac3_info *info = track->eac3_priv;
422 PutBitContext pbc;
423 uint8_t buf[3];
424
425
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) {
426 av_log(s, AV_LOG_ERROR,
427 "Cannot write moov atom before AC3 packets."
428 " Set the delay_moov flag to fix this.\n");
429 return AVERROR(EINVAL);
430 }
431
432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->substream[0].bsid > 8) {
433 av_log(s, AV_LOG_ERROR,
434 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
435 "ISOBMFF specification in ETSI TS 102 366!\n",
436 info->substream[0].bsid);
437 return AVERROR(EINVAL);
438 }
439
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->ac3_bit_rate_code < 0) {
441 av_log(s, AV_LOG_ERROR,
442 "No valid AC3 bit rate code for data rate of %d!\n",
443 info->data_rate);
444 return AVERROR(EINVAL);
445 }
446
447 7 avio_wb32(pb, 11);
448 7 ffio_wfourcc(pb, "dac3");
449
450 7 init_put_bits(&pbc, buf, sizeof(buf));
451 7 put_bits(&pbc, 2, info->substream[0].fscod);
452 7 put_bits(&pbc, 5, info->substream[0].bsid);
453 7 put_bits(&pbc, 3, info->substream[0].bsmod);
454 7 put_bits(&pbc, 3, info->substream[0].acmod);
455 7 put_bits(&pbc, 1, info->substream[0].lfeon);
456 7 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
457 7 put_bits(&pbc, 5, 0); // reserved
458
459 7 flush_put_bits(&pbc);
460 7 avio_write(pb, buf, sizeof(buf));
461
462 7 return 11;
463 }
464
465 1737 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
466 {
467 1737 AC3HeaderInfo *hdr = NULL;
468 struct eac3_info *info;
469 int num_blocks, ret;
470
471
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
1737 if (!track->eac3_priv) {
472
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
473 return AVERROR(ENOMEM);
474
475 10 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
476 }
477 1737 info = track->eac3_priv;
478
479
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()))
480 return AVERROR(ENOMEM);
481
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (info->eof) {
483 av_assert1(!info->pkt->size);
484 ret = pkt->size;
485 goto end;
486 }
487
488
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) {
489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
490 goto end;
491
492 /* drop the packets until we see a good one */
493
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
494 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
495 1 ret = 0;
496 } else
497 ret = AVERROR_INVALIDDATA;
498 1 goto end;
499 }
500
501 1736 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
502 1736 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
503 hdr->ac3_bit_rate_code);
504 1736 info->complexity_index_type_a = hdr->complexity_index_type_a;
505
506 1736 num_blocks = hdr->num_blocks;
507
508
2/2
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 14 times.
1736 if (!info->ec3_done) {
509 /* AC-3 substream must be the first one */
510
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) {
511 ret = AVERROR(EINVAL);
512 goto end;
513 }
514
515 /* this should always be the case, given that our AC-3 parser
516 * concatenates dependent frames to their independent parent */
517
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
518
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
519 /* substream ids must be incremental */
520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid > info->num_ind_sub + 1) {
521 ret = AVERROR(EINVAL);
522 goto end;
523 }
524
525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid == info->num_ind_sub + 1) {
526 //info->num_ind_sub++;
527 avpriv_request_sample(mov->fc, "Multiple independent substreams");
528 ret = AVERROR_PATCHWELCOME;
529 goto end;
530
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 } else if (hdr->substreamid < info->num_ind_sub ||
531
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) {
532 4 info->ec3_done = 1;
533 4 goto concatenate;
534 }
535 } else {
536 if (hdr->substreamid != 0) {
537 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
538 ret = AVERROR_PATCHWELCOME;
539 goto end;
540 }
541 }
542
543 /* fill the info needed for the "dec3" atom */
544 10 info->substream[hdr->substreamid].fscod = hdr->sr_code;
545 10 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
546 10 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
547 10 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
548 10 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
549
550
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (track->par->codec_id == AV_CODEC_ID_AC3) {
551 // with AC-3 we only require the information of a single packet,
552 // so we can finish as soon as the basic values of the bit stream
553 // have been set to the track's informational structure.
554 6 info->ec3_done = 1;
555 6 goto concatenate;
556 }
557
558 /* Parse dependent substream(s), if any */
559
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (pkt->size != hdr->frame_size) {
560 1 int cumul_size = hdr->frame_size;
561 1 int parent = hdr->substreamid;
562
563
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (cumul_size != pkt->size) {
564 1 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
566 goto end;
567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
568 ret = AVERROR(EINVAL);
569 goto end;
570 }
571 1 info->substream[parent].num_dep_sub++;
572 1 ret /= 8;
573
574 /* get the dependent stream channel map, if exists */
575
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (hdr->channel_map_present) {
576 /* chanmap is a 16-bit field read MSB-first, so flag index
577 * i sits at bit (15 - i), matching the indexing of
578 * ff_eac3_custom_channel_map_locations. chan_loc bits 0-7
579 * carry flag indices 5-12, i.e. chanmap bit (10 - j).
580 * The mapping is not contiguous at the top: index 13
581 * (Lts/Rts) has no chan_loc bit and is skipped, and
582 * chan_loc bit 8 carries LFE2, which is index 14 and so
583 * chanmap bit 1. */
584
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for (int j = 0; j < 8; j++) {
585
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if ((hdr->channel_map >> (10 - j)) & 1)
586 1 info->substream[parent].chan_loc |= 1 << j;
587 }
588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((hdr->channel_map >> 1) & 1)
589 info->substream[parent].chan_loc |= 1 << 8;
590 } else {
591 info->substream[parent].chan_loc |= hdr->channel_mode;
592 }
593 1 cumul_size += hdr->frame_size;
594 }
595 }
596 }
597
598 1726 concatenate:
599
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) {
600 1736 ret = pkt->size;
601 1736 goto end;
602 }
603 else if (info->num_blocks + num_blocks > 6) {
604 ret = AVERROR_INVALIDDATA;
605 goto end;
606 }
607
608 if (!info->num_blocks) {
609 ret = av_packet_ref(info->pkt, pkt);
610 if (!ret)
611 info->num_blocks = num_blocks;
612 goto end;
613 } else {
614 const AVPacketSideData *sd;
615 int64_t duration = pkt->duration;
616 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
617 goto end;
618 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
619 if (sd && sd->size >= 10) {
620 uint8_t *buf = av_packet_new_side_data(info->pkt, AV_PKT_DATA_SKIP_SAMPLES, sd->size);
621 if (buf)
622 memcpy(buf, sd->data, sd->size);
623 if (track->par->frame_size)
624 duration = FFMAX(av_rescale_q(track->par->frame_size, (AVRational){ 1, track->par->sample_rate },
625 track->st->time_base), duration);
626 }
627 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
628 info->num_blocks += num_blocks;
629 info->pkt->duration += duration;
630 if (info->num_blocks != 6)
631 goto end;
632 av_packet_unref(pkt);
633 av_packet_move_ref(pkt, info->pkt);
634 info->num_blocks = 0;
635 }
636 ret = pkt->size;
637
638 1737 end:
639 1737 av_free(hdr);
640
641 1737 return ret;
642 }
643
644 4 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
645 {
646 PutBitContext pbc;
647 uint8_t *buf;
648 struct eac3_info *info;
649 int size, i;
650
651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->eac3_priv) {
652 av_log(s, AV_LOG_ERROR,
653 "Cannot write moov atom before EAC3 packets parsed.\n");
654 return AVERROR(EINVAL);
655 }
656
657 4 info = track->eac3_priv;
658
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);
659 4 buf = av_malloc(size);
660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!buf) {
661 return AVERROR(ENOMEM);
662 }
663
664 4 init_put_bits(&pbc, buf, size);
665 4 put_bits(&pbc, 13, info->data_rate);
666 4 put_bits(&pbc, 3, info->num_ind_sub);
667
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i <= info->num_ind_sub; i++) {
668 4 put_bits(&pbc, 2, info->substream[i].fscod);
669 4 put_bits(&pbc, 5, info->substream[i].bsid);
670 4 put_bits(&pbc, 1, 0); /* reserved */
671 4 put_bits(&pbc, 1, 0); /* asvc */
672 4 put_bits(&pbc, 3, info->substream[i].bsmod);
673 4 put_bits(&pbc, 3, info->substream[i].acmod);
674 4 put_bits(&pbc, 1, info->substream[i].lfeon);
675 4 put_bits(&pbc, 3, 0); /* reserved */
676 4 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
677
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (!info->substream[i].num_dep_sub) {
678 3 put_bits(&pbc, 1, 0); /* reserved */
679 } else {
680 1 put_bits(&pbc, 9, info->substream[i].chan_loc);
681 }
682 }
683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (info->complexity_index_type_a) {
684 put_bits(&pbc, 7, 0); /* reserved */
685 put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
686 put_bits(&pbc, 8, info->complexity_index_type_a);
687 }
688 4 flush_put_bits(&pbc);
689 4 size = put_bytes_output(&pbc);
690
691 4 avio_wb32(pb, size + 8);
692 4 ffio_wfourcc(pb, "dec3");
693 4 avio_write(pb, buf, size);
694
695 4 av_free(buf);
696
697 4 return size;
698 }
699
700 /**
701 * This function writes extradata "as is".
702 * Extradata must be formatted like a valid atom (with size and tag).
703 */
704 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
705 {
706 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
707 12 return track->extradata_size[track->last_stsd_index];
708 }
709
710 static int mov_write_enda_tag(AVIOContext *pb)
711 {
712 avio_wb32(pb, 10);
713 ffio_wfourcc(pb, "enda");
714 avio_wb16(pb, 1); /* little endian */
715 return 10;
716 }
717
718 2 static int mov_write_enda_tag_be(AVIOContext *pb)
719 {
720 2 avio_wb32(pb, 10);
721 2 ffio_wfourcc(pb, "enda");
722 2 avio_wb16(pb, 0); /* big endian */
723 2 return 10;
724 }
725
726 405 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
727 {
728 405 int i = 3;
729 405 avio_w8(pb, tag);
730
2/2
✓ Branch 0 taken 1215 times.
✓ Branch 1 taken 405 times.
1620 for (; i > 0; i--)
731 1215 avio_w8(pb, (size >> (7 * i)) | 0x80);
732 405 avio_w8(pb, size & 0x7F);
733 405 }
734
735 278 static unsigned compute_avg_bitrate(MOVTrack *track)
736 {
737 278 uint64_t size = 0;
738 int i;
739
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 226 times.
278 if (!track->track_duration)
740 52 return 0;
741
2/2
✓ Branch 0 taken 15257 times.
✓ Branch 1 taken 226 times.
15483 for (i = 0; i < track->entry; i++)
742 15257 size += track->cluster[i].size;
743 226 return size * 8 * track->timescale / track->track_duration;
744 }
745
746 struct mpeg4_bit_rate_values {
747 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
748 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
749 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
750 };
751
752 278 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
753 {
754 556 const AVPacketSideData *sd = track->st ?
755 277 av_packet_side_data_get(track->st->codecpar->coded_side_data,
756 277 track->st->codecpar->nb_coded_side_data,
757
2/2
✓ Branch 0 taken 277 times.
✓ Branch 1 taken 1 times.
278 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
758
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 228 times.
278 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
759 278 struct mpeg4_bit_rate_values bit_rates = { 0 };
760
761 278 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
762
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 124 times.
278 if (!bit_rates.avg_bit_rate) {
763 // if the average bit rate cannot be calculated at this point, such as
764 // in the case of fragmented MP4, utilize the following values as
765 // fall-back in priority order:
766 //
767 // 1. average bit rate property
768 // 2. bit rate (usually average over the whole clip)
769 // 3. maximum bit rate property
770
771
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) {
772 16 bit_rates.avg_bit_rate = props->avg_bitrate;
773
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 129 times.
138 } else if (track->par->bit_rate) {
774 9 bit_rates.avg_bit_rate = track->par->bit_rate;
775
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) {
776 bit_rates.avg_bit_rate = props->max_bitrate;
777 }
778 }
779
780 // (FIXME should be max rate in any 1 sec window)
781 278 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
782 bit_rates.avg_bit_rate);
783
784 // utilize values from properties if we have them available
785
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 228 times.
278 if (props) {
786 // no avg_bitrate signals that the track is VBR
787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!props->avg_bitrate)
788 bit_rates.avg_bit_rate = props->avg_bitrate;
789 50 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
790 props->max_bitrate);
791 50 bit_rates.buffer_size = props->buffer_size / 8;
792 }
793
794 278 return bit_rates;
795 }
796
797 103 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
798 {
799 103 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
800 103 int64_t pos = avio_tell(pb);
801 206 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
802
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7 times.
103 5 + track->extradata_size[track->last_stsd_index] : 0;
803
804 103 avio_wb32(pb, 0); // size
805 103 ffio_wfourcc(pb, "esds");
806 103 avio_wb32(pb, 0); // Version
807
808 // ES descriptor
809 103 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
810 103 avio_wb16(pb, track->track_id);
811 103 avio_w8(pb, 0x00); // flags (= no flags)
812
813 // DecoderConfig descriptor
814 103 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
815
816 // Object type indication
817
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
103 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
818
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 102 times.
103 track->par->codec_id == AV_CODEC_ID_MP3) &&
819
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 track->par->sample_rate > 24000)
820 1 avio_w8(pb, 0x6B); // 11172-3
821 else
822 102 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
823
824 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
825 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
827 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
828
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 36 times.
103 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
829 67 avio_w8(pb, 0x15); // flags (= Audiostream)
830 else
831 36 avio_w8(pb, 0x11); // flags (= Visualstream)
832
833 103 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
834 103 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
835 103 avio_wb32(pb, bit_rates.avg_bit_rate);
836
837
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7 times.
103 if (track->extradata_size[track->last_stsd_index]) {
838 // DecoderSpecific info descriptor
839 96 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
840 96 avio_write(pb, track->extradata[track->last_stsd_index],
841 96 track->extradata_size[track->last_stsd_index]);
842 }
843
844 // SL descriptor
845 103 put_descr(pb, 0x06, 1);
846 103 avio_w8(pb, 0x02);
847 103 return update_size(pb, pos);
848 }
849
850 75 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
851 {
852
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 return codec_id == AV_CODEC_ID_PCM_S24LE ||
853
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 codec_id == AV_CODEC_ID_PCM_S32LE ||
854
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 ||
855 codec_id == AV_CODEC_ID_PCM_F64LE;
856 }
857
858 75 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
859 {
860
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
71 return codec_id == AV_CODEC_ID_PCM_S24BE ||
861
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 codec_id == AV_CODEC_ID_PCM_S32BE ||
862
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 ||
863 codec_id == AV_CODEC_ID_PCM_F64BE;
864 }
865
866 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
867 {
868 int ret;
869 int64_t pos = avio_tell(pb);
870 avio_wb32(pb, 0);
871 avio_wl32(pb, track->tag); // store it byteswapped
872 track->par->codec_tag = av_bswap16(track->tag >> 16);
873 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
874 return ret;
875 return update_size(pb, pos);
876 }
877
878 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
879 {
880 int ret;
881 int64_t pos = avio_tell(pb);
882 avio_wb32(pb, 0);
883 ffio_wfourcc(pb, "wfex");
884 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
885 return ret;
886 return update_size(pb, pos);
887 }
888
889 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
890 {
891 int64_t pos = avio_tell(pb);
892 avio_wb32(pb, 0);
893 ffio_wfourcc(pb, "dfLa");
894 avio_w8(pb, 0); /* version */
895 avio_wb24(pb, 0); /* flags */
896
897 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
898 if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
899 return AVERROR_INVALIDDATA;
900
901 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
902 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
903 avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
904 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
905
906 return update_size(pb, pos);
907 }
908
909 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
910 {
911 int64_t pos = avio_tell(pb);
912 int channels, channel_map;
913 avio_wb32(pb, 0);
914 ffio_wfourcc(pb, "dOps");
915 avio_w8(pb, 0); /* Version */
916 if (track->extradata_size[track->last_stsd_index] < 19) {
917 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
918 return AVERROR_INVALIDDATA;
919 }
920 /* extradata contains an Ogg OpusHead, other than byte-ordering and
921 OpusHead's preceding magic/version, OpusSpecificBox is currently
922 identical. */
923 channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
924 channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
925
926 avio_w8(pb, channels); /* OuputChannelCount */
927 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
928 avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
929 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
930 avio_w8(pb, channel_map); /* ChannelMappingFamily */
931 /* Write the rest of the header out without byte-swapping. */
932 if (channel_map) {
933 if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
934 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
935 return AVERROR_INVALIDDATA;
936 }
937 avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
938 }
939
940 return update_size(pb, pos);
941 }
942
943 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
944 {
945 int64_t pos = avio_tell(pb);
946 int length;
947 avio_wb32(pb, 0);
948 ffio_wfourcc(pb, "dmlp");
949
950 if (track->extradata_size[track->last_stsd_index] < 20) {
951 av_log(s, AV_LOG_ERROR,
952 "Cannot write moov atom before TrueHD packets."
953 " Set the delay_moov flag to fix this.\n");
954 return AVERROR(EINVAL);
955 }
956
957 length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
958 if (length < 20 || length > track->extradata_size[track->last_stsd_index])
959 return AVERROR_INVALIDDATA;
960
961 // Only TrueHD is supported
962 if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
963 return AVERROR_INVALIDDATA;
964
965 avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
966 avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
967 avio_wb32(pb, 0); /* reserved */
968
969 return update_size(pb, pos);
970 }
971
972 86 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
973 {
974 86 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
975 86 AVChannelLayout ch_layout = { 0 };
976 int64_t pos;
977 int ambisonic_order, ambi_channels, non_diegetic_channels;
978 int i, ret;
979
980
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 if (!str)
981 86 return 0;
982
983 ret = av_channel_layout_from_string(&ch_layout, str->value);
984 if (ret < 0) {
985 if (ret == AVERROR(EINVAL)) {
986 invalid:
987 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
988 ret = 0;
989 }
990 av_channel_layout_uninit(&ch_layout);
991 return ret;
992 }
993
994 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
995 goto invalid;
996
997 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
998 if (ambisonic_order < 0)
999 goto invalid;
1000
1001 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
1002 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
1003 if (non_diegetic_channels &&
1004 (non_diegetic_channels != 2 ||
1005 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
1006 goto invalid;
1007
1008 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
1009
1010 pos = avio_tell(pb);
1011
1012 avio_wb32(pb, 0); // Size
1013 ffio_wfourcc(pb, "SA3D");
1014 avio_w8(pb, 0); // version
1015 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
1016 avio_wb32(pb, ambisonic_order); // ambisonic_order
1017 avio_w8(pb, 0); // ambisonic_channel_ordering
1018 avio_w8(pb, 0); // ambisonic_normalization
1019 avio_wb32(pb, ch_layout.nb_channels); // num_channels
1020 for (i = 0; i < ambi_channels; i++)
1021 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
1022 for (; i < ch_layout.nb_channels; i++)
1023 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
1024
1025 av_channel_layout_uninit(&ch_layout);
1026
1027 return update_size(pb, pos);
1028 }
1029
1030 39 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1031 {
1032 uint32_t layout_tag, bitmap, *channel_desc;
1033 39 int64_t pos = avio_tell(pb);
1034 int num_desc, ret;
1035
1036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (track->multichannel_as_mono)
1037 return 0;
1038
1039 39 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
1040 &bitmap, &channel_desc);
1041
1042
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0) {
1043 if (ret == AVERROR(ENOSYS)) {
1044 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
1045 "lack of channel information\n");
1046 ret = 0;
1047 }
1048
1049 return ret;
1050 }
1051
1052 /* no predefined tag found + ch_layout in AV_CHANNEL_ORDER_NATIVE
1053 * but bitstream channels not actually in native order */
1054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (layout_tag == MOV_CH_LAYOUT_UNKNOWN)
1055 return 0;
1056
1057
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) {
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1059 1 channel_desc = av_malloc(sizeof(*channel_desc));
1060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1061 return AVERROR(ENOMEM);
1062
1063 1 layout_tag = 0;
1064 1 bitmap = 0;
1065 1 *channel_desc = 3; // channel label "Center"
1066 }
1067
1068
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 36 times.
39 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1069
1070 39 avio_wb32(pb, 0); // Size
1071 39 ffio_wfourcc(pb, "chan"); // Type
1072 39 avio_w8(pb, 0); // Version
1073 39 avio_wb24(pb, 0); // Flags
1074 39 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1075 39 avio_wb32(pb, bitmap); // mChannelBitmap
1076 39 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1077
1078
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39 times.
42 for (int i = 0; i < num_desc; i++) {
1079 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1080 3 avio_wb32(pb, 0); // mChannelFlags
1081 3 avio_wl32(pb, 0); // mCoordinates[0]
1082 3 avio_wl32(pb, 0); // mCoordinates[1]
1083 3 avio_wl32(pb, 0); // mCoordinates[2]
1084 }
1085
1086 39 av_free(channel_desc);
1087
1088 39 return update_size(pb, pos);
1089 }
1090
1091 14 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1092 {
1093 14 int64_t pos = avio_tell(pb);
1094
1095 14 avio_wb32(pb, 0); /* size */
1096 14 ffio_wfourcc(pb, "wave");
1097
1098
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1099 14 avio_wb32(pb, 12); /* size */
1100 14 ffio_wfourcc(pb, "frma");
1101 14 avio_wl32(pb, track->tag);
1102 }
1103
1104
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1105 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1106 3 avio_wb32(pb, 12); /* size */
1107 3 ffio_wfourcc(pb, "mp4a");
1108 3 avio_wb32(pb, 0);
1109 3 mov_write_esds_tag(pb, track);
1110
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1111 mov_write_enda_tag(pb);
1112
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
11 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1113 2 mov_write_enda_tag_be(pb);
1114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1115 mov_write_amr_tag(pb, track);
1116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1117 mov_write_ac3_tag(s, pb, track);
1118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1119 mov_write_eac3_tag(s, pb, track);
1120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1121 track->par->codec_id == AV_CODEC_ID_QDM2) {
1122 9 mov_write_extradata_tag(pb, track);
1123 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1124 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1125 mov_write_ms_tag(s, pb, track);
1126 }
1127
1128 14 avio_wb32(pb, 8); /* size */
1129 14 avio_wb32(pb, 0); /* null tag */
1130
1131 14 return update_size(pb, pos);
1132 }
1133
1134 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1135 {
1136 uint8_t *unescaped;
1137 const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1138 track->extradata_size[track->last_stsd_index];
1139 int unescaped_size, seq_found = 0;
1140 int level = 0, interlace = 0;
1141 int packet_seq = track->vc1_info.packet_seq;
1142 int packet_entry = track->vc1_info.packet_entry;
1143 int slices = track->vc1_info.slices;
1144 PutBitContext pbc;
1145
1146 if (track->start_dts == AV_NOPTS_VALUE) {
1147 /* No packets written yet, vc1_info isn't authoritative yet. */
1148 /* Assume inline sequence and entry headers. */
1149 packet_seq = packet_entry = 1;
1150 av_log(NULL, AV_LOG_WARNING,
1151 "moov atom written before any packets, unable to write correct "
1152 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1153 }
1154
1155 unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1156 if (!unescaped)
1157 return AVERROR(ENOMEM);
1158 start = find_next_marker(track->extradata[track->last_stsd_index], end);
1159 for (next = start; next < end; start = next) {
1160 GetBitContext gb;
1161 int size;
1162 next = find_next_marker(start + 4, end);
1163 size = next - start - 4;
1164 if (size <= 0)
1165 continue;
1166 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1167 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1168 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1169 int profile = get_bits(&gb, 2);
1170 if (profile != PROFILE_ADVANCED) {
1171 av_free(unescaped);
1172 return AVERROR(ENOSYS);
1173 }
1174 seq_found = 1;
1175 level = get_bits(&gb, 3);
1176 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1177 * width, height */
1178 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1179 skip_bits(&gb, 1); /* broadcast */
1180 interlace = get_bits1(&gb);
1181 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1182 }
1183 }
1184 if (!seq_found) {
1185 av_free(unescaped);
1186 return AVERROR(ENOSYS);
1187 }
1188
1189 init_put_bits(&pbc, buf, 7);
1190 /* VC1DecSpecStruc */
1191 put_bits(&pbc, 4, 12); /* profile - advanced */
1192 put_bits(&pbc, 3, level);
1193 put_bits(&pbc, 1, 0); /* reserved */
1194 /* VC1AdvDecSpecStruc */
1195 put_bits(&pbc, 3, level);
1196 put_bits(&pbc, 1, 0); /* cbr */
1197 put_bits(&pbc, 6, 0); /* reserved */
1198 put_bits(&pbc, 1, !interlace); /* no interlace */
1199 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1200 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1201 put_bits(&pbc, 1, !slices); /* no slice code */
1202 put_bits(&pbc, 1, 0); /* no bframe */
1203 put_bits(&pbc, 1, 0); /* reserved */
1204
1205 /* framerate */
1206 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1207 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1208 else
1209 put_bits32(&pbc, 0xffffffff);
1210
1211 flush_put_bits(&pbc);
1212
1213 av_free(unescaped);
1214
1215 return 0;
1216 }
1217
1218 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1219 {
1220 uint8_t buf[7] = { 0 };
1221 int ret;
1222
1223 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1224 return ret;
1225
1226 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1227 ffio_wfourcc(pb, "dvc1");
1228 avio_write(pb, buf, sizeof(buf));
1229 avio_write(pb, track->extradata[track->last_stsd_index],
1230 track->extradata_size[track->last_stsd_index]);
1231
1232 return 0;
1233 }
1234
1235 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1236 {
1237 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1238 4 ffio_wfourcc(pb, "glbl");
1239 4 avio_write(pb, track->extradata[track->last_stsd_index],
1240 4 track->extradata_size[track->last_stsd_index]);
1241 4 return 8 + track->extradata_size[track->last_stsd_index];
1242 }
1243
1244 /**
1245 * Compute flags for 'lpcm' tag.
1246 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1247 */
1248 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1249 {
1250
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) {
1251 case AV_CODEC_ID_PCM_F32BE:
1252 case AV_CODEC_ID_PCM_F64BE:
1253 return 11;
1254 case AV_CODEC_ID_PCM_F32LE:
1255 case AV_CODEC_ID_PCM_F64LE:
1256 return 9;
1257 case AV_CODEC_ID_PCM_U8:
1258 return 10;
1259 case AV_CODEC_ID_PCM_S16BE:
1260 case AV_CODEC_ID_PCM_S24BE:
1261 case AV_CODEC_ID_PCM_S32BE:
1262 return 14;
1263 case AV_CODEC_ID_PCM_S8:
1264 case AV_CODEC_ID_PCM_S16LE:
1265 case AV_CODEC_ID_PCM_S24LE:
1266 case AV_CODEC_ID_PCM_S32LE:
1267 return 12;
1268 8 default:
1269 8 return 0;
1270 }
1271 }
1272
1273 32940 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1274 {
1275 int64_t next_dts;
1276
1277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32940 times.
32940 if (cluster_idx >= track->entry)
1278 return 0;
1279
1280
2/2
✓ Branch 0 taken 924 times.
✓ Branch 1 taken 32016 times.
32940 if (cluster_idx + 1 == track->entry)
1281 924 next_dts = track->track_duration + track->start_dts;
1282 else
1283 32016 next_dts = track->cluster[cluster_idx + 1].dts;
1284
1285 32940 next_dts -= track->cluster[cluster_idx].dts;
1286
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32940 times.
32940 av_assert0(next_dts >= 0);
1288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32940 times.
32940 av_assert0(next_dts <= INT_MAX);
1289
1290 32940 return next_dts;
1291 }
1292
1293 4 static int get_samples_per_packet(MOVTrack *track)
1294 {
1295 int i, first_duration;
1296
1297 /* use 1 for raw PCM */
1298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1299 return 1;
1300
1301 /* check to see if duration is constant for all clusters */
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1303 return 0;
1304 4 first_duration = get_cluster_duration(track, 0);
1305
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1306
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1307 4 return 0;
1308 }
1309 return first_duration;
1310 }
1311
1312 175 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1313 {
1314 175 int64_t pos = avio_tell(pb);
1315 175 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1316
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
175 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1317
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 !bit_rates.buffer_size)
1318 // no useful data to be written, skip
1319 86 return 0;
1320
1321 89 avio_wb32(pb, 0); /* size */
1322 89 ffio_wfourcc(pb, "btrt");
1323
1324 89 avio_wb32(pb, bit_rates.buffer_size);
1325 89 avio_wb32(pb, bit_rates.max_bit_rate);
1326 89 avio_wb32(pb, bit_rates.avg_bit_rate);
1327
1328 89 return update_size(pb, pos);
1329 }
1330
1331 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1332 {
1333 7 int64_t pos = avio_tell(pb);
1334 7 int config = 0;
1335 int ret;
1336 7 uint8_t *speaker_pos = NULL;
1337 7 const AVChannelLayout *layout = &track->par->ch_layout;
1338
1339 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1340
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) {
1341 4 config = 0;
1342 4 speaker_pos = av_malloc(layout->nb_channels);
1343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1344 return AVERROR(ENOMEM);
1345 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1346 4 speaker_pos, layout->nb_channels);
1347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1348 char buf[128] = {0};
1349
1350 av_freep(&speaker_pos);
1351 av_channel_layout_describe(layout, buf, sizeof(buf));
1352 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1353 return ret;
1354 }
1355 }
1356
1357 7 avio_wb32(pb, 0); /* size */
1358 7 ffio_wfourcc(pb, "chnl");
1359 7 avio_wb32(pb, 0); /* version & flags */
1360
1361 7 avio_w8(pb, 1); /* stream_structure */
1362 7 avio_w8(pb, config);
1363
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1364 3 avio_wb64(pb, 0);
1365 } else {
1366 4 avio_write(pb, speaker_pos, layout->nb_channels);
1367 4 av_freep(&speaker_pos);
1368 }
1369
1370 7 return update_size(pb, pos);
1371 }
1372
1373 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1374 {
1375 9 int64_t pos = avio_tell(pb);
1376 int format_flags;
1377 int sample_size;
1378
1379 9 avio_wb32(pb, 0); /* size */
1380 9 ffio_wfourcc(pb, "pcmC");
1381 9 avio_wb32(pb, 0); /* version & flags */
1382
1383 /* 0x01: indicates little-endian format */
1384 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1385
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1387
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 ||
1388 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1389 9 avio_w8(pb, format_flags);
1390 9 sample_size = track->par->bits_per_raw_sample;
1391
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1392 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1394 9 avio_w8(pb, sample_size);
1395
1396 9 return update_size(pb, pos);
1397 }
1398
1399 5 static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track)
1400 {
1401 5 int64_t pos = avio_tell(pb);
1402 5 avio_wb32(pb, 0); /* size */
1403 5 ffio_wfourcc(pb, "srat");
1404 5 avio_wb32(pb, 0); /* version & flags */
1405
1406 5 avio_wb32(pb, track->par->sample_rate);
1407
1408 5 return update_size(pb, pos);
1409 }
1410
1411 128 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1412 {
1413 128 int64_t pos = avio_tell(pb);
1414 128 int version = 0;
1415 128 uint32_t tag = track->tag;
1416 128 int ret = 0;
1417
1418
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
128 if (track->mode == MODE_MOV) {
1419
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 ||
1420
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 track->par->ch_layout.nb_channels > 2) {
1422
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1423 tag = AV_RL32("lpcm");
1424 4 version = 2;
1425
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) ||
1426 26 mov_pcm_be_gt16(track->par->codec_id) ||
1427
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1428
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1430 11 version = 1;
1431 }
1432
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 3 times.
89 } else if (track->mode == MODE_MP4) {
1433
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
86 if (track->par->sample_rate > UINT16_MAX &&
1434 (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG))
1435 5 version = 1;
1436 }
1437
1438 128 avio_wb32(pb, 0); /* size */
1439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (mov->encryption_scheme != MOV_ENC_NONE) {
1440 ffio_wfourcc(pb, "enca");
1441 } else {
1442 128 avio_wl32(pb, tag); // store it byteswapped
1443 }
1444 128 avio_wb32(pb, 0); /* Reserved */
1445 128 avio_wb16(pb, 0); /* Reserved */
1446 128 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1447
1448 /* SoundDescription */
1449 128 avio_wb16(pb, version); /* Version */
1450 128 avio_wb16(pb, 0); /* Revision level */
1451 128 avio_wb32(pb, 0); /* Reserved */
1452
1453
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 124 times.
128 if (version == 2) {
1454 4 avio_wb16(pb, 3);
1455 4 avio_wb16(pb, 16);
1456 4 avio_wb16(pb, 0xfffe);
1457 4 avio_wb16(pb, 0);
1458 4 avio_wb32(pb, 0x00010000);
1459 4 avio_wb32(pb, 72);
1460 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1461 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1462 4 avio_wb32(pb, 0x7F000000);
1463 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1464 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1465 4 avio_wb32(pb, track->sample_size);
1466 4 avio_wb32(pb, get_samples_per_packet(track));
1467 } else {
1468 124 unsigned sample_rate = track->par->sample_rate;
1469
1470
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 89 times.
124 if (track->mode == MODE_MOV) {
1471 35 avio_wb16(pb, track->par->ch_layout.nb_channels);
1472
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1473
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1474 1 avio_wb16(pb, 8); /* bits per sample */
1475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1476 avio_wb16(pb, track->par->bits_per_coded_sample);
1477 else
1478 34 avio_wb16(pb, 16);
1479
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26 times.
35 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1480 } else { /* reserved for mp4/3gp */
1481
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 5 times.
173 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1482 84 0 : track->par->ch_layout.nb_channels);
1483
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 5 times.
89 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 track->par->codec_id == AV_CODEC_ID_ALAC) {
1485 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1486 } else {
1487 84 avio_wb16(pb, 16);
1488 }
1489 89 avio_wb16(pb, 0);
1490
1491
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 89 times.
94 while (sample_rate > UINT16_MAX)
1492 5 sample_rate >>= 1;
1493 }
1494
1495 124 avio_wb16(pb, 0); /* packet size (= 0) */
1496
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 119 times.
124 if (track->tag == MKTAG('i','a','m','f'))
1497 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1499 avio_wb16(pb, 48000);
1500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1501 avio_wb32(pb, track->par->sample_rate);
1502 else
1503 119 avio_wb16(pb, sample_rate);
1504
1505
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
124 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1506 124 avio_wb16(pb, 0); /* Reserved */
1507 }
1508
1509
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 28 times.
128 if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */
1510
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) ||
1511 11 mov_pcm_be_gt16(track->par->codec_id))
1512 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1513 else
1514 9 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1515 11 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1516 11 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1517 11 avio_wb32(pb, 2); /* Bytes per sample */
1518 }
1519
1520
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
128 if (track->mode == MODE_MOV &&
1521
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
39 (track->par->codec_id == AV_CODEC_ID_AAC ||
1522
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AC3 ||
1523
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1524
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1525
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1526
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1527
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1528
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 ||
1529
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) ||
1530
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1531 14 ret = mov_write_wave_tag(s, pb, track);
1532
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 50 times.
114 else if (track->tag == MKTAG('m','p','4','a'))
1533 64 ret = mov_write_esds_tag(pb, track);
1534 #if CONFIG_IAMFENC
1535
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 45 times.
50 else if (track->tag == MKTAG('i','a','m','f'))
1536 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1537 #endif
1538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1539 ret = mov_write_amr_tag(pb, track);
1540
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 38 times.
45 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1541 7 ret = mov_write_ac3_tag(s, pb, track);
1542
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34 times.
38 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1543 4 ret = mov_write_eac3_tag(s, pb, track);
1544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1545 ret = mov_write_extradata_tag(pb, track);
1546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1547 ret = mov_write_wfex_tag(s, pb, track);
1548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1549 ret = mov_write_dfla_tag(pb, track);
1550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1551 ret = mov_write_dops_tag(s, pb, track);
1552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1553 ret = mov_write_dmlp_tag(s, pb, track);
1554
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) {
1555
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (track->par->sample_rate > UINT16_MAX)
1556 5 mov_write_srat_tag(pb, track);
1557
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1558 7 ret = mov_write_chnl_tag(s, pb, track);
1559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1560 return ret;
1561 9 ret = mov_write_pcmc_tag(s, pb, track);
1562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1563 ret = mov_write_glbl_tag(pb, track);
1564
1565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (ret < 0)
1566 return ret;
1567
1568
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
128 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1569
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 86 times.
86 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1570 return ret;
1571 }
1572
1573
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
128 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1574
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1575 return ret;
1576 }
1577
1578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (mov->encryption_scheme != MOV_ENC_NONE
1579 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1580 return ret;
1581 }
1582
1583
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
214 if (mov->write_btrt &&
1584 86 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1585 return ret;
1586
1587
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 42 times.
128 if (track->mode == MODE_MP4)
1588 86 track->entry_version = version;
1589
1590 128 ret = update_size(pb, pos);
1591 128 return ret;
1592 }
1593
1594 static int mov_write_d263_tag(AVIOContext *pb)
1595 {
1596 avio_wb32(pb, 0xf); /* size */
1597 ffio_wfourcc(pb, "d263");
1598 ffio_wfourcc(pb, "FFMP");
1599 avio_w8(pb, 0); /* decoder version */
1600 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1601 avio_w8(pb, 0xa); /* level */
1602 avio_w8(pb, 0); /* profile */
1603 return 0xf;
1604 }
1605
1606 2 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1607 {
1608 2 int64_t pos = avio_tell(pb);
1609
1610 2 avio_wb32(pb, 0);
1611 2 ffio_wfourcc(pb, "av1C");
1612 2 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1613 2 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1614 2 return update_size(pb, pos);
1615 }
1616
1617 59 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1618 {
1619 59 int64_t pos = avio_tell(pb);
1620
1621 59 avio_wb32(pb, 0);
1622 59 ffio_wfourcc(pb, "avcC");
1623 59 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1624 59 track->extradata_size[track->last_stsd_index]);
1625 59 return update_size(pb, pos);
1626 }
1627
1628 /* AVS3 Intelligent Media Coding
1629 * Information Technology - Intelligent Media Coding
1630 * Part 6: Intelligent Media Format
1631 */
1632 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1633 {
1634 if (len < 4)
1635 return AVERROR_INVALIDDATA;
1636
1637 if (data[0] == 1) {
1638 // In Avs3DecoderConfigurationRecord format
1639 avio_write(pb, data, len);
1640 return 0;
1641 }
1642
1643 avio_w8(pb, 1); // version
1644 avio_wb16(pb, len); // sequence_header_length
1645 avio_write(pb, data, len); // sequence_header
1646 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1647
1648 return 0;
1649 }
1650
1651 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1652 {
1653 int64_t pos = avio_tell(pb);
1654 avio_wb32(pb, 0);
1655 ffio_wfourcc(pb, "av3c");
1656 mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1657 track->extradata_size[track->last_stsd_index]);
1658 return update_size(pb, pos);
1659 }
1660
1661 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1662 {
1663 int64_t pos = avio_tell(pb);
1664
1665 avio_wb32(pb, 0);
1666 ffio_wfourcc(pb, "vpcC");
1667 ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1668 track->extradata_size[track->last_stsd_index], track->par);
1669 return update_size(pb, pos);
1670 }
1671
1672 11 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1673 {
1674 11 int64_t pos = avio_tell(pb);
1675
1676 11 avio_wb32(pb, 0);
1677 11 ffio_wfourcc(pb, "hvcC");
1678
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (track->tag == MKTAG('h','v','c','1'))
1679 3 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1680 3 track->extradata_size[track->last_stsd_index], 1, s);
1681 else
1682 8 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1683 8 track->extradata_size[track->last_stsd_index], 0, s);
1684 11 return update_size(pb, pos);
1685 }
1686
1687 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1688 {
1689 1 int64_t pos = avio_tell(pb);
1690 int ret;
1691
1692 1 avio_wb32(pb, 0);
1693 1 ffio_wfourcc(pb, "lhvC");
1694
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1695 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1696 1 track->extradata_size[track->last_stsd_index], 1, s);
1697 else
1698 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1699 track->extradata_size[track->last_stsd_index], 0, s);
1700
1701
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1702 avio_seek(pb, pos, SEEK_SET);
1703 return ret;
1704 }
1705
1706 1 return update_size(pb, pos);
1707 }
1708
1709 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1710 {
1711 1 int64_t pos = avio_tell(pb);
1712
1713 1 avio_wb32(pb, 0);
1714 1 ffio_wfourcc(pb, "evcC");
1715
1716
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1717 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1718 1 track->extradata_size[track->last_stsd_index], 1);
1719 else
1720 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1721 track->extradata_size[track->last_stsd_index], 0);
1722
1723 1 return update_size(pb, pos);
1724 }
1725
1726 static int mov_write_lvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1727 {
1728 int64_t pos = avio_tell(pb);
1729
1730 avio_wb32(pb, 0);
1731 ffio_wfourcc(pb, "lvcC");
1732
1733 ff_isom_write_lvcc(pb, track->extradata[track->last_stsd_index],
1734 track->extradata_size[track->last_stsd_index], s);
1735
1736 return update_size(pb, pos);
1737 }
1738
1739 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1740 {
1741 1 int64_t pos = avio_tell(pb);
1742
1743 1 avio_wb32(pb, 0);
1744 1 ffio_wfourcc(pb, "vvcC");
1745
1746 1 avio_w8 (pb, 0); /* version */
1747 1 avio_wb24(pb, 0); /* flags */
1748
1749
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1750 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1751 1 track->extradata_size[track->last_stsd_index], 1);
1752 else
1753 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1754 track->extradata_size[track->last_stsd_index], 0);
1755 1 return update_size(pb, pos);
1756 }
1757
1758 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1759 {
1760 1 int64_t pos = avio_tell(pb);
1761
1762 1 avio_wb32(pb, 0);
1763 1 ffio_wfourcc(pb, "apvC");
1764
1765 1 avio_w8 (pb, 0); /* version */
1766 1 avio_wb24(pb, 0); /* flags */
1767
1768 1 ff_isom_write_apvc(pb, track->apv, s);
1769
1770 1 return update_size(pb, pos);
1771 }
1772
1773 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1774 /* https://community.avid.com/forums/t/136517.aspx */
1775 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1776 {
1777 int interlaced;
1778 int cid;
1779 23 int display_width = track->par->width;
1780 const uint8_t *extradata;
1781
1782
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) {
1783
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) {
1784 /* looks like a DNxHD bit stream */
1785 23 extradata = track->extradata[track->last_stsd_index];
1786 } else {
1787 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1788 return 0;
1789 }
1790 } else {
1791 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1792 return 0;
1793 }
1794
1795 23 cid = AV_RB32(extradata + 0x28);
1796
1797 23 avio_wb32(pb, 24); /* size */
1798 23 ffio_wfourcc(pb, "ACLR");
1799 23 ffio_wfourcc(pb, "ACLR");
1800 23 ffio_wfourcc(pb, "0001");
1801 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1802 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1804 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1805 23 avio_wb32(pb, 1);
1806 } else {
1807 avio_wb32(pb, 2);
1808 }
1809 23 avio_wb32(pb, 0); /* reserved */
1810
1811
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1812 12 int alp = extradata[0x07] & 1;
1813 12 int pma = (extradata[0x07] >> 2) & 1;
1814 12 int sbd = (extradata[0x21] >> 5) & 3;
1815 12 int ssc = (extradata[0x2C] >> 5) & 3;
1816 12 int clv = (extradata[0x2C] >> 1) & 3;
1817 12 int clf = extradata[0x2C] & 1;
1818
1819 12 avio_wb32(pb, 32);
1820 12 ffio_wfourcc(pb, "ADHR");
1821 12 ffio_wfourcc(pb, "0001");
1822 12 avio_wb32(pb, cid); // Compression ID
1823 // 0: 4:2:2 Sub Sampling
1824 // 1: 4:2:0 Sub Sampling
1825 // 2: 4:4:4 Sub Sampling
1826 12 avio_wb32(pb, ssc); // Sub Sampling Control
1827 // 1: 8-bits per sample
1828 // 2: 10-bits per sample
1829 // 3: 12-bits per sample
1830 12 avio_wb32(pb, sbd); // Sample Bit Depth
1831 // 0: Bitstream is encoded using the YCBCR format rules and tables
1832 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1833 12 avio_wb16(pb, clf); // Color Format
1834 // 0: ITU-R BT.709
1835 // 1: ITU-R BT.2020
1836 // 2: ITU-R BT.2020 C
1837 // 3: Out-of-band
1838 12 avio_wb16(pb, clv); // Color Volume
1839 // 0: Alpha channel not present
1840 // 1: Alpha channel present
1841 12 avio_wb16(pb, alp); // Alpha Present
1842 // 0: Alpha has not been applied to video channels
1843 // 1: Alpha has been applied to the video channels prior to encoding
1844 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1845 12 return 0;
1846 }
1847
1848 11 interlaced = extradata[5] & 2;
1849
1850 11 avio_wb32(pb, 24); /* size */
1851 11 ffio_wfourcc(pb, "APRG");
1852 11 ffio_wfourcc(pb, "APRG");
1853 11 ffio_wfourcc(pb, "0001");
1854 // 1 for progressive or 2 for interlaced
1855
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1856 11 avio_wb32(pb, 2);
1857 else
1858 avio_wb32(pb, 1);
1859 11 avio_wb32(pb, 0); /* reserved */
1860
1861 11 avio_wb32(pb, 120); /* size */
1862 11 ffio_wfourcc(pb, "ARES");
1863 11 ffio_wfourcc(pb, "ARES");
1864 11 ffio_wfourcc(pb, "0001");
1865 11 avio_wb32(pb, cid); /* cid */
1866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1867 && track->par->sample_aspect_ratio.den > 0)
1868 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1869 11 avio_wb32(pb, display_width); // field width
1870
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1871 11 avio_wb32(pb, track->par->height / 2); // field height
1872 11 avio_wb32(pb, 2); // num fields
1873 11 avio_wb32(pb, 0); // num black lines (must be 0)
1874 // 4: HD1080i
1875 // 5: HD1080P
1876 // 6: HD720P
1877 11 avio_wb32(pb, 4); // video format
1878 } else {
1879 avio_wb32(pb, track->par->height);
1880 avio_wb32(pb, 1); // num fields
1881 avio_wb32(pb, 0);
1882 if (track->par->height == 1080)
1883 avio_wb32(pb, 5);
1884 else
1885 avio_wb32(pb, 6);
1886 }
1887 /* padding */
1888 11 ffio_fill(pb, 0, 10 * 8);
1889
1890 11 return 0;
1891 }
1892
1893 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1894 {
1895 avio_wb32(pb, 12);
1896 ffio_wfourcc(pb, "DpxE");
1897 if (track->extradata_size[track->last_stsd_index] >= 12 &&
1898 !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1899 avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1900 } else {
1901 avio_wb32(pb, 1);
1902 }
1903 return 0;
1904 }
1905
1906 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1907 {
1908 int tag;
1909
1910
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1911
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1912
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');
1913 1 else tag = MKTAG('d','v','c',' ');
1914 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1915 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1916 else tag = MKTAG('d','v','p','p');
1917 } else if (track->par->height == 720) { /* HD 720 line */
1918 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1919 else tag = MKTAG('d','v','h','p');
1920 } else if (track->par->height == 1080) { /* HD 1080 line */
1921 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1922 else tag = MKTAG('d','v','h','6');
1923 } else {
1924 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1925 return 0;
1926 }
1927
1928 1 return tag;
1929 }
1930
1931 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1932 {
1933 3 AVRational rational_framerate = st->avg_frame_rate;
1934 3 int rate = 0;
1935
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1936 3 rate = av_q2d(rational_framerate);
1937 3 return rate;
1938 }
1939
1940 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1941 {
1942 1 int tag = track->par->codec_tag;
1943 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1944 1 AVStream *st = track->st;
1945 1 int rate = defined_frame_rate(s, st);
1946
1947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1948 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1949
1950
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1951
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) {
1952 if (!interlaced) {
1953 if (rate == 24) tag = MKTAG('x','d','v','4');
1954 else if (rate == 25) tag = MKTAG('x','d','v','5');
1955 else if (rate == 30) tag = MKTAG('x','d','v','1');
1956 else if (rate == 50) tag = MKTAG('x','d','v','a');
1957 else if (rate == 60) tag = MKTAG('x','d','v','9');
1958 }
1959
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) {
1960 if (!interlaced) {
1961 if (rate == 24) tag = MKTAG('x','d','v','6');
1962 else if (rate == 25) tag = MKTAG('x','d','v','7');
1963 else if (rate == 30) tag = MKTAG('x','d','v','8');
1964 } else {
1965 if (rate == 25) tag = MKTAG('x','d','v','3');
1966 else if (rate == 30) tag = MKTAG('x','d','v','2');
1967 }
1968
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) {
1969 if (!interlaced) {
1970 if (rate == 24) tag = MKTAG('x','d','v','d');
1971 else if (rate == 25) tag = MKTAG('x','d','v','e');
1972 else if (rate == 30) tag = MKTAG('x','d','v','f');
1973 } else {
1974 if (rate == 25) tag = MKTAG('x','d','v','c');
1975 else if (rate == 30) tag = MKTAG('x','d','v','b');
1976 }
1977 }
1978 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1979 if (track->par->width == 1280 && track->par->height == 720) {
1980 if (!interlaced) {
1981 if (rate == 24) tag = MKTAG('x','d','5','4');
1982 else if (rate == 25) tag = MKTAG('x','d','5','5');
1983 else if (rate == 30) tag = MKTAG('x','d','5','1');
1984 else if (rate == 50) tag = MKTAG('x','d','5','a');
1985 else if (rate == 60) tag = MKTAG('x','d','5','9');
1986 }
1987 } else if (track->par->width == 1920 && track->par->height == 1080) {
1988 if (!interlaced) {
1989 if (rate == 24) tag = MKTAG('x','d','5','d');
1990 else if (rate == 25) tag = MKTAG('x','d','5','e');
1991 else if (rate == 30) tag = MKTAG('x','d','5','f');
1992 } else {
1993 if (rate == 25) tag = MKTAG('x','d','5','c');
1994 else if (rate == 30) tag = MKTAG('x','d','5','b');
1995 }
1996 }
1997 }
1998
1999 1 return tag;
2000 }
2001
2002 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
2003 {
2004 2 int tag = track->par->codec_tag;
2005 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2006 2 AVStream *st = track->st;
2007 2 int rate = defined_frame_rate(s, st);
2008
2009
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
2010 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
2011
2012
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
2013
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
2014 2 return tag;
2015
2016 if (track->par->format == AV_PIX_FMT_YUV420P10) {
2017 if (track->par->width == 960 && track->par->height == 720) {
2018 if (!interlaced) {
2019 if (rate == 24) tag = MKTAG('a','i','5','p');
2020 else if (rate == 25) tag = MKTAG('a','i','5','q');
2021 else if (rate == 30) tag = MKTAG('a','i','5','p');
2022 else if (rate == 50) tag = MKTAG('a','i','5','q');
2023 else if (rate == 60) tag = MKTAG('a','i','5','p');
2024 }
2025 } else if (track->par->width == 1440 && track->par->height == 1080) {
2026 if (!interlaced) {
2027 if (rate == 24) tag = MKTAG('a','i','5','3');
2028 else if (rate == 25) tag = MKTAG('a','i','5','2');
2029 else if (rate == 30) tag = MKTAG('a','i','5','3');
2030 } else {
2031 if (rate == 50) tag = MKTAG('a','i','5','5');
2032 else if (rate == 60) tag = MKTAG('a','i','5','6');
2033 }
2034 }
2035 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
2036 if (track->par->width == 1280 && track->par->height == 720) {
2037 if (!interlaced) {
2038 if (rate == 24) tag = MKTAG('a','i','1','p');
2039 else if (rate == 25) tag = MKTAG('a','i','1','q');
2040 else if (rate == 30) tag = MKTAG('a','i','1','p');
2041 else if (rate == 50) tag = MKTAG('a','i','1','q');
2042 else if (rate == 60) tag = MKTAG('a','i','1','p');
2043 }
2044 } else if (track->par->width == 1920 && track->par->height == 1080) {
2045 if (!interlaced) {
2046 if (rate == 24) tag = MKTAG('a','i','1','3');
2047 else if (rate == 25) tag = MKTAG('a','i','1','2');
2048 else if (rate == 30) tag = MKTAG('a','i','1','3');
2049 } else {
2050 if (rate == 25) tag = MKTAG('a','i','1','5');
2051 else if (rate == 50) tag = MKTAG('a','i','1','5');
2052 else if (rate == 60) tag = MKTAG('a','i','1','6');
2053 }
2054 } else if ( track->par->width == 4096 && track->par->height == 2160
2055 || track->par->width == 3840 && track->par->height == 2160
2056 || track->par->width == 2048 && track->par->height == 1080) {
2057 tag = MKTAG('a','i','v','x');
2058 }
2059 }
2060
2061 return tag;
2062 }
2063
2064 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
2065 {
2066 int tag = track->par->codec_tag;
2067
2068 if (!tag)
2069 tag = MKTAG('e', 'v', 'c', '1');
2070
2071 return tag;
2072 }
2073
2074 static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
2075 {
2076 int tag = track->par->codec_tag;
2077
2078 if (!tag)
2079 tag = MKTAG('a', 'p', 'v', '1');
2080
2081 return tag;
2082 }
2083
2084
2085 static const struct {
2086 enum AVPixelFormat pix_fmt;
2087 uint32_t tag;
2088 unsigned bps;
2089 } mov_pix_fmt_tags[] = {
2090 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
2091 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2092 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2093 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2094 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2095 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2096 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2097 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2098 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2099 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2100 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2101 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2102 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2103 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2104 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2105 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2106 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2107 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2108 };
2109
2110 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2111 {
2112 23 int tag = MKTAG('A','V','d','n');
2113
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2114
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2115 12 tag = MKTAG('A','V','d','h');
2116 23 return tag;
2117 }
2118
2119 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2120 {
2121 17 int tag = track->par->codec_tag;
2122 int i;
2123 enum AVPixelFormat pix_fmt;
2124
2125
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++) {
2126
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2127 17 tag = mov_pix_fmt_tags[i].tag;
2128 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2129
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2130 5 break;
2131 }
2132 }
2133
2134 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2135 17 track->par->bits_per_coded_sample);
2136
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2138 track->par->format != AV_PIX_FMT_GRAY8 &&
2139 track->par->format != AV_PIX_FMT_NONE)
2140 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2141 av_get_pix_fmt_name(track->par->format));
2142 17 return tag;
2143 }
2144
2145 170 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2146 {
2147 170 unsigned int tag = track->par->codec_tag;
2148
2149 // "rtp " is used to distinguish internally created RTP-hint tracks
2150 // (with rtp_ctx) from other tracks.
2151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (tag == MKTAG('r','t','p',' '))
2152 tag = 0;
2153
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 &&
2154
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2155
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 17 times.
133 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2156
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 track->par->codec_id == AV_CODEC_ID_H263 ||
2157
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 2 times.
116 track->par->codec_id == AV_CODEC_ID_H264 ||
2158
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 23 times.
114 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2159
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 ||
2160 90 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2161
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2162 1 tag = mov_get_dv_codec_tag(s, track);
2163
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2164 17 tag = mov_get_rawvideo_codec_tag(s, track);
2165
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2166 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2167
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2168 2 tag = mov_get_h264_codec_tag(s, track);
2169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2170 tag = mov_get_evc_codec_tag(s, track);
2171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2172 tag = mov_get_apv_codec_tag(s, track);
2173
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2174 23 tag = mov_get_dnxhd_codec_tag(s, track);
2175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2176 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2177 if (!tag) { // if no mac fcc found, try with Microsoft tags
2178 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2179 if (tag)
2180 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2181 "the file may be unplayable!\n");
2182 }
2183
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2184 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2186 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2187 if (ms_tag) {
2188 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2189 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2190 "the file may be unplayable!\n");
2191 }
2192 }
2193 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2194 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2195 }
2196
2197 170 return tag;
2198 }
2199
2200 static const AVCodecTag codec_cover_image_tags[] = {
2201 { AV_CODEC_ID_MJPEG, 0xD },
2202 { AV_CODEC_ID_PNG, 0xE },
2203 { AV_CODEC_ID_BMP, 0x1B },
2204 { AV_CODEC_ID_NONE, 0 },
2205 };
2206
2207 132 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2208 unsigned int tag, int codec_id)
2209 {
2210 int i;
2211
2212 /**
2213 * Check that tag + id is in the table
2214 */
2215
2/4
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
132 for (i = 0; tags && tags[i]; i++) {
2216 132 const AVCodecTag *codec_tags = tags[i];
2217
1/2
✓ Branch 0 taken 2130 times.
✗ Branch 1 not taken.
2130 while (codec_tags->id != AV_CODEC_ID_NONE) {
2218
2/2
✓ Branch 2 taken 154 times.
✓ Branch 3 taken 1976 times.
2130 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2219
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 22 times.
154 codec_tags->id == codec_id)
2220 132 return codec_tags->tag;
2221 1998 codec_tags++;
2222 }
2223 }
2224 return 0;
2225 }
2226
2227 304 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2228 {
2229
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 302 times.
304 if (is_cover_image(track->st))
2230 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2231
2232
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 301 times.
302 if (track->mode == MODE_IPOD)
2233
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") &&
2234
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2235 1 !av_match_ext(s->url, "m4b"))
2236 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2237 "Quicktime/Ipod might not play the file\n");
2238
2239
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 132 times.
302 if (track->mode == MODE_MOV) {
2240 170 return mov_get_codec_tag(s, track);
2241 } else
2242 132 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2243 132 track->par->codec_id);
2244 }
2245
2246 /** Write uuid atom.
2247 * Needed to make file play in iPods running newest firmware
2248 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2249 */
2250 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2251 {
2252 avio_wb32(pb, 28);
2253 ffio_wfourcc(pb, "uuid");
2254 avio_wb32(pb, 0x6b6840f2);
2255 avio_wb32(pb, 0x5f244fc5);
2256 avio_wb32(pb, 0xba39a51b);
2257 avio_wb32(pb, 0xcf0323f3);
2258 avio_wb32(pb, 0x0);
2259 return 28;
2260 }
2261
2262 static const uint16_t fiel_data[] = {
2263 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2264 };
2265
2266 101 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2267 {
2268 101 unsigned mov_field_order = 0;
2269
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2270 101 mov_field_order = fiel_data[field_order];
2271 else
2272 return 0;
2273 101 avio_wb32(pb, 10);
2274 101 ffio_wfourcc(pb, "fiel");
2275 101 avio_wb16(pb, mov_field_order);
2276 101 return 10;
2277 }
2278
2279 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2280 {
2281 6 MOVMuxContext *mov = s->priv_data;
2282 6 int ret = AVERROR_BUG;
2283 6 int64_t pos = avio_tell(pb);
2284 6 avio_wb32(pb, 0); /* size */
2285 6 avio_wl32(pb, track->tag); // store it byteswapped
2286 6 avio_wb32(pb, 0); /* Reserved */
2287 6 avio_wb16(pb, 0); /* Reserved */
2288 6 avio_wb16(pb, 1); /* Data-reference index */
2289
2290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2291 mov_write_esds_tag(pb, track);
2292
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2293
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2294 2 case MOV_ISMV_TTML_TAG:
2295 // ISMV dfxp requires no extradata.
2296 4 break;
2297 2 case MOV_MP4_TTML_TAG:
2298 // As specified in 14496-30, XMLSubtitleSampleEntry
2299 // Namespace
2300 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2301 // Empty schema_location
2302 2 avio_w8(pb, 0);
2303 // Empty auxiliary_mime_types
2304 2 avio_w8(pb, 0);
2305 2 break;
2306 default:
2307 av_log(NULL, AV_LOG_ERROR,
2308 "Unknown codec tag '%s' utilized for TTML stream with "
2309 "index %d (track id %d)!\n",
2310 av_fourcc2str(track->par->codec_tag), track->st->index,
2311 track->track_id);
2312 return AVERROR(EINVAL);
2313 }
2314
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2315 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2316
2317
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 &&
2318 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2319 return ret;
2320
2321 6 return update_size(pb, pos);
2322 }
2323
2324 1 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2325 {
2326 int8_t stereo_mode;
2327
2328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo_3d->flags != 0) {
2329 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2330 return 0;
2331 }
2332
2333
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo_3d->type) {
2334 case AV_STEREO3D_2D:
2335 stereo_mode = 0;
2336 break;
2337 case AV_STEREO3D_TOPBOTTOM:
2338 stereo_mode = 1;
2339 break;
2340 1 case AV_STEREO3D_SIDEBYSIDE:
2341 1 stereo_mode = 2;
2342 1 break;
2343 default:
2344 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2345 return 0;
2346 }
2347 1 avio_wb32(pb, 13); /* size */
2348 1 ffio_wfourcc(pb, "st3d");
2349 1 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2350 1 avio_w8(pb, stereo_mode);
2351 1 return 13;
2352 }
2353
2354 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2355 {
2356 int64_t sv3d_pos, svhd_pos, proj_pos;
2357 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2358
2359 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2360 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2361 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2362 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2363 return 0;
2364 }
2365
2366 sv3d_pos = avio_tell(pb);
2367 avio_wb32(pb, 0); /* size */
2368 ffio_wfourcc(pb, "sv3d");
2369
2370 svhd_pos = avio_tell(pb);
2371 avio_wb32(pb, 0); /* size */
2372 ffio_wfourcc(pb, "svhd");
2373 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2374 avio_put_str(pb, metadata_source);
2375 update_size(pb, svhd_pos);
2376
2377 proj_pos = avio_tell(pb);
2378 avio_wb32(pb, 0); /* size */
2379 ffio_wfourcc(pb, "proj");
2380
2381 avio_wb32(pb, 24); /* size */
2382 ffio_wfourcc(pb, "prhd");
2383 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2384 avio_wb32(pb, spherical_mapping->yaw);
2385 avio_wb32(pb, spherical_mapping->pitch);
2386 avio_wb32(pb, spherical_mapping->roll);
2387
2388 switch (spherical_mapping->projection) {
2389 case AV_SPHERICAL_EQUIRECTANGULAR:
2390 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2391 avio_wb32(pb, 28); /* size */
2392 ffio_wfourcc(pb, "equi");
2393 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2394 avio_wb32(pb, spherical_mapping->bound_top);
2395 avio_wb32(pb, spherical_mapping->bound_bottom);
2396 avio_wb32(pb, spherical_mapping->bound_left);
2397 avio_wb32(pb, spherical_mapping->bound_right);
2398 break;
2399 case AV_SPHERICAL_CUBEMAP:
2400 avio_wb32(pb, 20); /* size */
2401 ffio_wfourcc(pb, "cbmp");
2402 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2403 avio_wb32(pb, 0); /* layout */
2404 avio_wb32(pb, spherical_mapping->padding); /* padding */
2405 break;
2406 }
2407 update_size(pb, proj_pos);
2408
2409 return update_size(pb, sv3d_pos);
2410 }
2411
2412 5 static inline int64_t rescale_rational(AVRational q, int b)
2413 {
2414 5 return av_rescale(q.num, b, q.den);
2415 }
2416
2417 2 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2418 const AVStereo3D *stereo3d)
2419 {
2420
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!stereo3d->horizontal_field_of_view.num)
2421 1 return;
2422
2423 1 avio_wb32(pb, 12); /* size */
2424 1 ffio_wfourcc(pb, "hfov");
2425 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2426 }
2427
2428 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2429 const AVSphericalMapping *spherical_mapping)
2430 {
2431 1 avio_wb32(pb, 24); /* size */
2432 1 ffio_wfourcc(pb, "proj");
2433 1 avio_wb32(pb, 16); /* size */
2434 1 ffio_wfourcc(pb, "prji");
2435 1 avio_wb32(pb, 0); /* version + flags */
2436
2437
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) {
2438 1 case AV_SPHERICAL_RECTILINEAR:
2439 1 ffio_wfourcc(pb, "rect");
2440 1 break;
2441 case AV_SPHERICAL_EQUIRECTANGULAR:
2442 ffio_wfourcc(pb, "equi");
2443 break;
2444 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2445 ffio_wfourcc(pb, "hequ");
2446 break;
2447 case AV_SPHERICAL_FISHEYE:
2448 ffio_wfourcc(pb, "fish");
2449 break;
2450 default:
2451 av_assert0(0);
2452 }
2453 1 }
2454
2455 2 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2456 const AVStereo3D *stereo3d)
2457 {
2458 2 int64_t pos = avio_tell(pb);
2459 2 int view = 0;
2460
2461 2 avio_wb32(pb, 0); /* size */
2462 2 ffio_wfourcc(pb, "eyes");
2463
2464 // stri is mandatory
2465 2 avio_wb32(pb, 13); /* size */
2466 2 ffio_wfourcc(pb, "stri");
2467 2 avio_wb32(pb, 0); /* version + flags */
2468
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 switch (stereo3d->view) {
2469 case AV_STEREO3D_VIEW_LEFT:
2470 view |= 1 << 0;
2471 break;
2472 case AV_STEREO3D_VIEW_RIGHT:
2473 view |= 1 << 1;
2474 break;
2475 2 case AV_STEREO3D_VIEW_PACKED:
2476 2 view |= (1 << 0) | (1 << 1);
2477 2 break;
2478 }
2479 2 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2480 2 avio_w8(pb, view);
2481
2482 // hero is optional
2483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2484 avio_wb32(pb, 13); /* size */
2485 ffio_wfourcc(pb, "hero");
2486 avio_wb32(pb, 0); /* version + flags */
2487 avio_w8(pb, stereo3d->primary_eye);
2488 }
2489
2490 // it's not clear if cams is mandatory or optional
2491
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->baseline) {
2492 1 avio_wb32(pb, 24); /* size */
2493 1 ffio_wfourcc(pb, "cams");
2494 1 avio_wb32(pb, 16); /* size */
2495 1 ffio_wfourcc(pb, "blin");
2496 1 avio_wb32(pb, 0); /* version + flags */
2497 1 avio_wb32(pb, stereo3d->baseline);
2498 }
2499
2500 // it's not clear if cmfy is mandatory or optional
2501
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->horizontal_disparity_adjustment.num) {
2502 1 avio_wb32(pb, 24); /* size */
2503 1 ffio_wfourcc(pb, "cmfy");
2504 1 avio_wb32(pb, 16); /* size */
2505 1 ffio_wfourcc(pb, "dadj");
2506 1 avio_wb32(pb, 0); /* version + flags */
2507 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2508 }
2509
2510 2 return update_size(pb, pos);
2511 }
2512
2513 2 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2514 const AVStereo3D *stereo3d,
2515 const AVSphericalMapping *spherical_mapping)
2516 {
2517 int64_t pos;
2518
2519
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping &&
2520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2521 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2522 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2523 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2524 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2525 spherical_mapping->projection);
2526 spherical_mapping = NULL;
2527 }
2528
2529
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 ||
2530
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2532 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2533 !stereo3d->baseline &&
2534 !stereo3d->horizontal_disparity_adjustment.num))) {
2535 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2536 stereo3d = NULL;
2537 }
2538
2539
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)
2540 return 0;
2541
2542 2 pos = avio_tell(pb);
2543 2 avio_wb32(pb, 0); /* size */
2544 2 ffio_wfourcc(pb, "vexu");
2545
2546
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping)
2547 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2548
2549
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (stereo3d)
2550 2 mov_write_eyes_tag(s, pb, stereo3d);
2551
2552 2 return update_size(pb, pos);
2553 }
2554
2555 2 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2556 {
2557 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2558
2559 2 avio_wb32(pb, 32); /* size = 8 + 24 */
2560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (dovi->dv_profile > 10)
2561 ffio_wfourcc(pb, "dvwC");
2562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (dovi->dv_profile > 7)
2563 ffio_wfourcc(pb, "dvvC");
2564 else
2565 2 ffio_wfourcc(pb, "dvcC");
2566
2567 2 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2568 2 avio_write(pb, buf, sizeof(buf));
2569
2570 2 return 32; /* 8 + 24 */
2571 }
2572
2573 2 static int mov_write_hvce_tag(AVIOContext *pb, const AVPacketSideData *sd)
2574 {
2575 2 avio_wb32(pb, 8 + sd->size);
2576 2 ffio_wfourcc(pb, "hvcE");
2577 2 avio_write(pb, sd->data, sd->size);
2578 2 return 8 + sd->size;
2579 }
2580
2581 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2582 uint32_t top, uint32_t bottom,
2583 uint32_t left, uint32_t right)
2584 {
2585 5 uint32_t cropped_width = track->par->width - left - right;
2586 5 uint32_t cropped_height = track->height - top - bottom;
2587 AVRational horizOff =
2588 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2589 5 (AVRational) { left, 1 });
2590 AVRational vertOff =
2591 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2592 5 (AVRational) { top, 1 });
2593
2594 5 avio_wb32(pb, 40);
2595 5 ffio_wfourcc(pb, "clap");
2596 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2597 5 avio_wb32(pb, 1); /* apertureWidthD */
2598 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2599 5 avio_wb32(pb, 1); /* apertureHeightD */
2600
2601 5 avio_wb32(pb, -horizOff.num);
2602 5 avio_wb32(pb, horizOff.den);
2603 5 avio_wb32(pb, -vertOff.num);
2604 5 avio_wb32(pb, vertOff.den);
2605
2606 5 return 40;
2607 }
2608
2609 26 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2610 {
2611 AVRational sar;
2612 26 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2613 26 track->par->sample_aspect_ratio.den, INT_MAX);
2614
2615 26 avio_wb32(pb, 16);
2616 26 ffio_wfourcc(pb, "pasp");
2617 26 avio_wb32(pb, sar.num);
2618 26 avio_wb32(pb, sar.den);
2619 26 return 16;
2620 }
2621
2622 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2623 {
2624 uint32_t gama = 0;
2625 if (gamma <= 0.0)
2626 gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2627 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2628
2629 if (gamma > 1e-6) {
2630 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2631 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2632
2633 av_assert0(track->mode == MODE_MOV);
2634 avio_wb32(pb, 12);
2635 ffio_wfourcc(pb, "gama");
2636 avio_wb32(pb, gama);
2637 return 12;
2638 } else {
2639 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2640 }
2641 return 0;
2642 }
2643
2644 12 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2645 {
2646 12 int64_t pos = avio_tell(pb);
2647
2648 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2649 // Ref (MP4): ISO/IEC 14496-12:2012
2650
2651
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (prefer_icc) {
2652 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2653 4 track->st->codecpar->nb_coded_side_data,
2654 AV_PKT_DATA_ICC_PROFILE);
2655
2656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2657 avio_wb32(pb, 12 + sd->size);
2658 ffio_wfourcc(pb, "colr");
2659 ffio_wfourcc(pb, "prof");
2660 avio_write(pb, sd->data, sd->size);
2661 return 12 + sd->size;
2662 }
2663 else {
2664 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2665 }
2666 }
2667
2668 /* We should only ever be called for MOV, MP4 and AVIF. */
2669
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 ||
2670 track->mode == MODE_AVIF);
2671
2672 12 avio_wb32(pb, 0); /* size */
2673 12 ffio_wfourcc(pb, "colr");
2674
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)
2675 4 ffio_wfourcc(pb, "nclx");
2676 else
2677 8 ffio_wfourcc(pb, "nclc");
2678 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2679 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2680 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2681 12 avio_wb16(pb, track->par->color_primaries);
2682 12 avio_wb16(pb, track->par->color_trc);
2683 12 avio_wb16(pb, track->par->color_space);
2684
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) {
2685 4 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2686 4 avio_w8(pb, full_range << 7);
2687 }
2688
2689 12 return update_size(pb, pos);
2690 }
2691
2692 228 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2693 {
2694 const AVPacketSideData *side_data;
2695 const AVContentLightMetadata *content_light_metadata;
2696
2697 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2698 228 track->st->codecpar->nb_coded_side_data,
2699 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2700
1/2
✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
228 if (!side_data) {
2701 228 return 0;
2702 }
2703 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2704
2705 avio_wb32(pb, 12); // size
2706 ffio_wfourcc(pb, "clli");
2707 avio_wb16(pb, content_light_metadata->MaxCLL);
2708 avio_wb16(pb, content_light_metadata->MaxFALL);
2709 return 12;
2710 }
2711
2712 228 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2713 {
2714 228 const int chroma_den = 50000;
2715 228 const int luma_den = 10000;
2716 const AVPacketSideData *side_data;
2717 228 const AVMasteringDisplayMetadata *metadata = NULL;
2718
2719 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2720 228 track->st->codecpar->nb_coded_side_data,
2721 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 228 times.
228 if (side_data)
2723 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2724
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) {
2725 228 return 0;
2726 }
2727
2728 avio_wb32(pb, 32); // size
2729 ffio_wfourcc(pb, "mdcv");
2730 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2731 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2732 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2733 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2734 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2735 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2736 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2737 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2738 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2739 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2740 return 32;
2741 }
2742
2743 228 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2744 {
2745 228 const int illuminance_den = 10000;
2746 228 const int ambient_den = 50000;
2747 const AVPacketSideData *side_data;
2748 const AVAmbientViewingEnvironment *ambient;
2749
2750
2751 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2752 228 track->st->codecpar->nb_coded_side_data,
2753 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2754
2755
2/2
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 1 times.
228 if (!side_data)
2756 227 return 0;
2757
2758 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2759
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)
2760 return 0;
2761
2762 1 avio_wb32(pb, 16); // size
2763 1 ffio_wfourcc(pb, "amve");
2764 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2765 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2766 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2767 1 return 16;
2768 }
2769
2770 234 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2771 {
2772 AVDictionaryEntry *encoder;
2773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2774
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)
2775
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);
2776
2777
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if ((track->mode == MODE_AVIF ||
2778
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
234 track->mode == MODE_MOV ||
2779
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) &&
2780 228 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2781 159 av_strlcpy(compressor_name, encoder->value, 32);
2782
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) {
2783 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2784 AVStream *st = track->st;
2785 int rate = defined_frame_rate(NULL, st);
2786 av_strlcatf(compressor_name, len, "XDCAM");
2787 if (track->par->format == AV_PIX_FMT_YUV422P) {
2788 av_strlcatf(compressor_name, len, " HD422");
2789 } else if(track->par->width == 1440) {
2790 av_strlcatf(compressor_name, len, " HD");
2791 } else
2792 av_strlcatf(compressor_name, len, " EX");
2793
2794 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2795
2796 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2797 }
2798 234 }
2799
2800 static int mov_write_ccst_tag(AVIOContext *pb)
2801 {
2802 int64_t pos = avio_tell(pb);
2803 // Write sane defaults:
2804 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2805 // intra_pred_used = 1 : intra prediction may or may not be used.
2806 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2807 // reference images can be used.
2808 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2809 (1 << 6) | /* intra_pred_used */
2810 (15 << 2); /* max_ref_per_pic */
2811 avio_wb32(pb, 0); /* size */
2812 ffio_wfourcc(pb, "ccst");
2813 avio_wb32(pb, 0); /* Version & flags */
2814 avio_w8(pb, ccstValue);
2815 avio_wb24(pb, 0); /* reserved */
2816 return update_size(pb, pos);
2817 }
2818
2819 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2820 {
2821 int64_t pos = avio_tell(pb);
2822 avio_wb32(pb, 0); /* size */
2823 ffio_wfourcc(pb, aux_type);
2824 avio_wb32(pb, 0); /* Version & flags */
2825 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2826 return update_size(pb, pos);
2827 }
2828
2829 234 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2830 {
2831 234 int ret = AVERROR_BUG;
2832 234 int64_t pos = avio_tell(pb);
2833 const AVPacketSideData *sd;
2834 234 char compressor_name[32] = { 0 };
2835 234 int avid = 0;
2836
2837
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)
2838
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)
2839
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)
2840
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)
2841
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)
2842
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);
2843
2844 234 avio_wb32(pb, 0); /* size */
2845
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 228 times.
234 if (mov->encryption_scheme != MOV_ENC_NONE) {
2846 6 ffio_wfourcc(pb, "encv");
2847 } else {
2848 228 avio_wl32(pb, track->tag); // store it byteswapped
2849 }
2850 234 avio_wb32(pb, 0); /* Reserved */
2851 234 avio_wb16(pb, 0); /* Reserved */
2852 234 avio_wb16(pb, 1); /* Data-reference index */
2853
2854
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 230 times.
234 if (uncompressed_ycbcr) {
2855 4 avio_wb16(pb, 2); /* Codec stream version */
2856 } else {
2857 230 avio_wb16(pb, 0); /* Codec stream version */
2858 }
2859 234 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2860
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
234 if (track->mode == MODE_MOV) {
2861 144 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2862
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) {
2863 17 avio_wb32(pb, 0); /* Temporal Quality */
2864 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2865 } else {
2866 127 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2867 127 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2868 }
2869 } else {
2870 90 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2871 }
2872 234 avio_wb16(pb, track->par->width); /* Video width */
2873 234 avio_wb16(pb, track->height); /* Video height */
2874 234 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2875 234 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2876 234 avio_wb32(pb, 0); /* Data size (= 0) */
2877 234 avio_wb16(pb, 1); /* Frame count (= 1) */
2878
2879 234 find_compressor(compressor_name, 32, track);
2880 234 avio_w8(pb, strlen(compressor_name));
2881 234 avio_write(pb, compressor_name, 31);
2882
2883
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)
2884 avio_wb16(pb, 0x18);
2885
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)
2886 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2887
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2888 else
2889 201 avio_wb16(pb, 0x18); /* Reserved */
2890
2891
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) {
2892 int pal_size, i;
2893 5 avio_wb16(pb, 0); /* Color table ID */
2894 5 avio_wb32(pb, 0); /* Color table seed */
2895 5 avio_wb16(pb, 0x8000); /* Color table flags */
2896
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)
2897 return AVERROR(EINVAL);
2898 5 pal_size = 1 << track->par->bits_per_coded_sample;
2899 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2900
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2901 1040 uint32_t rgb = track->palette[i];
2902 1040 uint16_t r = (rgb >> 16) & 0xff;
2903 1040 uint16_t g = (rgb >> 8) & 0xff;
2904 1040 uint16_t b = rgb & 0xff;
2905 1040 avio_wb16(pb, 0);
2906 1040 avio_wb16(pb, (r << 8) | r);
2907 1040 avio_wb16(pb, (g << 8) | g);
2908 1040 avio_wb16(pb, (b << 8) | b);
2909 }
2910 } else
2911 229 avio_wb16(pb, 0xffff); /* Reserved */
2912
2913
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 198 times.
234 if (track->tag == MKTAG('m','p','4','v'))
2914 36 mov_write_esds_tag(pb, track);
2915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 else if (track->par->codec_id == AV_CODEC_ID_H263)
2916 mov_write_d263_tag(pb);
2917
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 3 times.
198 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2919 3 mov_write_extradata_tag(pb, track);
2920 3 avio_wb32(pb, 0);
2921
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 172 times.
195 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2922 23 mov_write_avid_tag(pb, track);
2923 23 avid = 1;
2924
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 161 times.
172 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2925 11 mov_write_hvcc_tag(mov->fc, pb, track);
2926
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2927 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2929 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2930 }
2931
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160 times.
161 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2932 1 mov_write_vvcc_tag(pb, track);
2933
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)) {
2934 59 mov_write_avcc_tag(pb, track);
2935
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 if (track->mode == MODE_IPOD)
2936 mov_write_uuid_tag_ipod(pb);
2937 }
2938
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2939 1 mov_write_evcc_tag(pb, track);
2940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 } else if (track->par->codec_id == AV_CODEC_ID_LCEVC) {
2941 mov_write_lvcc_tag(mov->fc, pb, track);
2942
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2943 1 mov_write_apvc_tag(mov->fc, pb, track);
2944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2945 mov_write_vpcc_tag(mov->fc, pb, track);
2946
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 97 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2947 2 mov_write_av1c_tag(pb, track);
2948
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)
2949 mov_write_dvc1_tag(pb, track);
2950
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2951
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2952 /* Don't write any potential extradata here - the cropping
2953 * is signalled via the normal width/height fields. */
2954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2955 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2956 mov_write_dpxe_tag(pb, track);
2957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2958 mov_write_av3c_tag(pb, track);
2959
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
2960 4 mov_write_glbl_tag(pb, track);
2961
2962
2/2
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 59 times.
234 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2963
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2964
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 23 times.
145 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2965 122 int field_order = track->par->field_order;
2966
2967
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 21 times.
122 if (field_order != AV_FIELD_UNKNOWN)
2968 101 mov_write_fiel_tag(pb, track, field_order);
2969 }
2970
2971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2972 if (track->mode == MODE_MOV)
2973 mov_write_gama_tag(s, pb, track, mov->gamma);
2974 else
2975 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2976 }
2977
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) {
2978 464 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2979
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 &&
2980
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2981
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 ||
2982 216 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2983 AV_PKT_DATA_ICC_PROFILE)) {
2984
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;
2985 12 mov_write_colr_tag(pb, track, prefer_icc);
2986 }
2987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2988 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2989 }
2990
2991
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) {
2992 228 mov_write_clli_tag(pb, track);
2993 228 mov_write_mdcv_tag(pb, track);
2994 228 mov_write_amve_tag(pb, track);
2995 }
2996
2997
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
234 if (track->mode == MODE_MP4) {
2998 84 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2999 84 track->st->codecpar->nb_coded_side_data,
3000 AV_PKT_DATA_STEREO3D);
3001 84 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3002 84 track->st->codecpar->nb_coded_side_data,
3003 AV_PKT_DATA_SPHERICAL);
3004
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)
3005 1 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
3006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 else if (stereo_3d)
3007 av_log(s, AV_LOG_WARNING, "Writing supported 'st3d' metadata requires -strict unofficial.\n");
3008
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)
3009 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
3010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 else if (spherical_mapping)
3011 av_log(s, AV_LOG_WARNING, "Writing supported 'sv3d' metadata requires -strict unofficial.\n");
3012 }
3013
3014
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 &&
3015
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 81 times.
84 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
3016 147 const AVStereo3D *stereo3d = NULL;
3017 147 const AVSphericalMapping *spherical_mapping = NULL;
3018
3019 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3020 147 track->st->codecpar->nb_coded_side_data,
3021 AV_PKT_DATA_STEREO3D);
3022
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (sd)
3023 2 stereo3d = (AVStereo3D *)sd->data;
3024
3025 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3026 147 track->st->codecpar->nb_coded_side_data,
3027 AV_PKT_DATA_SPHERICAL);
3028
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 146 times.
147 if (sd)
3029 1 spherical_mapping = (AVSphericalMapping *)sd->data;
3030
3031
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)
3032 2 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
3033
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (stereo3d)
3034 2 mov_write_hfov_tag(s, pb, stereo3d);
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 *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3039 84 track->st->codecpar->nb_coded_side_data,
3040 AV_PKT_DATA_DOVI_CONF);
3041
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) {
3042 2 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
3043
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (dovi) {
3044 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
3045 }
3046
3047 84 const AVPacketSideData *hvce = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3048 84 track->st->codecpar->nb_coded_side_data,
3049 AV_PKT_DATA_HEVC_CONF);
3050
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) {
3051 2 mov_write_hvce_tag(pb, hvce);
3052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (hvce) {
3053 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'hvcE' box. Requires -strict unofficial.\n");
3054 }
3055 }
3056
3057
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) {
3058 26 mov_write_pasp_tag(pb, track);
3059 }
3060
3061 234 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3062 234 track->st->codecpar->nb_coded_side_data,
3063 AV_PKT_DATA_FRAME_CROPPING);
3064
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) {
3065 1 uint64_t top = AV_RL32(sd->data + 0);
3066 1 uint64_t bottom = AV_RL32(sd->data + 4);
3067 1 uint64_t left = AV_RL32(sd->data + 8);
3068 1 uint64_t right = AV_RL32(sd->data + 12);
3069
3070
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
3071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
3072 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
3073 return AVERROR(EINVAL);
3074 }
3075
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)
3076 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
3077
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 229 times.
233 } else if (uncompressed_ycbcr)
3078 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
3079
3080
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 228 times.
234 if (mov->encryption_scheme != MOV_ENC_NONE) {
3081 6 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
3082 }
3083
3084
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 &&
3085 84 ((ret = mov_write_btrt_tag(pb, track)) < 0))
3086 return ret;
3087
3088 /* extra padding for avid stsd */
3089 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3090
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 211 times.
234 if (avid)
3091 23 avio_wb32(pb, 0);
3092
3093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (track->mode == MODE_AVIF) {
3094 mov_write_ccst_tag(pb);
3095 if (mov->nb_streams > 0 && track == &mov->tracks[1])
3096 mov_write_aux_tag(pb, "auxi");
3097 }
3098
3099 234 return update_size(pb, pos);
3100 }
3101
3102 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
3103 {
3104 2 int64_t pos = avio_tell(pb);
3105 2 avio_wb32(pb, 0); /* size */
3106 2 ffio_wfourcc(pb, "rtp ");
3107 2 avio_wb32(pb, 0); /* Reserved */
3108 2 avio_wb16(pb, 0); /* Reserved */
3109 2 avio_wb16(pb, 1); /* Data-reference index */
3110
3111 2 avio_wb16(pb, 1); /* Hint track version */
3112 2 avio_wb16(pb, 1); /* Highest compatible version */
3113 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3114
3115 2 avio_wb32(pb, 12); /* size */
3116 2 ffio_wfourcc(pb, "tims");
3117 2 avio_wb32(pb, track->timescale);
3118
3119 2 return update_size(pb, pos);
3120 }
3121
3122 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3123 {
3124 2 uint64_t str_size =strlen(reel_name);
3125 2 int64_t pos = avio_tell(pb);
3126
3127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3128 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3129 avio_wb16(pb, 0);
3130 return AVERROR(EINVAL);
3131 }
3132
3133 2 avio_wb32(pb, 0); /* size */
3134 2 ffio_wfourcc(pb, "name"); /* Data format */
3135 2 avio_wb16(pb, str_size); /* string size */
3136 2 avio_wb16(pb, track->language); /* langcode */
3137 2 avio_write(pb, reel_name, str_size); /* reel name */
3138 2 return update_size(pb,pos);
3139 }
3140
3141 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3142 {
3143 13 int64_t pos = avio_tell(pb);
3144 #if 1
3145 int frame_duration;
3146 int nb_frames;
3147 13 AVDictionaryEntry *t = NULL;
3148
3149
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) {
3150 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3151 return AVERROR(EINVAL);
3152 } else {
3153 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3154
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);
3155 }
3156
3157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3158 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3159 return AVERROR(EINVAL);
3160 }
3161
3162 13 avio_wb32(pb, 0); /* size */
3163 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3164 13 avio_wb32(pb, 0); /* Reserved */
3165 13 avio_wb32(pb, 1); /* Data reference index */
3166 13 avio_wb32(pb, 0); /* Flags */
3167 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3168 13 avio_wb32(pb, track->timescale); /* Timescale */
3169 13 avio_wb32(pb, frame_duration); /* Frame duration */
3170 13 avio_w8(pb, nb_frames); /* Number of frames */
3171 13 avio_w8(pb, 0); /* Reserved */
3172
3173 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3174
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)
3175 2 mov_write_source_reference_tag(pb, track, t->value);
3176 else
3177 11 avio_wb16(pb, 0); /* zero size */
3178 #else
3179
3180 avio_wb32(pb, 0); /* size */
3181 ffio_wfourcc(pb, "tmcd"); /* Data format */
3182 avio_wb32(pb, 0); /* Reserved */
3183 avio_wb32(pb, 1); /* Data reference index */
3184 if (track->par->extradata_size)
3185 avio_write(pb, track->par->extradata, track->par->extradata_size);
3186 #endif
3187 13 return update_size(pb, pos);
3188 }
3189
3190 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3191 {
3192 1 int64_t pos = avio_tell(pb);
3193 1 avio_wb32(pb, 0); /* size */
3194 1 ffio_wfourcc(pb, "gpmd");
3195 1 avio_wb32(pb, 0); /* Reserved */
3196 1 avio_wb16(pb, 0); /* Reserved */
3197 1 avio_wb16(pb, 1); /* Data-reference index */
3198 1 avio_wb32(pb, 0); /* Reserved */
3199 1 return update_size(pb, pos);
3200 }
3201
3202 382 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3203 {
3204 382 int64_t pos = avio_tell(pb);
3205 382 int ret = 0;
3206 382 avio_wb32(pb, 0); /* size */
3207 382 ffio_wfourcc(pb, "stsd");
3208 382 avio_wb32(pb, 0); /* version & flags */
3209 382 avio_wb32(pb, track->stsd_count);
3210
3211 382 int stsd_index_back = track->last_stsd_index;
3212 382 for (track->last_stsd_index = 0;
3213
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 382 times.
766 track->last_stsd_index < track->stsd_count;
3214 384 track->last_stsd_index++) {
3215
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 150 times.
384 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3216 234 ret = mov_write_video_tag(s, pb, mov, track);
3217
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 22 times.
150 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3218 128 ret = mov_write_audio_tag(s, pb, mov, track);
3219
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3220 6 ret = mov_write_subtitle_tag(s, pb, track);
3221
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3222 2 ret = mov_write_rtp_tag(pb, track);
3223
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3224 13 ret = mov_write_tmcd_tag(pb, track);
3225
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3226 1 ret = mov_write_gpmd_tag(pb, track);
3227
3228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 384 times.
384 if (ret < 0)
3229 return ret;
3230 }
3231
3232 382 track->last_stsd_index = stsd_index_back;
3233
3234 382 return update_size_and_version(pb, pos, track->entry_version);
3235 }
3236
3237 15 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3238 {
3239 15 MOVMuxContext *mov = s->priv_data;
3240 MOVCtts *ctts_entries;
3241 15 uint32_t entries = 0;
3242 uint32_t atom_size;
3243 int i;
3244
3245 15 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!ctts_entries)
3247 return AVERROR(ENOMEM);
3248 15 ctts_entries[0].count = 1;
3249 15 ctts_entries[0].offset = track->cluster[0].cts;
3250
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 15 times.
775 for (i = 1; i < track->entry; i++) {
3251
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 629 times.
760 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3252 131 ctts_entries[entries].count++; /* compress */
3253 } else {
3254 629 entries++;
3255 629 ctts_entries[entries].offset = track->cluster[i].cts;
3256 629 ctts_entries[entries].count = 1;
3257 }
3258 }
3259 15 entries++; /* last one */
3260 15 atom_size = 16 + (entries * 8);
3261 15 avio_wb32(pb, atom_size); /* size */
3262 15 ffio_wfourcc(pb, "ctts");
3263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3264 avio_w8(pb, 1); /* version */
3265 else
3266 15 avio_w8(pb, 0); /* version */
3267 15 avio_wb24(pb, 0); /* flags */
3268 15 avio_wb32(pb, entries); /* entry count */
3269
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 15 times.
659 for (i = 0; i < entries; i++) {
3270 644 avio_wb32(pb, ctts_entries[i].count);
3271 644 avio_wb32(pb, ctts_entries[i].offset);
3272 }
3273 15 av_free(ctts_entries);
3274 15 return atom_size;
3275 }
3276
3277 /* Time to sample atom */
3278 382 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3279 {
3280 382 MOVStts *stts_entries = NULL;
3281 382 uint32_t entries = -1;
3282 uint32_t atom_size;
3283 int i;
3284
3285
4/4
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 93 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3286 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3288 return AVERROR(ENOMEM);
3289 35 stts_entries[0].count = track->sample_count;
3290 35 stts_entries[0].duration = 1;
3291 35 entries = 1;
3292 } else {
3293
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 106 times.
347 if (track->entry) {
3294 241 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 241 times.
241 if (!stts_entries)
3296 return AVERROR(ENOMEM);
3297 }
3298
2/2
✓ Branch 0 taken 15829 times.
✓ Branch 1 taken 347 times.
16176 for (i = 0; i < track->entry; i++) {
3299 15829 int duration = get_cluster_duration(track, i);
3300 #if CONFIG_IAMFENC
3301
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 15774 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
15829 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3302 duration = av_rescale(duration, 48000, track->par->sample_rate);
3303 #endif
3304
4/4
✓ Branch 0 taken 15588 times.
✓ Branch 1 taken 241 times.
✓ Branch 2 taken 15158 times.
✓ Branch 3 taken 430 times.
15829 if (i && duration == stts_entries[entries].duration) {
3305 15158 stts_entries[entries].count++; /* compress */
3306 } else {
3307 671 entries++;
3308 671 stts_entries[entries].duration = duration;
3309 671 stts_entries[entries].count = 1;
3310 }
3311 }
3312 347 entries++; /* last one */
3313 }
3314 382 atom_size = 16 + (entries * 8);
3315 382 avio_wb32(pb, atom_size); /* size */
3316 382 ffio_wfourcc(pb, "stts");
3317 382 avio_wb32(pb, 0); /* version & flags */
3318 382 avio_wb32(pb, entries); /* entry count */
3319
2/2
✓ Branch 0 taken 706 times.
✓ Branch 1 taken 382 times.
1088 for (i = 0; i < entries; i++) {
3320 706 avio_wb32(pb, stts_entries[i].count);
3321 706 avio_wb32(pb, stts_entries[i].duration);
3322 }
3323 382 av_free(stts_entries);
3324 382 return atom_size;
3325 }
3326
3327 382 static int mov_write_dref_tag(AVIOContext *pb)
3328 {
3329 382 avio_wb32(pb, 28); /* size */
3330 382 ffio_wfourcc(pb, "dref");
3331 382 avio_wb32(pb, 0); /* version & flags */
3332 382 avio_wb32(pb, 1); /* entry count */
3333
3334 382 avio_wb32(pb, 0xc); /* size */
3335 //FIXME add the alis and rsrc atom
3336 382 ffio_wfourcc(pb, "url ");
3337 382 avio_wb32(pb, 1); /* version & flags */
3338
3339 382 return 28;
3340 }
3341
3342 65 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3343 {
3344 struct sgpd_entry {
3345 int count;
3346 int16_t roll_distance;
3347 int group_description_index;
3348 };
3349
3350 65 struct sgpd_entry *sgpd_entries = NULL;
3351 65 int entries = -1;
3352 65 int group = 0;
3353 int i, j;
3354
3355 65 const int OPUS_SEEK_PREROLL_MS = 80;
3356 65 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3357 65 (AVRational){1, 1000},
3358 65 (AVRational){1, 48000});
3359
3360
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 20 times.
65 if (!track->entry)
3361 45 return 0;
3362
3363 20 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!sgpd_entries)
3365 return AVERROR(ENOMEM);
3366
3367
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);
3368
3369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3370 for (i = 0; i < track->entry; i++) {
3371 int roll_samples_remaining = roll_samples;
3372 int distance = 0;
3373 for (j = i - 1; j >= 0; j--) {
3374 roll_samples_remaining -= get_cluster_duration(track, j);
3375 distance++;
3376 if (roll_samples_remaining <= 0)
3377 break;
3378 }
3379 /* We don't have enough preceding samples to compute a valid
3380 roll_distance here, so this sample can't be independently
3381 decoded. */
3382 if (roll_samples_remaining > 0)
3383 distance = 0;
3384 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3385 if (distance > 32) {
3386 av_freep(&sgpd_entries);
3387 return AVERROR_INVALIDDATA;
3388 }
3389 if (i && distance == sgpd_entries[entries].roll_distance) {
3390 sgpd_entries[entries].count++;
3391 } else {
3392 entries++;
3393 sgpd_entries[entries].count = 1;
3394 sgpd_entries[entries].roll_distance = distance;
3395 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3396 }
3397 }
3398 } else {
3399 20 entries++;
3400 20 sgpd_entries[entries].count = track->sample_count;
3401 20 sgpd_entries[entries].roll_distance = 1;
3402 20 sgpd_entries[entries].group_description_index = ++group;
3403 }
3404 20 entries++;
3405
3406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!group) {
3407 av_free(sgpd_entries);
3408 return 0;
3409 }
3410
3411 /* Write sgpd tag */
3412 20 avio_wb32(pb, 24 + (group * 2)); /* size */
3413 20 ffio_wfourcc(pb, "sgpd");
3414 20 avio_wb32(pb, 1 << 24); /* fullbox */
3415 20 ffio_wfourcc(pb, "roll");
3416 20 avio_wb32(pb, 2); /* default_length */
3417 20 avio_wb32(pb, group); /* entry_count */
3418
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for (i = 0; i < entries; i++) {
3419
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (sgpd_entries[i].group_description_index) {
3420 20 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3421 }
3422 }
3423
3424 /* Write sbgp tag */
3425 20 avio_wb32(pb, 20 + (entries * 8)); /* size */
3426 20 ffio_wfourcc(pb, "sbgp");
3427 20 avio_wb32(pb, 0); /* fullbox */
3428 20 ffio_wfourcc(pb, "roll");
3429 20 avio_wb32(pb, entries); /* entry_count */
3430
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for (i = 0; i < entries; i++) {
3431 20 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3432 20 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3433 }
3434
3435 20 av_free(sgpd_entries);
3436 20 return 0;
3437 }
3438
3439 382 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3440 {
3441 382 int64_t pos = avio_tell(pb);
3442 382 int ret = 0;
3443
3444 382 avio_wb32(pb, 0); /* size */
3445 382 ffio_wfourcc(pb, "stbl");
3446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3447 return ret;
3448 382 mov_write_stts_tag(pb, track);
3449
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 232 times.
382 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3450
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3451
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3452
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) ||
3453
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 148 times.
150 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3454
4/4
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 111 times.
234 track->has_keyframes && track->has_keyframes < track->entry)
3455 68 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3456
5/6
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 229 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3457 3 mov_write_sdtp_tag(pb, track);
3458
3/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
382 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3459 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3460
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3461
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) {
3462
3463
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3464 return ret;
3465 }
3466 382 mov_write_stsc_tag(pb, track);
3467 382 mov_write_stsz_tag(pb, track);
3468 382 mov_write_stco_tag(pb, track);
3469
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 377 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
382 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3470 5 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3471 }
3472
3/4
✓ Branch 0 taken 382 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 317 times.
382 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3473 65 mov_preroll_write_stbl_atoms(pb, track);
3474 }
3475 382 return update_size(pb, pos);
3476 }
3477
3478 382 static int mov_write_dinf_tag(AVIOContext *pb)
3479 {
3480 382 int64_t pos = avio_tell(pb);
3481 382 avio_wb32(pb, 0); /* size */
3482 382 ffio_wfourcc(pb, "dinf");
3483 382 mov_write_dref_tag(pb);
3484 382 return update_size(pb, pos);
3485 }
3486
3487 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3488 {
3489 7 avio_wb32(pb, 12);
3490 7 ffio_wfourcc(pb, "nmhd");
3491 7 avio_wb32(pb, 0);
3492 7 return 12;
3493 }
3494
3495 2 static int mov_write_sthd_tag(AVIOContext *pb)
3496 {
3497 2 avio_wb32(pb, 12);
3498 2 ffio_wfourcc(pb, "sthd");
3499 2 avio_wb32(pb, 0);
3500 2 return 12;
3501 }
3502
3503 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3504 {
3505 9 int64_t pos = avio_tell(pb);
3506 9 const char *font = "Lucida Grande";
3507 9 avio_wb32(pb, 0); /* size */
3508 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3509 9 avio_wb32(pb, 0); /* version & flags */
3510 9 avio_wb16(pb, 0); /* text font */
3511 9 avio_wb16(pb, 0); /* text face */
3512 9 avio_wb16(pb, 12); /* text size */
3513 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3514 9 avio_wb16(pb, 0x0000); /* text color (red) */
3515 9 avio_wb16(pb, 0x0000); /* text color (green) */
3516 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3517 9 avio_wb16(pb, 0xffff); /* background color (red) */
3518 9 avio_wb16(pb, 0xffff); /* background color (green) */
3519 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3520 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3521 9 avio_write(pb, font, strlen(font)); /* font name */
3522 9 return update_size(pb, pos);
3523 }
3524
3525 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3526 {
3527 11 int64_t pos = avio_tell(pb);
3528 11 avio_wb32(pb, 0); /* size */
3529 11 ffio_wfourcc(pb, "gmhd");
3530 11 avio_wb32(pb, 0x18); /* gmin size */
3531 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3532 11 avio_wb32(pb, 0); /* version & flags */
3533 11 avio_wb16(pb, 0x40); /* graphics mode = */
3534 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3535 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3536 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3537 11 avio_wb16(pb, 0); /* balance */
3538 11 avio_wb16(pb, 0); /* reserved */
3539
3540 /*
3541 * This special text atom is required for
3542 * Apple Quicktime chapters. The contents
3543 * don't appear to be documented, so the
3544 * bytes are copied verbatim.
3545 */
3546
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3547 11 avio_wb32(pb, 0x2C); /* size */
3548 11 ffio_wfourcc(pb, "text");
3549 11 avio_wb16(pb, 0x01);
3550 11 avio_wb32(pb, 0x00);
3551 11 avio_wb32(pb, 0x00);
3552 11 avio_wb32(pb, 0x00);
3553 11 avio_wb32(pb, 0x01);
3554 11 avio_wb32(pb, 0x00);
3555 11 avio_wb32(pb, 0x00);
3556 11 avio_wb32(pb, 0x00);
3557 11 avio_wb32(pb, 0x00004000);
3558 11 avio_wb16(pb, 0x0000);
3559 }
3560
3561
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3562 9 int64_t tmcd_pos = avio_tell(pb);
3563 9 avio_wb32(pb, 0); /* size */
3564 9 ffio_wfourcc(pb, "tmcd");
3565 9 mov_write_tcmi_tag(pb, track);
3566 9 update_size(pb, tmcd_pos);
3567
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3568 1 int64_t gpmd_pos = avio_tell(pb);
3569 1 avio_wb32(pb, 0); /* size */
3570 1 ffio_wfourcc(pb, "gpmd");
3571 1 avio_wb32(pb, 0); /* version */
3572 1 update_size(pb, gpmd_pos);
3573 }
3574 11 return update_size(pb, pos);
3575 }
3576
3577 128 static int mov_write_smhd_tag(AVIOContext *pb)
3578 {
3579 128 avio_wb32(pb, 16); /* size */
3580 128 ffio_wfourcc(pb, "smhd");
3581 128 avio_wb32(pb, 0); /* version & flags */
3582 128 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3583 128 avio_wb16(pb, 0); /* reserved */
3584 128 return 16;
3585 }
3586
3587 232 static uint16_t mov_graphics_mode(MOVTrack *track)
3588 {
3589
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 144 times.
232 if (track->mode != MODE_MOV)
3590 88 return 0; /* ISO/IEC 14496-12 doesn't define any other modes */
3591
3592
1/3
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
144 switch (track->par->alpha_mode) {
3593 144 default: return MOV_GRAPHICS_MODE_COPY;
3594 case AVALPHA_MODE_STRAIGHT: return MOV_GRAPHICS_MODE_STRAIGHT_ALPHA;
3595 case AVALPHA_MODE_PREMULTIPLIED: return MOV_GRAPHICS_MODE_PREMUL_BLACK_ALPHA;
3596 }
3597 }
3598
3599 232 static int mov_write_vmhd_tag(AVIOContext *pb, MOVTrack *track)
3600 {
3601 232 avio_wb32(pb, 0x14); /* size (always 0x14) */
3602 232 ffio_wfourcc(pb, "vmhd");
3603 232 avio_wb32(pb, 0x01); /* version & flags */
3604 232 avio_wb16(pb, mov_graphics_mode(track));
3605
2/2
✓ Branch 0 taken 696 times.
✓ Branch 1 taken 232 times.
928 for (int i = 0; i < 3; i++)
3606 696 avio_wb16(pb, 0); /* opcolor */
3607 232 return 0x14;
3608 }
3609
3610 229 static int is_clcp_track(MOVTrack *track)
3611 {
3612
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
458 return track->tag == MKTAG('c','7','0','8') ||
3613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 track->tag == MKTAG('c','6','0','8');
3614 }
3615
3616 574 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3617 {
3618 574 MOVMuxContext *mov = s->priv_data;
3619 574 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3620 574 int64_t pos = avio_tell(pb);
3621 size_t descr_len;
3622
3623 574 hdlr = "dhlr";
3624 574 hdlr_type = "url ";
3625 574 descr = "DataHandler";
3626
3627
2/2
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 192 times.
574 if (track) {
3628
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
382 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3629
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
232 if (track->mode == MODE_AVIF) {
3631 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3632 descr = "PictureHandler";
3633 } else {
3634 232 hdlr_type = "vide";
3635 232 descr = "VideoHandler";
3636 }
3637
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 22 times.
150 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3638 128 hdlr_type = "soun";
3639 128 descr = "SoundHandler";
3640
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3641
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3642 hdlr_type = "clcp";
3643 descr = "ClosedCaptionHandler";
3644 } else {
3645
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3646 1 hdlr_type = "sbtl";
3647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3648 hdlr_type = "subp";
3649
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3650 2 hdlr_type = "subt";
3651 } else {
3652 3 hdlr_type = "text";
3653 }
3654 6 descr = "SubtitleHandler";
3655 }
3656
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3657 2 hdlr_type = "hint";
3658 2 descr = "HintHandler";
3659
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3660 13 hdlr_type = "tmcd";
3661 13 descr = "TimeCodeHandler";
3662
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3663 1 hdlr_type = "meta";
3664 1 descr = "GoPro MET"; // GoPro Metadata
3665 } else {
3666 av_log(s, AV_LOG_WARNING,
3667 "Unknown hdlr_type for %s, writing dummy values\n",
3668 av_fourcc2str(track->par->codec_tag));
3669 }
3670
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 3 times.
382 if (track->st) {
3671 // hdlr.name is used by some players to identify the content title
3672 // of the track. So if an alternate handler description is
3673 // specified, use it.
3674 AVDictionaryEntry *t;
3675 379 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3676
3/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 352 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
379 if (t && utf8len(t->value))
3677 27 descr = t->value;
3678 }
3679 }
3680
3681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 574 times.
574 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3682 descr = "";
3683
3684 574 avio_wb32(pb, 0); /* size */
3685 574 ffio_wfourcc(pb, "hdlr");
3686 574 avio_wb32(pb, 0); /* Version & flags */
3687 574 avio_write(pb, hdlr, 4); /* handler */
3688 574 ffio_wfourcc(pb, hdlr_type); /* handler type */
3689 574 avio_wb32(pb, 0); /* reserved */
3690 574 avio_wb32(pb, 0); /* reserved */
3691 574 avio_wb32(pb, 0); /* reserved */
3692 574 descr_len = strlen(descr);
3693
4/4
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 190 times.
574 if (!track || track->mode == MODE_MOV)
3694 384 avio_w8(pb, descr_len); /* pascal string */
3695 574 avio_write(pb, descr, descr_len); /* handler description */
3696
4/4
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 192 times.
574 if (track && track->mode != MODE_MOV)
3697 190 avio_w8(pb, 0); /* c string */
3698 574 return update_size(pb, pos);
3699 }
3700
3701 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3702 {
3703 int64_t pos = avio_tell(pb);
3704 avio_wb32(pb, 0); /* size */
3705 ffio_wfourcc(pb, "pitm");
3706 avio_wb32(pb, 0); /* Version & flags */
3707 avio_wb16(pb, item_id); /* item_id */
3708 return update_size(pb, pos);
3709 }
3710
3711 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3712 {
3713 int64_t pos = avio_tell(pb);
3714 avio_wb32(pb, 0); /* size */
3715 ffio_wfourcc(pb, "iloc");
3716 avio_wb32(pb, 0); /* Version & flags */
3717 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3718 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3719 avio_wb16(pb, mov->nb_streams); /* item_count */
3720
3721 for (int i = 0; i < mov->nb_streams; i++) {
3722 avio_wb16(pb, i + 1); /* item_id */
3723 avio_wb16(pb, 0); /* data_reference_index */
3724 avio_wb16(pb, 1); /* extent_count */
3725 mov->avif_extent_pos[i] = avio_tell(pb);
3726 avio_wb32(pb, 0); /* extent_offset (written later) */
3727 // For animated AVIF, we simply write the first packet's size.
3728 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3729 }
3730
3731 return update_size(pb, pos);
3732 }
3733
3734 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3735 {
3736 int64_t iinf_pos = avio_tell(pb);
3737 avio_wb32(pb, 0); /* size */
3738 ffio_wfourcc(pb, "iinf");
3739 avio_wb32(pb, 0); /* Version & flags */
3740 avio_wb16(pb, mov->nb_streams); /* entry_count */
3741
3742 for (int i = 0; i < mov->nb_streams; i++) {
3743 int64_t infe_pos = avio_tell(pb);
3744 avio_wb32(pb, 0); /* size */
3745 ffio_wfourcc(pb, "infe");
3746 avio_w8(pb, 0x2); /* Version */
3747 avio_wb24(pb, 0); /* flags */
3748 avio_wb16(pb, i + 1); /* item_id */
3749 avio_wb16(pb, 0); /* item_protection_index */
3750 avio_write(pb, "av01", 4); /* item_type */
3751 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3752 update_size(pb, infe_pos);
3753 }
3754
3755 return update_size(pb, iinf_pos);
3756 }
3757
3758
3759 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3760 {
3761 int64_t auxl_pos;
3762 int64_t iref_pos = avio_tell(pb);
3763 avio_wb32(pb, 0); /* size */
3764 ffio_wfourcc(pb, "iref");
3765 avio_wb32(pb, 0); /* Version & flags */
3766
3767 auxl_pos = avio_tell(pb);
3768 avio_wb32(pb, 0); /* size */
3769 ffio_wfourcc(pb, "auxl");
3770 avio_wb16(pb, 2); /* from_item_ID */
3771 avio_wb16(pb, 1); /* reference_count */
3772 avio_wb16(pb, 1); /* to_item_ID */
3773 update_size(pb, auxl_pos);
3774
3775 return update_size(pb, iref_pos);
3776 }
3777
3778 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3779 int stream_index)
3780 {
3781 int64_t pos = avio_tell(pb);
3782 avio_wb32(pb, 0); /* size */
3783 ffio_wfourcc(pb, "ispe");
3784 avio_wb32(pb, 0); /* Version & flags */
3785 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3786 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3787 return update_size(pb, pos);
3788 }
3789
3790 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3791 int stream_index)
3792 {
3793 int64_t pos = avio_tell(pb);
3794 const AVPixFmtDescriptor *pixdesc =
3795 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3796 avio_wb32(pb, 0); /* size */
3797 ffio_wfourcc(pb, "pixi");
3798 avio_wb32(pb, 0); /* Version & flags */
3799 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3800 for (int i = 0; i < pixdesc->nb_components; ++i) {
3801 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3802 }
3803 return update_size(pb, pos);
3804 }
3805
3806 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3807 {
3808 int64_t pos = avio_tell(pb);
3809 avio_wb32(pb, 0); /* size */
3810 ffio_wfourcc(pb, "ipco");
3811 for (int i = 0; i < mov->nb_streams; i++) {
3812 mov_write_ispe_tag(pb, mov, s, i);
3813 mov_write_pixi_tag(pb, mov, s, i);
3814 mov_write_av1c_tag(pb, &mov->tracks[i]);
3815 if (!i)
3816 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3817 else
3818 mov_write_aux_tag(pb, "auxC");
3819 }
3820 return update_size(pb, pos);
3821 }
3822
3823 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3824 {
3825 int64_t pos = avio_tell(pb);
3826 avio_wb32(pb, 0); /* size */
3827 ffio_wfourcc(pb, "ipma");
3828 avio_wb32(pb, 0); /* Version & flags */
3829 avio_wb32(pb, mov->nb_streams); /* entry_count */
3830
3831 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3832 avio_wb16(pb, i + 1); /* item_ID */
3833 avio_w8(pb, 4); /* association_count */
3834
3835 // ispe association.
3836 avio_w8(pb, index++); /* essential and property_index */
3837 // pixi association.
3838 avio_w8(pb, index++); /* essential and property_index */
3839 // av1C association.
3840 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3841 // colr/auxC association.
3842 avio_w8(pb, index++); /* essential and property_index */
3843 }
3844 return update_size(pb, pos);
3845 }
3846
3847 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3848 {
3849 int64_t pos = avio_tell(pb);
3850 avio_wb32(pb, 0); /* size */
3851 ffio_wfourcc(pb, "iprp");
3852 mov_write_ipco_tag(pb, mov, s);
3853 mov_write_ipma_tag(pb, mov, s);
3854 return update_size(pb, pos);
3855 }
3856
3857 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3858 {
3859 /* This atom must be present, but leaving the values at zero
3860 * seems harmless. */
3861 2 avio_wb32(pb, 28); /* size */
3862 2 ffio_wfourcc(pb, "hmhd");
3863 2 avio_wb32(pb, 0); /* version, flags */
3864 2 avio_wb16(pb, 0); /* maxPDUsize */
3865 2 avio_wb16(pb, 0); /* avgPDUsize */
3866 2 avio_wb32(pb, 0); /* maxbitrate */
3867 2 avio_wb32(pb, 0); /* avgbitrate */
3868 2 avio_wb32(pb, 0); /* reserved */
3869 2 return 28;
3870 }
3871
3872 382 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3873 {
3874 382 int64_t pos = avio_tell(pb);
3875 int ret;
3876
3877 382 avio_wb32(pb, 0); /* size */
3878 382 ffio_wfourcc(pb, "minf");
3879
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3880 232 mov_write_vmhd_tag(pb, track);
3881
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 22 times.
150 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3882 128 mov_write_smhd_tag(pb);
3883
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3884
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)) {
3885 1 mov_write_gmhd_tag(pb, track);
3886
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3887 2 mov_write_sthd_tag(pb);
3888 } else {
3889 3 mov_write_nmhd_tag(pb);
3890 }
3891
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3892 2 mov_write_hmhd_tag(pb);
3893
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3894
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3895 4 mov_write_nmhd_tag(pb);
3896 else
3897 9 mov_write_gmhd_tag(pb, track);
3898
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3899 1 mov_write_gmhd_tag(pb, track);
3900 }
3901
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
382 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3902 192 mov_write_hdlr_tag(s, pb, NULL);
3903 382 mov_write_dinf_tag(pb);
3904
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3905 return ret;
3906 382 return update_size(pb, pos);
3907 }
3908
3909 1466 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3910 int64_t *start, int64_t *end, int elst, int mdhd)
3911 {
3912
5/6
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1416 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
1466 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd && track->nb_src_track) {
3913 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3914 // another track's duration, while the end_pts may be left at zero.
3915 // Calculate the pts duration for that track instead.
3916 38 get_pts_range(mov, &mov->tracks[*track->src_track], start, end, elst, mdhd);
3917 38 *start = av_rescale(*start, track->timescale,
3918 38 mov->tracks[*track->src_track].timescale);
3919 38 *end = av_rescale(*end, track->timescale,
3920 38 mov->tracks[*track->src_track].timescale);
3921 38 return;
3922 }
3923
4/4
✓ Branch 0 taken 1046 times.
✓ Branch 1 taken 382 times.
✓ Branch 2 taken 1005 times.
✓ Branch 3 taken 41 times.
1428 if (!mdhd && track->end_pts != AV_NOPTS_VALUE &&
3924
1/2
✓ Branch 0 taken 1005 times.
✗ Branch 1 not taken.
1005 track->start_dts != AV_NOPTS_VALUE &&
3925
1/2
✓ Branch 0 taken 1005 times.
✗ Branch 1 not taken.
1005 track->start_cts != AV_NOPTS_VALUE) {
3926 1005 *start = track->start_dts + track->start_cts;
3927
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 686 times.
1005 *end = elst ? track->elst_end_pts : track->end_pts;
3928 1005 return;
3929 }
3930 423 *start = 0;
3931 423 *end = track->track_duration;
3932 }
3933
3934 382 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3935 {
3936 int64_t start, end;
3937 382 get_pts_range(mov, track, &start, &end, 0, 1);
3938 382 return end - start;
3939 }
3940
3941 // Calculate the actual duration of the track, after edits.
3942 // If it starts with a pts < 0, that is removed by the edit list.
3943 // If it starts with a pts > 0, the edit list adds a delay before that.
3944 // Thus, with edit lists enabled, the post-edit output of the file is
3945 // starting with pts=0.
3946 727 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3947 {
3948 int64_t start, end;
3949 727 get_pts_range(mov, track, &start, &end, 0, 0);
3950
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 83 times.
727 if (mov->use_editlist != 0)
3951 644 start = 0;
3952 727 return end - start;
3953 }
3954
3955 319 static int64_t calc_elst_duration(MOVMuxContext *mov, MOVTrack *track)
3956 {
3957 int64_t start, end;
3958 319 get_pts_range(mov, track, &start, &end, 1, 0);
3959 319 return end - start;
3960 }
3961
3962 1044 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3963 {
3964
4/4
✓ Branch 0 taken 764 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 746 times.
1044 if (track && track->mode == MODE_ISM)
3965 18 return 1;
3966
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 8 times.
1026 if (duration < INT32_MAX)
3967 1018 return 0;
3968 8 return 1;
3969 }
3970
3971 382 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3972 MOVTrack *track)
3973 {
3974 382 int64_t duration = calc_samples_pts_duration(mov, track);
3975 382 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3976
3977
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3978 382 ffio_wfourcc(pb, "mdhd");
3979 382 avio_w8(pb, version);
3980 382 avio_wb24(pb, 0); /* flags */
3981
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 if (version == 1) {
3982 13 avio_wb64(pb, track->time);
3983 13 avio_wb64(pb, track->time);
3984 } else {
3985 369 avio_wb32(pb, track->time); /* creation time */
3986 369 avio_wb32(pb, track->time); /* modification time */
3987 }
3988 382 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3989
4/4
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 98 times.
382 if (!track->entry && mov->mode == MODE_ISM)
3990
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3991
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 275 times.
373 else if (!track->entry)
3992
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 94 times.
98 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3993 else
3994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3995 382 avio_wb16(pb, track->language); /* language */
3996 382 avio_wb16(pb, 0); /* reserved (quality) */
3997
3998
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
382 if (version != 0 && track->mode == MODE_MOV) {
3999 av_log(NULL, AV_LOG_ERROR,
4000 "FATAL error, file duration too long for timebase, this file will not be\n"
4001 "playable with QuickTime. Choose a different timebase with "
4002 "-video_track_timescale or a different container format\n");
4003 }
4004
4005 382 return 32;
4006 }
4007
4008 382 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
4009 MOVMuxContext *mov, MOVTrack *track)
4010 {
4011 382 int64_t pos = avio_tell(pb);
4012 int ret;
4013
4014 382 avio_wb32(pb, 0); /* size */
4015 382 ffio_wfourcc(pb, "mdia");
4016 382 mov_write_mdhd_tag(pb, mov, track);
4017 382 mov_write_hdlr_tag(s, pb, track);
4018
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
4019 return ret;
4020 382 return update_size(pb, pos);
4021 }
4022
4023 /* transformation matrix
4024 |a b u|
4025 |c d v|
4026 |tx ty w| */
4027 661 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
4028 int16_t d, int16_t tx, int16_t ty)
4029 {
4030 661 avio_wb32(pb, a << 16); /* 16.16 format */
4031 661 avio_wb32(pb, b << 16); /* 16.16 format */
4032 661 avio_wb32(pb, 0); /* u in 2.30 format */
4033 661 avio_wb32(pb, c << 16); /* 16.16 format */
4034 661 avio_wb32(pb, d << 16); /* 16.16 format */
4035 661 avio_wb32(pb, 0); /* v in 2.30 format */
4036 661 avio_wb32(pb, tx << 16); /* 16.16 format */
4037 661 avio_wb32(pb, ty << 16); /* 16.16 format */
4038 661 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
4039 661 }
4040
4041 382 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4042 MOVTrack *track, AVStream *st)
4043 {
4044 764 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
4045 382 mov->movie_timescale, track->timescale,
4046 AV_ROUND_UP);
4047 int version;
4048 382 int flags = MOV_TKHD_FLAG_IN_MOVIE;
4049 382 int group = 0;
4050
4051 382 uint32_t *display_matrix = NULL;
4052 int i;
4053
4054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (mov->mode == MODE_AVIF)
4055 if (!mov->avif_loop_count)
4056 duration = INT64_MAX;
4057 else
4058 duration *= mov->avif_loop_count;
4059
4060
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 13 times.
382 if (st) {
4061 const AVPacketSideData *sd;
4062
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 367 times.
369 if (mov->per_stream_grouping)
4063 2 group = st->index;
4064 else
4065 367 group = st->codecpar->codec_type;
4066
4067 369 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4068 369 st->codecpar->nb_coded_side_data,
4069 AV_PKT_DATA_DISPLAYMATRIX);
4070
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 368 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
369 if (sd && sd->size == 9 * sizeof(*display_matrix))
4071 1 display_matrix = (uint32_t *)sd->data;
4072 }
4073
4074
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 25 times.
382 if (track->flags & MOV_TRACK_ENABLED)
4075 357 flags |= MOV_TKHD_FLAG_ENABLED;
4076
4077 382 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4078
4079
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
4080 382 ffio_wfourcc(pb, "tkhd");
4081 382 avio_w8(pb, version);
4082 382 avio_wb24(pb, flags);
4083
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 if (version == 1) {
4084 13 avio_wb64(pb, track->time);
4085 13 avio_wb64(pb, track->time);
4086 } else {
4087 369 avio_wb32(pb, track->time); /* creation time */
4088 369 avio_wb32(pb, track->time); /* modification time */
4089 }
4090 382 avio_wb32(pb, track->track_id); /* track-id */
4091 382 avio_wb32(pb, 0); /* reserved */
4092
4/4
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 98 times.
382 if (!track->entry && mov->mode == MODE_ISM)
4093
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4094
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 275 times.
373 else if (!track->entry)
4095
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 94 times.
98 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4096 else
4097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
4098
4099 382 avio_wb32(pb, 0); /* reserved */
4100 382 avio_wb32(pb, 0); /* reserved */
4101 382 avio_wb16(pb, 0); /* layer */
4102 382 avio_wb16(pb, group); /* alternate group) */
4103 /* Volume, only for audio */
4104
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 254 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
4105 128 avio_wb16(pb, 0x0100);
4106 else
4107 254 avio_wb16(pb, 0);
4108 382 avio_wb16(pb, 0); /* reserved */
4109
4110 /* Matrix structure */
4111
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 381 times.
382 if (display_matrix) {
4112
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
4113 9 avio_wb32(pb, display_matrix[i]);
4114 } else {
4115 381 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4116 }
4117 /* Track width and height, for visual only */
4118
4/4
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 232 times.
382 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
4119
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 132 times.
374 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
4120 int64_t track_width_1616;
4121
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) {
4122 144 track_width_1616 = track->par->width * 0x10000ULL;
4123 } else {
4124 93 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
4125 93 track->par->width * 0x10000LL,
4126 93 st->sample_aspect_ratio.den);
4127
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 74 times.
93 if (!track_width_1616 ||
4128
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 ||
4129 track_width_1616 > UINT32_MAX)
4130 74 track_width_1616 = track->par->width * 0x10000ULL;
4131 }
4132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track_width_1616 > UINT32_MAX) {
4133 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4134 track_width_1616 = 0;
4135 }
4136 237 avio_wb32(pb, track_width_1616);
4137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track->height > 0xFFFF) {
4138 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4139 avio_wb32(pb, 0);
4140 } else
4141 237 avio_wb32(pb, track->height * 0x10000U);
4142 } else {
4143 145 avio_wb32(pb, 0);
4144 145 avio_wb32(pb, 0);
4145 }
4146 382 return 0x5c;
4147 }
4148
4149 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4150 {
4151 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4152 1 track->par->sample_aspect_ratio.den);
4153
4154 1 int64_t pos = avio_tell(pb);
4155
4156 1 avio_wb32(pb, 0); /* size */
4157 1 ffio_wfourcc(pb, "tapt");
4158
4159 1 avio_wb32(pb, 20);
4160 1 ffio_wfourcc(pb, "clef");
4161 1 avio_wb32(pb, 0);
4162 1 avio_wb32(pb, width << 16);
4163 1 avio_wb32(pb, track->par->height << 16);
4164
4165 1 avio_wb32(pb, 20);
4166 1 ffio_wfourcc(pb, "prof");
4167 1 avio_wb32(pb, 0);
4168 1 avio_wb32(pb, width << 16);
4169 1 avio_wb32(pb, track->par->height << 16);
4170
4171 1 avio_wb32(pb, 20);
4172 1 ffio_wfourcc(pb, "enof");
4173 1 avio_wb32(pb, 0);
4174 1 avio_wb32(pb, track->par->width << 16);
4175 1 avio_wb32(pb, track->par->height << 16);
4176
4177 1 return update_size(pb, pos);
4178 }
4179
4180 // This box is written in the following cases:
4181 // * Seems important for the psp playback. Without it the movie seems to hang.
4182 // * Used for specifying the looping behavior of animated AVIF (as specified
4183 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4184 319 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4185 MOVTrack *track)
4186 {
4187 638 int64_t duration = av_rescale_rnd(calc_elst_duration(mov, track),
4188 319 mov->movie_timescale, track->timescale,
4189 AV_ROUND_UP);
4190 319 int version = duration < INT32_MAX ? 0 : 1;
4191 int entry_size, entry_count, size;
4192 319 int64_t delay, start_ct = track->start_cts;
4193 319 int64_t start_dts = track->start_dts;
4194 319 int flags = 0;
4195
4196
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 60 times.
319 if (track->entry) {
4197
4/6
✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 256 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
259 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4198
4199 av_log(mov->fc, AV_LOG_DEBUG,
4200 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4201 track->cluster[0].dts, track->cluster[0].cts,
4202 start_dts, start_ct, track->track_id);
4203 start_dts = track->cluster[0].dts;
4204 start_ct = track->cluster[0].cts;
4205 }
4206 }
4207
4208 319 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4209 319 track->timescale, AV_ROUND_DOWN);
4210
4211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 319 times.
319 if (mov->mode == MODE_AVIF) {
4212 delay = 0;
4213 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4214 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4215 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4216 // edit list is repeated.
4217 flags = mov->avif_loop_count != 1;
4218 start_ct = 0;
4219 }
4220
4221 319 version |= delay < INT32_MAX ? 0 : 1;
4222
4223
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 entry_size = (version == 1) ? 20 : 12;
4224
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 entry_count = 1 + (delay > 0);
4225 319 size = 24 + entry_count * entry_size;
4226
4227 /* write the atom data */
4228 319 avio_wb32(pb, size);
4229 319 ffio_wfourcc(pb, "edts");
4230 319 avio_wb32(pb, size - 8);
4231 319 ffio_wfourcc(pb, "elst");
4232 319 avio_w8(pb, version);
4233 319 avio_wb24(pb, flags); /* flags */
4234
4235 319 avio_wb32(pb, entry_count);
4236
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 if (delay > 0) { /* add an empty edit to delay presentation */
4237 /* In the positive delay case, the delay includes the cts
4238 * offset, and the second edit list entry below trims out
4239 * the same amount from the actual content. This makes sure
4240 * that the offset last sample is included in the edit
4241 * list duration as well. */
4242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (version == 1) {
4243 avio_wb64(pb, delay);
4244 avio_wb64(pb, -1);
4245 } else {
4246 4 avio_wb32(pb, delay);
4247 4 avio_wb32(pb, -1);
4248 }
4249 4 avio_wb32(pb, 0x00010000);
4250
1/2
✓ Branch 0 taken 315 times.
✗ Branch 1 not taken.
315 } else if (mov->mode != MODE_AVIF) {
4251 /* Avoid accidentally ending up with start_ct = -1 which has got a
4252 * special meaning. Normally start_ct should end up positive or zero
4253 * here, but use FFMIN in case dts is a small positive integer
4254 * rounded to 0 when represented in movie timescale units. */
4255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
315 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4256 315 start_ct = -FFMIN(start_dts, 0);
4257
4258 #if CONFIG_IAMFENC
4259
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 310 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
315 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4260 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4261 #endif
4262 /* Note, this delay is calculated from the pts of the first sample,
4263 * ensuring that we don't reduce the duration for cases with
4264 * dts<0 pts=0. */
4265 315 duration += delay;
4266 }
4267
4268 /* For fragmented files, we don't know the full length yet. Setting
4269 * duration to 0 allows us to only specify the offset, including
4270 * the rest of the content (from all future fragments) without specifying
4271 * an explicit duration.
4272 *
4273 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4274 * don't reset duration to zero.
4275 */
4276
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 255 times.
319 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4277
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))
4278 64 duration = 0;
4279
4280 /* duration */
4281
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 if (version == 1) {
4282 4 avio_wb64(pb, duration);
4283 4 avio_wb64(pb, start_ct);
4284 } else {
4285 315 avio_wb32(pb, duration);
4286 315 avio_wb32(pb, start_ct);
4287 }
4288 319 avio_wb32(pb, 0x00010000);
4289 319 return size;
4290 }
4291
4292 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4293 {
4294 14 int64_t pos = avio_tell(pb);
4295 14 avio_wb32(pb, 0); // size placeholder
4296 14 ffio_wfourcc(pb, "tref");
4297
4298
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 for (int i = 0; i < track->nb_tref_tags; i++) {
4299 14 MovTag *tag = &track->tref_tags[i];
4300 14 avio_wb32(pb, 8 + tag->nb_id * sizeof(*tag->id)); // size (subatom)
4301 14 avio_wl32(pb, tag->name);
4302
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 14 times.
30 for (int j = 0; j < tag->nb_id; j++)
4303 16 avio_wb32(pb, tag->id[j]);
4304 }
4305 14 return update_size(pb, pos);
4306 }
4307
4308 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4309 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4310 {
4311 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4312 2 ffio_wfourcc(pb, "uuid");
4313 2 ffio_wfourcc(pb, "USMT");
4314 2 avio_wb32(pb, 0x21d24fce);
4315 2 avio_wb32(pb, 0xbb88695c);
4316 2 avio_wb32(pb, 0xfac9c740);
4317 2 avio_wb32(pb, 0x1c); // another size here!
4318 2 ffio_wfourcc(pb, "MTDT");
4319 2 avio_wb32(pb, 0x00010012);
4320 2 avio_wb32(pb, 0x0a);
4321 2 avio_wb32(pb, 0x55c40000);
4322 2 avio_wb32(pb, 0x1);
4323 2 avio_wb32(pb, 0x0);
4324 2 return 0x34;
4325 }
4326
4327 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4328 {
4329 2 AVFormatContext *ctx = track->rtp_ctx;
4330 2 char buf[1000] = "";
4331 int len;
4332
4333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
4334 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], *track->src_track,
4335 NULL, NULL, 0, 0, ctx);
4336 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4337 2 len = strlen(buf);
4338
4339 2 avio_wb32(pb, len + 24);
4340 2 ffio_wfourcc(pb, "udta");
4341 2 avio_wb32(pb, len + 16);
4342 2 ffio_wfourcc(pb, "hnti");
4343 2 avio_wb32(pb, len + 8);
4344 2 ffio_wfourcc(pb, "sdp ");
4345 2 avio_write(pb, buf, len);
4346 2 return len + 24;
4347 }
4348
4349 359 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4350 const char *tag, const char *str)
4351 {
4352 359 int64_t pos = avio_tell(pb);
4353 359 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4354
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 358 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
359 if (!t || !utf8len(t->value))
4355 358 return 0;
4356
4357 1 avio_wb32(pb, 0); /* size */
4358 1 ffio_wfourcc(pb, tag); /* type */
4359 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4360 1 return update_size(pb, pos);
4361 }
4362
4363 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4364 const char *value)
4365 {
4366 2 int64_t pos = avio_tell(pb);
4367
4368 /* Box|FullBox basics */
4369 2 avio_wb32(pb, 0); /* size placeholder */
4370 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4371 2 avio_w8(pb, 0); /* version = 0 */
4372 2 avio_wb24(pb, 0); /* flags = 0 */
4373
4374 /* Required null-terminated scheme URI */
4375 2 avio_write(pb, (const unsigned char *)scheme_uri,
4376 2 strlen(scheme_uri));
4377 2 avio_w8(pb, 0);
4378
4379 /* Optional value string */
4380
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])
4381 2 avio_write(pb, (const unsigned char *)value,
4382 2 strlen(value));
4383
4384 2 avio_w8(pb, 0);
4385
4386 2 return update_size(pb, pos);
4387 }
4388
4389 173 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4390 {
4391 173 int ret = AVERROR_BUG;
4392
4393
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 173 times.
346 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4394 173 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4395
4396
2/2
✓ Branch 0 taken 865 times.
✓ Branch 1 taken 173 times.
1038 for (int j = 0; map.value_maps[j].disposition; j++) {
4397 865 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4398
2/2
✓ Branch 0 taken 863 times.
✓ Branch 1 taken 2 times.
865 if (!(st->disposition & value_map.disposition))
4399 863 continue;
4400
4401
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)
4402 return ret;
4403 }
4404 }
4405
4406 173 return 0;
4407 }
4408
4409 382 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4410 AVStream *st)
4411 {
4412 AVIOContext *pb_buf;
4413 int ret, size;
4414 uint8_t *buf;
4415
4416
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 if (!st)
4417 13 return 0;
4418
4419 369 ret = avio_open_dyn_buf(&pb_buf);
4420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
369 if (ret < 0)
4421 return ret;
4422
4423
2/2
✓ Branch 0 taken 359 times.
✓ Branch 1 taken 10 times.
369 if (mov->mode & (MODE_MP4|MODE_MOV))
4424 359 mov_write_track_metadata(pb_buf, st, "name", "title");
4425
4426
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 196 times.
369 if (mov->mode & MODE_MP4) {
4427
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4428 goto end;
4429 }
4430
4431
2/2
✓ Branch 1 taken 366 times.
✓ Branch 2 taken 3 times.
369 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4432 3 avio_wb32(pb, size + 8);
4433 3 ffio_wfourcc(pb, "udta");
4434 3 avio_write(pb, buf, size);
4435 }
4436 366 end:
4437 369 ffio_free_dyn_buf(&pb_buf);
4438
4439 369 return ret;
4440 }
4441
4442 382 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4443 MOVTrack *track, AVStream *st)
4444 {
4445 382 int64_t pos = avio_tell(pb);
4446 382 int entry_backup = track->entry;
4447 382 int chunk_backup = track->chunkCount;
4448 int ret;
4449
4450 /* If we want to have an empty moov, but some samples already have been
4451 * buffered (delay_moov), pretend that no samples have been written yet. */
4452
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 279 times.
382 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4453 103 track->chunkCount = track->entry = 0;
4454
4455 382 avio_wb32(pb, 0); /* size */
4456 382 ffio_wfourcc(pb, "trak");
4457 382 mov_write_tkhd_tag(pb, mov, track, st);
4458
4459 av_assert2(mov->use_editlist >= 0);
4460
4461
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 37 times.
382 if (track->start_dts != AV_NOPTS_VALUE) {
4462
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 26 times.
345 if (mov->use_editlist)
4463 319 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4464
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))
4465 av_log(mov->fc, AV_LOG_WARNING,
4466 "Not writing any edit list even though one would have been required\n");
4467 }
4468
4469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (mov->is_animated_avif)
4470 mov_write_edts_tag(pb, mov, track);
4471
4472
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 368 times.
382 if (track->nb_tref_tags)
4473 14 mov_write_tref_tag(pb, track);
4474
4475
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4476 return ret;
4477
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 380 times.
382 if (track->mode == MODE_PSP)
4478 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4479
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 380 times.
382 if (track->tag == MKTAG('r','t','p',' '))
4480 2 mov_write_udta_sdp(pb, track);
4481
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
382 if (track->mode == MODE_MOV) {
4482
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 48 times.
192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4483 144 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4484
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) {
4485 1 mov_write_tapt_tag(pb, track);
4486 }
4487 }
4488
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) {
4489 mov_write_tapt_tag(pb, track);
4490 }
4491 }
4492 382 mov_write_track_udta_tag(pb, mov, st);
4493 382 track->entry = entry_backup;
4494 382 track->chunkCount = chunk_backup;
4495 382 return update_size(pb, pos);
4496 }
4497
4498 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4499 {
4500 int i, has_audio = 0, has_video = 0;
4501 int64_t pos = avio_tell(pb);
4502 int audio_profile = mov->iods_audio_profile;
4503 int video_profile = mov->iods_video_profile;
4504 for (i = 0; i < mov->nb_tracks; i++) {
4505 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4506 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4507 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4508 }
4509 }
4510 if (audio_profile < 0)
4511 audio_profile = 0xFF - has_audio;
4512 if (video_profile < 0)
4513 video_profile = 0xFF - has_video;
4514 avio_wb32(pb, 0x0); /* size */
4515 ffio_wfourcc(pb, "iods");
4516 avio_wb32(pb, 0); /* version & flags */
4517 put_descr(pb, 0x10, 7);
4518 avio_wb16(pb, 0x004f);
4519 avio_w8(pb, 0xff);
4520 avio_w8(pb, 0xff);
4521 avio_w8(pb, audio_profile);
4522 avio_w8(pb, video_profile);
4523 avio_w8(pb, 0xff);
4524 return update_size(pb, pos);
4525 }
4526
4527 123 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4528 {
4529 123 avio_wb32(pb, 0x20); /* size */
4530 123 ffio_wfourcc(pb, "trex");
4531 123 avio_wb32(pb, 0); /* version & flags */
4532 123 avio_wb32(pb, track->track_id); /* track ID */
4533 123 avio_wb32(pb, 1); /* default sample description index */
4534 123 avio_wb32(pb, 0); /* default sample duration */
4535 123 avio_wb32(pb, 0); /* default sample size */
4536 123 avio_wb32(pb, 0); /* default sample flags */
4537 123 return 0;
4538 }
4539
4540 67 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4541 {
4542 67 int64_t pos = avio_tell(pb);
4543 int i;
4544 67 avio_wb32(pb, 0x0); /* size */
4545 67 ffio_wfourcc(pb, "mvex");
4546
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 67 times.
190 for (i = 0; i < mov->nb_tracks; i++)
4547 123 mov_write_trex_tag(pb, &mov->tracks[i]);
4548 67 return update_size(pb, pos);
4549 }
4550
4551 280 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4552 {
4553 280 int max_track_id = 1, i;
4554 280 int64_t max_track_len = 0;
4555 int version;
4556 int timescale;
4557
4558
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
4559
3/4
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 345 times.
✗ Branch 3 not taken.
384 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4560 690 int64_t max_track_len_temp = av_rescale_rnd(
4561 345 calc_pts_duration(mov, &mov->tracks[i]),
4562 345 mov->movie_timescale,
4563 345 mov->tracks[i].timescale,
4564 AV_ROUND_UP);
4565
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 70 times.
345 if (max_track_len < max_track_len_temp)
4566 275 max_track_len = max_track_len_temp;
4567
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 261 times.
345 if (max_track_id < mov->tracks[i].track_id)
4568 84 max_track_id = mov->tracks[i].track_id;
4569 }
4570 }
4571 /* If using delay_moov, make sure the output is the same as if no
4572 * samples had been written yet. */
4573
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 223 times.
280 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4574 57 max_track_len = 0;
4575 57 max_track_id = 1;
4576 }
4577
4578 280 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4580
4581 280 ffio_wfourcc(pb, "mvhd");
4582 280 avio_w8(pb, version);
4583 280 avio_wb24(pb, 0); /* flags */
4584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 if (version == 1) {
4585 avio_wb64(pb, mov->time);
4586 avio_wb64(pb, mov->time);
4587 } else {
4588 280 avio_wb32(pb, mov->time); /* creation time */
4589 280 avio_wb32(pb, mov->time); /* modification time */
4590 }
4591
4592 280 timescale = mov->movie_timescale;
4593
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
280 if (mov->mode == MODE_AVIF && !timescale)
4594 timescale = mov->tracks[0].timescale;
4595
4596 280 avio_wb32(pb, timescale);
4597
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4598
4599 280 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4600 280 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4601 280 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4602
4603 /* Matrix structure */
4604 280 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4605
4606 280 avio_wb32(pb, 0); /* reserved (preview time) */
4607 280 avio_wb32(pb, 0); /* reserved (preview duration) */
4608 280 avio_wb32(pb, 0); /* reserved (poster time) */
4609 280 avio_wb32(pb, 0); /* reserved (selection time) */
4610 280 avio_wb32(pb, 0); /* reserved (selection duration) */
4611 280 avio_wb32(pb, 0); /* reserved (current time) */
4612 280 avio_wb32(pb, max_track_id + 1); /* Next track id */
4613 280 return 0x6c;
4614 }
4615
4616 120 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4617 AVFormatContext *s)
4618 {
4619 120 avio_wb32(pb, 33); /* size */
4620 120 ffio_wfourcc(pb, "hdlr");
4621 120 avio_wb32(pb, 0);
4622 120 avio_wb32(pb, 0);
4623 120 ffio_wfourcc(pb, "mdir");
4624 120 ffio_wfourcc(pb, "appl");
4625 120 avio_wb32(pb, 0);
4626 120 avio_wb32(pb, 0);
4627 120 avio_w8(pb, 0);
4628 120 return 33;
4629 }
4630
4631 /* helper function to write a data tag with the specified string as data */
4632 75 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4633 {
4634 75 size_t data_len = strlen(data);
4635
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 34 times.
75 if (long_style) {
4636 41 int size = 16 + data_len;
4637 41 avio_wb32(pb, size); /* size */
4638 41 ffio_wfourcc(pb, "data");
4639 41 avio_wb32(pb, 1);
4640 41 avio_wb32(pb, 0);
4641 41 avio_write(pb, data, data_len);
4642 41 return size;
4643 } else {
4644 34 avio_wb16(pb, data_len); /* string length */
4645
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4646 26 lang = ff_mov_iso639_to_lang("und", 1);
4647 34 avio_wb16(pb, lang);
4648 34 avio_write(pb, data, data_len);
4649 34 return data_len + 4;
4650 }
4651 }
4652
4653 74 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4654 const char *value, int lang, int long_style)
4655 {
4656 74 int size = 0;
4657
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]) {
4658 74 int64_t pos = avio_tell(pb);
4659 74 avio_wb32(pb, 0); /* size */
4660 74 ffio_wfourcc(pb, name);
4661 74 mov_write_string_data_tag(pb, value, lang, long_style);
4662 74 size = update_size(pb, pos);
4663 }
4664 74 return size;
4665 }
4666
4667 1 static int mov_write_freeform_tag(AVIOContext *pb, const char *mean,
4668 const char *name, const char *data)
4669 {
4670
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])
4671 return 0;
4672
4673 static const char stub_flags[4] = {0, 0, 0, 0};
4674
4675 1 int64_t entry_pos = avio_tell(pb);
4676 1 avio_wb32(pb, 0); /* size */
4677 1 ffio_wfourcc(pb, "----"); /* freeform */
4678
4679 1 size_t mean_len = strlen(mean);
4680 1 avio_wb32(pb, 12 + mean_len);
4681 1 ffio_wfourcc(pb, "mean");
4682 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4683 1 avio_write(pb, mean, mean_len);
4684
4685 1 size_t name_len = strlen(name);
4686 1 avio_wb32(pb, 12 + name_len);
4687 1 ffio_wfourcc(pb, "name");
4688 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4689 1 avio_write(pb, name, name_len);
4690
4691 1 mov_write_string_data_tag(pb, data, 0, 1);
4692
4693 1 return update_size(pb, entry_pos);
4694 }
4695
4696 4506 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4697 const char *tag, int *lang)
4698 {
4699 int l, len, len2;
4700 4506 AVDictionaryEntry *t, *t2 = NULL;
4701 char tag2[16];
4702
4703 4506 *lang = 0;
4704
4705
2/2
✓ Branch 1 taken 4443 times.
✓ Branch 2 taken 63 times.
4506 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4706 4443 return NULL;
4707
4708 63 len = strlen(t->key);
4709 63 snprintf(tag2, sizeof(tag2), "%s-", tag);
4710
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))) {
4711 8 len2 = strlen(t2->key);
4712
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)
4713
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4714 8 *lang = l;
4715 8 return t;
4716 }
4717 }
4718 55 return t;
4719 }
4720
4721 4386 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4722 const char *name, const char *tag,
4723 int long_style)
4724 {
4725 int lang;
4726 4386 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4727
2/2
✓ Branch 0 taken 4323 times.
✓ Branch 1 taken 63 times.
4386 if (!t)
4728 4323 return 0;
4729 63 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4730 }
4731
4732 120 static int mov_write_custom_metadata(AVFormatContext *s, AVIOContext *pb,
4733 const char *mean, const char *name,
4734 const char *tag)
4735 {
4736 120 AVDictionaryEntry *t = av_dict_get(s->metadata, tag, NULL, 0);
4737
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 1 times.
120 if (!t)
4738 119 return 0;
4739 1 return mov_write_freeform_tag(pb, mean, name, t->value);
4740 }
4741
4742 /* iTunes bpm number */
4743 120 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4744 {
4745 120 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 int size = 0, tmpo = t ? atoi(t->value) : 0;
4747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (tmpo) {
4748 size = 26;
4749 avio_wb32(pb, size);
4750 ffio_wfourcc(pb, "tmpo");
4751 avio_wb32(pb, size-8); /* size */
4752 ffio_wfourcc(pb, "data");
4753 avio_wb32(pb, 0x15); //type specifier
4754 avio_wb32(pb, 0);
4755 avio_wb16(pb, tmpo); // data
4756 }
4757 120 return size;
4758 }
4759
4760 /* 3GPP TS 26.244 */
4761 120 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4762 {
4763 int lang;
4764 120 int64_t pos = avio_tell(pb);
4765 double latitude, longitude, altitude;
4766 int32_t latitude_fix, longitude_fix, altitude_fix;
4767 120 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4768 120 const char *ptr, *place = "";
4769 char *end;
4770 static const char *astronomical_body = "earth";
4771
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 if (!t)
4772 120 return 0;
4773
4774 ptr = t->value;
4775 latitude = strtod(ptr, &end);
4776 if (end == ptr) {
4777 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4778 return 0;
4779 }
4780 ptr = end;
4781 longitude = strtod(ptr, &end);
4782 if (end == ptr) {
4783 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4784 return 0;
4785 }
4786 ptr = end;
4787 altitude = strtod(ptr, &end);
4788 /* If no altitude was present, the default 0 should be fine */
4789 if (*end == '/')
4790 place = end + 1;
4791
4792 latitude_fix = (int32_t) ((1 << 16) * latitude);
4793 longitude_fix = (int32_t) ((1 << 16) * longitude);
4794 altitude_fix = (int32_t) ((1 << 16) * altitude);
4795
4796 avio_wb32(pb, 0); /* size */
4797 ffio_wfourcc(pb, "loci"); /* type */
4798 avio_wb32(pb, 0); /* version + flags */
4799 avio_wb16(pb, lang);
4800 avio_write(pb, place, strlen(place) + 1);
4801 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4802 avio_wb32(pb, longitude_fix);
4803 avio_wb32(pb, latitude_fix);
4804 avio_wb32(pb, altitude_fix);
4805 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4806 avio_w8(pb, 0); /* additional notes, null terminated string */
4807
4808 return update_size(pb, pos);
4809 }
4810
4811 /* iTunes track or disc number */
4812 240 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4813 AVFormatContext *s, int disc)
4814 {
4815
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 120 times.
240 AVDictionaryEntry *t = av_dict_get(s->metadata,
4816 disc ? "disc" : "track",
4817 NULL, 0);
4818
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 236 times.
240 int size = 0, track = t ? atoi(t->value) : 0;
4819
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 236 times.
240 if (track) {
4820 4 int tracks = 0;
4821 4 char *slash = strchr(t->value, '/');
4822
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (slash)
4823 3 tracks = atoi(slash + 1);
4824 4 avio_wb32(pb, 32); /* size */
4825
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4826 4 avio_wb32(pb, 24); /* size */
4827 4 ffio_wfourcc(pb, "data");
4828 4 avio_wb32(pb, 0); // 8 bytes empty
4829 4 avio_wb32(pb, 0);
4830 4 avio_wb16(pb, 0); // empty
4831 4 avio_wb16(pb, track); // track / disc number
4832 4 avio_wb16(pb, tracks); // total track / disc number
4833 4 avio_wb16(pb, 0); // empty
4834 4 size = 32;
4835 }
4836 240 return size;
4837 }
4838
4839 720 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4840 const char *name, const char *tag,
4841 int len)
4842 {
4843 720 AVDictionaryEntry *t = NULL;
4844 uint8_t num;
4845 720 int size = 24 + len;
4846
4847
3/4
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 480 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
720 if (len != 1 && len != 4)
4848 return -1;
4849
4850
2/2
✓ Branch 1 taken 718 times.
✓ Branch 2 taken 2 times.
720 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4851 718 return 0;
4852 2 num = atoi(t->value);
4853
4854 2 avio_wb32(pb, size);
4855 2 ffio_wfourcc(pb, name);
4856 2 avio_wb32(pb, size - 8);
4857 2 ffio_wfourcc(pb, "data");
4858 2 avio_wb32(pb, 0x15);
4859 2 avio_wb32(pb, 0);
4860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4861 2 else avio_w8 (pb, num);
4862
4863 2 return size;
4864 }
4865
4866 120 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4867 {
4868 120 MOVMuxContext *mov = s->priv_data;
4869 120 int64_t pos = 0;
4870
4871
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 120 times.
303 for (int i = 0; i < mov->nb_streams; i++) {
4872 183 MOVTrack *trk = &mov->tracks[i];
4873
4874
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 181 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
183 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4875 181 continue;
4876
4877
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4878 1 pos = avio_tell(pb);
4879 1 avio_wb32(pb, 0);
4880 1 ffio_wfourcc(pb, "covr");
4881 }
4882 2 avio_wb32(pb, 16 + trk->cover_image->size);
4883 2 ffio_wfourcc(pb, "data");
4884 2 avio_wb32(pb, trk->tag);
4885 2 avio_wb32(pb , 0);
4886 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4887 }
4888
4889
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 119 times.
120 return pos ? update_size(pb, pos) : 0;
4890 }
4891
4892 /* iTunes meta data list */
4893 120 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4894 AVFormatContext *s)
4895 {
4896 120 int64_t pos = avio_tell(pb);
4897 120 avio_wb32(pb, 0); /* size */
4898 120 ffio_wfourcc(pb, "ilst");
4899 120 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4900 120 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4901 120 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4902 120 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4903 120 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4904 120 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4905
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4906
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 109 times.
120 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4907 11 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4908 }
4909 120 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4910 120 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4911 120 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4912 120 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4913 120 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4914 120 mov_write_string_metadata(s, pb, "desc", "description",1);
4915 120 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4916 120 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4917 120 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4918 120 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4919 120 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4920 120 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4921 120 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4922 120 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4923 120 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4924 120 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4925 120 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4926 120 mov_write_covr(pb, s);
4927 120 mov_write_trkn_tag(pb, mov, s, 0); // track number
4928 120 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4929 120 mov_write_tmpo_tag(pb, s);
4930 120 mov_write_custom_metadata(s, pb, "com.apple.iTunes", "DISCSUBTITLE", "disc_subtitle");
4931 120 return update_size(pb, pos);
4932 }
4933
4934 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4935 AVFormatContext *s)
4936 {
4937 avio_wb32(pb, 33); /* size */
4938 ffio_wfourcc(pb, "hdlr");
4939 avio_wb32(pb, 0);
4940 avio_wb32(pb, 0);
4941 ffio_wfourcc(pb, "mdta");
4942 avio_wb32(pb, 0);
4943 avio_wb32(pb, 0);
4944 avio_wb32(pb, 0);
4945 avio_w8(pb, 0);
4946 return 33;
4947 }
4948
4949 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4950 AVFormatContext *s)
4951 {
4952 const AVDictionaryEntry *t = NULL;
4953 int64_t pos = avio_tell(pb);
4954 int64_t curpos, entry_pos;
4955 int count = 0;
4956
4957 avio_wb32(pb, 0); /* size */
4958 ffio_wfourcc(pb, "keys");
4959 avio_wb32(pb, 0);
4960 entry_pos = avio_tell(pb);
4961 avio_wb32(pb, 0); /* entry count */
4962
4963 while (t = av_dict_iterate(s->metadata, t)) {
4964 size_t key_len = strlen(t->key);
4965 avio_wb32(pb, key_len + 8);
4966 ffio_wfourcc(pb, "mdta");
4967 avio_write(pb, t->key, key_len);
4968 count += 1;
4969 }
4970 curpos = avio_tell(pb);
4971 avio_seek(pb, entry_pos, SEEK_SET);
4972 avio_wb32(pb, count); // rewrite entry count
4973 avio_seek(pb, curpos, SEEK_SET);
4974
4975 return update_size(pb, pos);
4976 }
4977
4978 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4979 AVFormatContext *s)
4980 {
4981 const AVDictionaryEntry *t = NULL;
4982 int64_t pos = avio_tell(pb);
4983 int count = 1; /* keys are 1-index based */
4984
4985 avio_wb32(pb, 0); /* size */
4986 ffio_wfourcc(pb, "ilst");
4987
4988 while (t = av_dict_iterate(s->metadata, t)) {
4989 int64_t entry_pos = avio_tell(pb);
4990 avio_wb32(pb, 0); /* size */
4991 avio_wb32(pb, count); /* key */
4992 mov_write_string_data_tag(pb, t->value, 0, 1);
4993 update_size(pb, entry_pos);
4994 count += 1;
4995 }
4996 return update_size(pb, pos);
4997 }
4998
4999 /* meta data tags */
5000 120 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
5001 AVFormatContext *s)
5002 {
5003 120 int size = 0;
5004 120 int64_t pos = avio_tell(pb);
5005 120 avio_wb32(pb, 0); /* size */
5006 120 ffio_wfourcc(pb, "meta");
5007 120 avio_wb32(pb, 0);
5008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
5009 mov_write_mdta_hdlr_tag(pb, mov, s);
5010 mov_write_mdta_keys_tag(pb, mov, s);
5011 mov_write_mdta_ilst_tag(pb, mov, s);
5012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 } else if (mov->mode == MODE_AVIF) {
5013 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
5014 // We always write the primary item id as 1 since only one track is
5015 // supported for AVIF.
5016 mov_write_pitm_tag(pb, 1);
5017 mov_write_iloc_tag(pb, mov, s);
5018 mov_write_iinf_tag(pb, mov, s);
5019 if (mov->nb_streams > 1)
5020 mov_write_iref_tag(pb, mov, s);
5021 mov_write_iprp_tag(pb, mov, s);
5022 } else {
5023 /* iTunes metadata tag */
5024 120 mov_write_itunes_hdlr_tag(pb, mov, s);
5025 120 mov_write_ilst_tag(pb, mov, s);
5026 }
5027 120 size = update_size(pb, pos);
5028 120 return size;
5029 }
5030
5031 159 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
5032 const char *name, const char *key)
5033 {
5034 int len;
5035 AVDictionaryEntry *t;
5036
5037
1/2
✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
159 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
5038 159 return 0;
5039
5040 len = strlen(t->value);
5041 if (len > 0) {
5042 int size = len + 8;
5043 avio_wb32(pb, size);
5044 ffio_wfourcc(pb, name);
5045 avio_write(pb, t->value, len);
5046 return size;
5047 }
5048 return 0;
5049 }
5050
5051 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
5052 {
5053 int val;
5054 while (*b) {
5055 GET_UTF8(val, *b++, return -1;)
5056 avio_wb16(pb, val);
5057 }
5058 avio_wb16(pb, 0x00);
5059 return 0;
5060 }
5061
5062 static uint16_t language_code(const char *str)
5063 {
5064 return (((str[0] - 0x60) & 0x1F) << 10) +
5065 (((str[1] - 0x60) & 0x1F) << 5) +
5066 (( str[2] - 0x60) & 0x1F);
5067 }
5068
5069 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
5070 const char *tag, const char *str)
5071 {
5072 int64_t pos = avio_tell(pb);
5073 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
5074 if (!t || !utf8len(t->value))
5075 return 0;
5076 avio_wb32(pb, 0); /* size */
5077 ffio_wfourcc(pb, tag); /* type */
5078 avio_wb32(pb, 0); /* version + flags */
5079 if (!strcmp(tag, "yrrc"))
5080 avio_wb16(pb, atoi(t->value));
5081 else {
5082 avio_wb16(pb, language_code("eng")); /* language */
5083 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
5084 if (!strcmp(tag, "albm") &&
5085 (t = av_dict_get(s->metadata, "track", NULL, 0)))
5086 avio_w8(pb, atoi(t->value));
5087 }
5088 return update_size(pb, pos);
5089 }
5090
5091 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
5092 {
5093 1 int64_t pos = avio_tell(pb);
5094 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
5095
5096 1 avio_wb32(pb, 0); // size
5097 1 ffio_wfourcc(pb, "chpl");
5098 1 avio_wb32(pb, 0x01000000); // version + flags
5099 1 avio_wb32(pb, 0); // unknown
5100 1 avio_w8(pb, nb_chapters);
5101
5102
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
5103 4 AVChapter *c = s->chapters[i];
5104 AVDictionaryEntry *t;
5105 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
5106
5107
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
5108
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
5109 4 avio_w8(pb, len);
5110 4 avio_write(pb, t->value, len);
5111 } else
5112 avio_w8(pb, 0);
5113 }
5114 1 return update_size(pb, pos);
5115 }
5116
5117 279 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
5118 AVFormatContext *s)
5119 {
5120 AVIOContext *pb_buf;
5121 int ret, size;
5122 uint8_t *buf;
5123
5124 279 ret = avio_open_dyn_buf(&pb_buf);
5125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 if (ret < 0)
5126 return ret;
5127
5128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 if (mov->mode & MODE_3GP) {
5129 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
5130 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
5131 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
5132 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
5133 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
5134 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
5135 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
5136 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
5137 mov_write_loci_tag(s, pb_buf);
5138
3/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
279 } 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
5139 159 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
5140 159 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
5141 159 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
5142 159 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
5143 159 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
5144 159 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
5145 // currently ignored by mov.c
5146 159 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
5147 // add support for libquicktime, this atom is also actually read by mov.c
5148 159 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
5149 159 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
5150 159 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
5151 159 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
5152 159 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
5153 159 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
5154 159 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
5155 159 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
5156 } else {
5157 /* iTunes meta data */
5158 120 mov_write_meta_tag(pb_buf, mov, s);
5159 120 mov_write_loci_tag(s, pb_buf);
5160 }
5161
5162
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
279 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
5163 1 mov_write_chpl_tag(pb_buf, s);
5164
5165
2/2
✓ Branch 1 taken 148 times.
✓ Branch 2 taken 131 times.
279 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
5166 148 avio_wb32(pb, size + 8);
5167 148 ffio_wfourcc(pb, "udta");
5168 148 avio_write(pb, buf, size);
5169 }
5170 279 ffio_free_dyn_buf(&pb_buf);
5171
5172 279 return 0;
5173 }
5174
5175 static void mov_write_psp_udta_tag(AVIOContext *pb,
5176 const char *str, const char *lang, int type)
5177 {
5178 int len = utf8len(str) + 1;
5179 if (len <= 0)
5180 return;
5181 avio_wb16(pb, len * 2 + 10); /* size */
5182 avio_wb32(pb, type); /* type */
5183 avio_wb16(pb, language_code(lang)); /* language */
5184 avio_wb16(pb, 0x01); /* ? */
5185 ascii_to_wc(pb, str);
5186 }
5187
5188 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5189 {
5190 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5191 int64_t pos, pos2;
5192
5193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5194 pos = avio_tell(pb);
5195 avio_wb32(pb, 0); /* size placeholder*/
5196 ffio_wfourcc(pb, "uuid");
5197 ffio_wfourcc(pb, "USMT");
5198 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5199 avio_wb32(pb, 0xbb88695c);
5200 avio_wb32(pb, 0xfac9c740);
5201
5202 pos2 = avio_tell(pb);
5203 avio_wb32(pb, 0); /* size placeholder*/
5204 ffio_wfourcc(pb, "MTDT");
5205 avio_wb16(pb, 4);
5206
5207 // ?
5208 avio_wb16(pb, 0x0C); /* size */
5209 avio_wb32(pb, 0x0B); /* type */
5210 avio_wb16(pb, language_code("und")); /* language */
5211 avio_wb16(pb, 0x0); /* ? */
5212 avio_wb16(pb, 0x021C); /* data */
5213
5214 if (!(s->flags & AVFMT_FLAG_BITEXACT))
5215 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5216 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5217 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5218
5219 update_size(pb, pos2);
5220 return update_size(pb, pos);
5221 }
5222
5223 1 return 0;
5224 }
5225
5226 371 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5227 {
5228 AVEncryptionInitInfo *info;
5229 371 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5230 371 st->codecpar->nb_coded_side_data,
5231 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5232
1/2
✓ Branch 0 taken 371 times.
✗ Branch 1 not taken.
371 if (!sd)
5233 371 return 0;
5234
5235 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5236 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5237 int64_t pos;
5238
5239 if (!copy->data_size && !copy->num_key_ids)
5240 continue;
5241
5242 pos = avio_tell(pb);
5243 avio_wb32(pb, 0); /* size placeholder */
5244 ffio_wfourcc(pb, "pssh");
5245 avio_w8(pb, 1); /* version */
5246 avio_wb24(pb, 0);
5247 for (int i = 0; i < copy->system_id_size; i++)
5248 avio_w8(pb, copy->system_id[i]);
5249 avio_wb32(pb, copy->num_key_ids);
5250 for (int i = 0; i < copy->num_key_ids; i++)
5251 for (int j = 0; j < copy->key_id_size; j++)
5252 avio_w8(pb, copy->key_ids[i][j]);
5253 avio_wb32(pb, copy->data_size);
5254 avio_write(pb, copy->data, copy->data_size);
5255 update_size(pb, pos);
5256 }
5257
5258 av_encryption_init_info_free(info);
5259
5260 return 0;
5261 }
5262
5263 345 static void build_chunks(MOVTrack *trk)
5264 {
5265 int i;
5266 345 MOVIentry *chunk = &trk->cluster[0];
5267 345 uint64_t chunkSize = chunk->size;
5268 345 chunk->chunkNum = 1;
5269
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 287 times.
345 if (trk->chunkCount)
5270 58 return;
5271 287 trk->chunkCount = 1;
5272
2/2
✓ Branch 0 taken 18504 times.
✓ Branch 1 taken 287 times.
18791 for (i = 1; i<trk->entry; i++){
5273
2/2
✓ Branch 0 taken 16765 times.
✓ Branch 1 taken 1739 times.
18504 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5274
2/2
✓ Branch 0 taken 16763 times.
✓ Branch 1 taken 2 times.
16765 chunk->stsd_index == trk->cluster[i].stsd_index &&
5275
2/2
✓ Branch 0 taken 16118 times.
✓ Branch 1 taken 645 times.
16763 chunkSize + trk->cluster[i].size < (1<<20)){
5276 16118 chunkSize += trk->cluster[i].size;
5277 16118 chunk->samples_in_chunk += trk->cluster[i].entries;
5278 } else {
5279 2386 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5280 2386 chunk=&trk->cluster[i];
5281 2386 chunkSize = chunk->size;
5282 2386 trk->chunkCount++;
5283 }
5284 }
5285 }
5286
5287 /**
5288 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5289 * the stream ids are used as track ids.
5290 *
5291 * This assumes mov->tracks and s->streams are in the same order and
5292 * there are no gaps in either of them (so mov->tracks[n] refers to
5293 * s->streams[n]).
5294 *
5295 * As an exception, there can be more entries in
5296 * s->streams than in mov->tracks, in which case new track ids are
5297 * generated (starting after the largest found stream id).
5298 */
5299 280 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5300 {
5301 int i;
5302
5303
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 247 times.
280 if (mov->track_ids_ok)
5304 33 return 0;
5305
5306
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->use_stream_ids_as_track_ids) {
5307 1 int next_generated_track_id = 0;
5308
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5309 2 AVStream *st = mov->tracks[i].st;
5310
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5311 2 next_generated_track_id = st->id;
5312 }
5313
5314
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5315
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))
5316 continue;
5317
5318
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;
5319 }
5320 } else {
5321 246 int last_track_id = 0;
5322
2/2
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 246 times.
562 for (i = 0; i < mov->nb_tracks; i++) {
5323
4/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 33 times.
316 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5324 2 continue;
5325
5326 314 last_track_id =
5327 314 mov->tracks[i].track_id = (mov->tracks[i].st
5328 311 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5329
2/2
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 3 times.
314 : FFMAX(i, last_track_id)) + 1;
5330 }
5331 }
5332
5333 247 mov->track_ids_ok = 1;
5334
5335 247 return 0;
5336 }
5337
5338 16 static int mov_find_tref_id(MOVMuxContext *mov, const MovTag *tag, uint32_t id)
5339 {
5340
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12 times.
19 for (int i = 0; i < tag->nb_id; i++) {
5341
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (tag->id[i] == id)
5342 4 return 1;
5343 }
5344 12 return 0;
5345 }
5346
5347 16 static int mov_add_tref_id(MOVMuxContext *mov, MovTag *tag, uint32_t id)
5348 {
5349 16 int ret = mov_find_tref_id(mov, tag, id);
5350
5351
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 if (!ret) {
5352 12 uint32_t *tmp = av_realloc_array(tag->id, tag->nb_id + 1, sizeof(*tag->id));
5353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!tmp)
5354 return AVERROR(ENOMEM);
5355 12 tag->id = tmp;
5356 12 tag->id[tag->nb_id++] = id;
5357 }
5358
5359 16 return 0;
5360 }
5361
5362 16 static MovTag *mov_find_tref_tag(MOVMuxContext *mov, const MOVTrack *trk, uint32_t name)
5363 {
5364
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 for (int i = 0; i < trk->nb_tref_tags; i++) {
5365 6 MovTag *entry = &trk->tref_tags[i];
5366
5367
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (entry->name == name)
5368 6 return entry;
5369 }
5370 10 return NULL;
5371 }
5372
5373 16 static MovTag *mov_add_tref_tag(MOVMuxContext *mov, MOVTrack *trk, uint32_t name)
5374 {
5375 16 MovTag *tag = mov_find_tref_tag(mov, trk, name);
5376
5377
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if (!tag) {
5378 10 MovTag *tmp = av_realloc_array(trk->tref_tags, trk->nb_tref_tags + 1,
5379 sizeof(*trk->tref_tags));
5380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!tmp)
5381 return NULL;
5382 10 trk->tref_tags = tmp;
5383 10 tag = &trk->tref_tags[trk->nb_tref_tags++];
5384 10 *tag = (MovTag){ .name = name };
5385 }
5386
5387 16 return tag;
5388 }
5389
5390 280 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5391 AVFormatContext *s)
5392 {
5393 int i;
5394 280 int64_t pos = avio_tell(pb);
5395 280 avio_wb32(pb, 0); /* size placeholder*/
5396 280 ffio_wfourcc(pb, "moov");
5397
5398 280 mov_setup_track_ids(mov, s);
5399
5400
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
5401
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 345 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 37 times.
384 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5402 2 continue;
5403
5404 382 mov->tracks[i].time = mov->time;
5405
5406
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 37 times.
382 if (mov->tracks[i].entry)
5407 345 build_chunks(&mov->tracks[i]);
5408 }
5409
5410
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
280 if (mov->chapter_track)
5411
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5412 1 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[i], MKTAG('c','h','a','p'));
5413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
5414 return AVERROR(ENOMEM);
5415
5416 1 int ret = mov_add_tref_id(mov, tag, mov->tracks[mov->chapter_track].track_id);
5417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
5418 return ret;
5419 }
5420
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
5421 384 MOVTrack *track = &mov->tracks[i];
5422
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 382 times.
384 if (track->tag == MKTAG('r','t','p',' ')) {
5423 2 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('h','i','n','t'));
5424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
5425 return AVERROR(ENOMEM);
5426
5427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
5428 2 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
5430 return ret;
5431
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
382 } else if (track->tag == MKTAG('l','v','c','1') && track->nb_src_track) {
5432 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('s','b','a','s'));
5433 if (!tag)
5434 return AVERROR(ENOMEM);
5435
5436 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5437 if (ret < 0)
5438 return ret;
5439 } else {
5440
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 254 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5441 128 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5442 128 track->st->codecpar->nb_coded_side_data,
5443 AV_PKT_DATA_FALLBACK_TRACK );
5444
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
128 if (sd && sd->size == sizeof(int)) {
5445 int *fallback = (int *)sd->data;
5446 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5447 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('f','a','l','l'));
5448 if (!tag)
5449 return AVERROR(ENOMEM);
5450
5451 int ret = mov_add_tref_id(mov, tag, mov->tracks[*fallback].track_id);
5452 if (ret < 0)
5453 return ret;
5454 }
5455 }
5456 }
5457
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 382 times.
395 for (int j = 0; j < track->nb_src_track; j++) {
5458 13 int src_trk = track->src_track[j];
5459 13 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[src_trk], track->tag);
5460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tag)
5461 return AVERROR(ENOMEM);
5462 13 int ret = mov_add_tref_id(mov, tag, track->track_id);
5463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (ret < 0)
5464 return ret;
5465 }
5466
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
382 if (mov->nb_meta_tmcd && track->nb_src_track) {
5467 /* Derive the duration from the first source track, matching
5468 * the convention used by get_pts_range() and the rtp/lvc1
5469 * branches above. The source may use a different timescale. */
5470 10 int src_trk = track->src_track[0];
5471 10 track->track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5472 10 track->timescale,
5473 10 mov->tracks[src_trk].timescale);
5474 }
5475 }
5476 }
5477
5478 280 mov_write_mvhd_tag(pb, mov);
5479
4/6
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 121 times.
280 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5480 mov_write_iods_tag(pb, mov);
5481
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
5482
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 345 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 37 times.
384 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5484
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 13 times.
382 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (ret < 0)
5486 return ret;
5487 }
5488 }
5489 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5490 * (mov->moov_written != 0)
5491 */
5492
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 211 times.
280 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5493
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))
5494 67 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5495
5496
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
280 if (mov->mode == MODE_PSP)
5497 1 mov_write_uuidusmt_tag(pb, s);
5498
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
279 else if (mov->mode != MODE_AVIF)
5499 279 mov_write_udta_tag(pb, mov, s);
5500
2/2
✓ Branch 0 taken 371 times.
✓ Branch 1 taken 280 times.
651 for (i = 0; i < mov->nb_streams; i++)
5501 371 mov_write_pssh_tag(pb, mov->tracks[i].st);
5502
5503 280 return update_size(pb, pos);
5504 }
5505
5506 static void param_write_int(AVIOContext *pb, const char *name, int value)
5507 {
5508 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5509 }
5510
5511 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5512 {
5513 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5514 }
5515
5516 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5517 {
5518 char buf[150];
5519 len = FFMIN(sizeof(buf) / 2 - 1, len);
5520 ff_data_to_hex(buf, value, len, 0);
5521 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5522 }
5523
5524 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5525 {
5526 int64_t pos = avio_tell(pb);
5527 int i;
5528
5529 static const AVUUID uuid = {
5530 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5531 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5532 };
5533
5534 avio_wb32(pb, 0);
5535 ffio_wfourcc(pb, "uuid");
5536 avio_write(pb, uuid, AV_UUID_LEN);
5537 avio_wb32(pb, 0);
5538
5539 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5540 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5541 avio_printf(pb, "<head>\n");
5542 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5543 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5544 LIBAVFORMAT_IDENT);
5545 avio_printf(pb, "</head>\n");
5546 avio_printf(pb, "<body>\n");
5547 avio_printf(pb, "<switch>\n");
5548
5549 mov_setup_track_ids(mov, s);
5550
5551 for (i = 0; i < mov->nb_tracks; i++) {
5552 MOVTrack *track = &mov->tracks[i];
5553 struct mpeg4_bit_rate_values bit_rates =
5554 calculate_mpeg4_bit_rates(track);
5555 const char *type;
5556 int track_id = track->track_id;
5557 char track_name_buf[32] = { 0 };
5558
5559 AVStream *st = track->st;
5560 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5561
5562 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5563 type = "video";
5564 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5565 type = "audio";
5566 } else {
5567 continue;
5568 }
5569
5570 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5571 bit_rates.avg_bit_rate);
5572 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5573 param_write_int(pb, "trackID", track_id);
5574 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5575
5576 /* Build track name piece by piece: */
5577 /* 1. track type */
5578 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5579 /* 2. track language, if available */
5580 if (lang)
5581 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5582 "_%s", lang->value);
5583 /* 3. special type suffix */
5584 /* "_cc" = closed captions, "_ad" = audio_description */
5585 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5586 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5587 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5588 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5589
5590 param_write_string(pb, "trackName", track_name_buf);
5591
5592 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5593 if (track->par->codec_id == AV_CODEC_ID_H264) {
5594 uint8_t *ptr;
5595 int size = track->extradata_size[track->last_stsd_index];
5596 if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5597 &size)) {
5598 param_write_hex(pb, "CodecPrivateData",
5599 ptr ? ptr : track->extradata[track->last_stsd_index],
5600 size);
5601 av_free(ptr);
5602 }
5603 param_write_string(pb, "FourCC", "H264");
5604 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5605 param_write_string(pb, "FourCC", "WVC1");
5606 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5607 track->extradata_size[track->last_stsd_index]);
5608 }
5609 param_write_int(pb, "MaxWidth", track->par->width);
5610 param_write_int(pb, "MaxHeight", track->par->height);
5611 param_write_int(pb, "DisplayWidth", track->par->width);
5612 param_write_int(pb, "DisplayHeight", track->par->height);
5613 } else {
5614 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5615 switch (track->par->profile) {
5616 case AV_PROFILE_AAC_HE_V2:
5617 param_write_string(pb, "FourCC", "AACP");
5618 break;
5619 case AV_PROFILE_AAC_HE:
5620 param_write_string(pb, "FourCC", "AACH");
5621 break;
5622 default:
5623 param_write_string(pb, "FourCC", "AACL");
5624 }
5625 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5626 param_write_string(pb, "FourCC", "WMAP");
5627 }
5628 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5629 track->extradata_size[track->last_stsd_index]);
5630 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5631 track->par->codec_id));
5632 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5633 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5634 0 : track->par->sample_rate);
5635 param_write_int(pb, "BitsPerSample", 16);
5636 param_write_int(pb, "PacketSize", track->par->block_align ?
5637 track->par->block_align : 4);
5638 }
5639 avio_printf(pb, "</%s>\n", type);
5640 }
5641 avio_printf(pb, "</switch>\n");
5642 avio_printf(pb, "</body>\n");
5643 avio_printf(pb, "</smil>\n");
5644
5645 return update_size(pb, pos);
5646 }
5647
5648 238 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5649 {
5650 238 avio_wb32(pb, 16);
5651 238 ffio_wfourcc(pb, "mfhd");
5652 238 avio_wb32(pb, 0);
5653 238 avio_wb32(pb, mov->fragments);
5654 238 return 0;
5655 }
5656
5657 13566 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5658 {
5659
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 :
5660 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5661 }
5662
5663 358 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5664 MOVTrack *track, int64_t moof_offset)
5665 {
5666 358 int64_t pos = avio_tell(pb);
5667 358 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5668 MOV_TFHD_BASE_DATA_OFFSET;
5669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 if (!track->entry) {
5670 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5671 } else {
5672 358 flags |= MOV_TFHD_DEFAULT_FLAGS;
5673 }
5674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5675 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5676
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 214 times.
358 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5677 144 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5678 144 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5679 }
5680 /* CMAF requires all values to be explicit in tfhd atoms */
5681
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 298 times.
358 if (mov->flags & FF_MOV_FLAG_CMAF)
5682 60 flags |= MOV_TFHD_STSD_ID;
5683
5684 /* Don't set a default sample size, the silverlight player refuses
5685 * to play files with that set. Don't set a default sample duration,
5686 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5687 * file format says it MUST NOT be set. */
5688
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 276 times.
358 if (track->mode == MODE_ISM)
5689 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5690 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5691
5692 358 avio_wb32(pb, 0); /* size placeholder */
5693 358 ffio_wfourcc(pb, "tfhd");
5694 358 avio_w8(pb, 0); /* version */
5695 358 avio_wb24(pb, flags);
5696
5697 358 avio_wb32(pb, track->track_id); /* track-id */
5698
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 226 times.
358 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5699 132 avio_wb64(pb, moof_offset);
5700
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 298 times.
358 if (flags & MOV_TFHD_STSD_ID) {
5701 60 avio_wb32(pb, 1);
5702 }
5703
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5704 276 track->default_duration = get_cluster_duration(track, 0);
5705 276 avio_wb32(pb, track->default_duration);
5706 }
5707
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5708
1/2
✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
276 track->default_size = track->entry ? track->cluster[0].size : 1;
5709 276 avio_wb32(pb, track->default_size);
5710 } else
5711 82 track->default_size = -1;
5712
5713
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5714 /* Set the default flags based on the second sample, if available.
5715 * If the first sample is different, that can be signaled via a separate field. */
5716
2/2
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 72 times.
358 if (track->entry > 1)
5717 286 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5718 else
5719 72 track->default_sample_flags =
5720 72 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5721
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) :
5722 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5723 358 avio_wb32(pb, track->default_sample_flags);
5724 }
5725
5726 358 return update_size(pb, pos);
5727 }
5728
5729 360 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5730 MOVTrack *track, int moof_size,
5731 int first, int end)
5732 {
5733 360 int64_t pos = avio_tell(pb);
5734 360 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5735 int i;
5736
5737
2/2
✓ Branch 0 taken 12740 times.
✓ Branch 1 taken 360 times.
13100 for (i = first; i < end; i++) {
5738
2/2
✓ Branch 1 taken 1838 times.
✓ Branch 2 taken 10902 times.
12740 if (get_cluster_duration(track, i) != track->default_duration)
5739 1838 flags |= MOV_TRUN_SAMPLE_DURATION;
5740
2/2
✓ Branch 0 taken 2956 times.
✓ Branch 1 taken 9784 times.
12740 if (track->cluster[i].size != track->default_size)
5741 2956 flags |= MOV_TRUN_SAMPLE_SIZE;
5742
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)
5743 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5744 }
5745
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 &&
5746
2/2
✓ Branch 1 taken 176 times.
✓ Branch 2 taken 176 times.
352 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5747 176 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5748
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 260 times.
360 if (track->flags & MOV_TRACK_CTTS)
5749 100 flags |= MOV_TRUN_SAMPLE_CTS;
5750
5751 360 avio_wb32(pb, 0); /* size placeholder */
5752 360 ffio_wfourcc(pb, "trun");
5753
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 202 times.
360 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5754 158 avio_w8(pb, 1); /* version */
5755 else
5756 202 avio_w8(pb, 0); /* version */
5757 360 avio_wb24(pb, flags);
5758
5759 360 avio_wb32(pb, end - first); /* sample count */
5760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5761 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5762 !mov->first_trun)
5763 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5764 else
5765 360 avio_wb32(pb, moof_size + 8 + track->data_offset +
5766 360 track->cluster[first].pos); /* data offset */
5767
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 184 times.
360 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5768 176 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5769
5770
2/2
✓ Branch 0 taken 12740 times.
✓ Branch 1 taken 360 times.
13100 for (i = first; i < end; i++) {
5771
2/2
✓ Branch 0 taken 2030 times.
✓ Branch 1 taken 10710 times.
12740 if (flags & MOV_TRUN_SAMPLE_DURATION)
5772 2030 avio_wb32(pb, get_cluster_duration(track, i));
5773
2/2
✓ Branch 0 taken 3636 times.
✓ Branch 1 taken 9104 times.
12740 if (flags & MOV_TRUN_SAMPLE_SIZE)
5774 3636 avio_wb32(pb, track->cluster[i].size);
5775
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 12368 times.
12740 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5776 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5777
2/2
✓ Branch 0 taken 3162 times.
✓ Branch 1 taken 9578 times.
12740 if (flags & MOV_TRUN_SAMPLE_CTS)
5778 3162 avio_wb32(pb, track->cluster[i].cts);
5779 }
5780
5781 360 mov->first_trun = 0;
5782 360 return update_size(pb, pos);
5783 }
5784
5785 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5786 {
5787 82 int64_t pos = avio_tell(pb);
5788 static const uint8_t uuid[] = {
5789 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5790 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5791 };
5792
5793 82 avio_wb32(pb, 0); /* size placeholder */
5794 82 ffio_wfourcc(pb, "uuid");
5795 82 avio_write(pb, uuid, AV_UUID_LEN);
5796 82 avio_w8(pb, 1);
5797 82 avio_wb24(pb, 0);
5798 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5799 82 avio_wb64(pb, track->end_pts -
5800 82 (track->cluster[0].dts + track->cluster[0].cts));
5801
5802 82 return update_size(pb, pos);
5803 }
5804
5805 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5806 MOVTrack *track, int entry)
5807 {
5808 int n = track->nb_frag_info - 1 - entry, i;
5809 int size = 8 + 16 + 4 + 1 + 16*n;
5810 static const uint8_t uuid[] = {
5811 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5812 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5813 };
5814
5815 if (entry < 0)
5816 return 0;
5817
5818 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5819 avio_wb32(pb, size);
5820 ffio_wfourcc(pb, "uuid");
5821 avio_write(pb, uuid, AV_UUID_LEN);
5822 avio_w8(pb, 1);
5823 avio_wb24(pb, 0);
5824 avio_w8(pb, n);
5825 for (i = 0; i < n; i++) {
5826 int index = entry + 1 + i;
5827 avio_wb64(pb, track->frag_info[index].time);
5828 avio_wb64(pb, track->frag_info[index].duration);
5829 }
5830 if (n < mov->ism_lookahead) {
5831 int free_size = 16 * (mov->ism_lookahead - n);
5832 avio_wb32(pb, free_size);
5833 ffio_wfourcc(pb, "free");
5834 ffio_fill(pb, 0, free_size - 8);
5835 }
5836
5837 return 0;
5838 }
5839
5840 178 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5841 MOVTrack *track)
5842 {
5843 178 int64_t pos = avio_tell(pb);
5844 int i;
5845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 178 times.
178 for (i = 0; i < mov->ism_lookahead; i++) {
5846 /* Update the tfrf tag for the last ism_lookahead fragments,
5847 * nb_frag_info - 1 is the next fragment to be written. */
5848 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5849 }
5850 178 avio_seek(pb, pos, SEEK_SET);
5851 178 return 0;
5852 }
5853
5854 118 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5855 int size)
5856 {
5857 int i;
5858
2/2
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 118 times.
339 for (i = 0; i < mov->nb_tracks; i++) {
5859 221 MOVTrack *track = &mov->tracks[i];
5860 MOVFragmentInfo *info;
5861
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)
5862 43 continue;
5863 178 track->nb_frag_info++;
5864
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 106 times.
178 if (track->nb_frag_info >= track->frag_info_capacity) {
5865 72 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5866
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (av_reallocp_array(&track->frag_info,
5867 new_capacity,
5868 sizeof(*track->frag_info)))
5869 return AVERROR(ENOMEM);
5870 72 track->frag_info_capacity = new_capacity;
5871 }
5872 178 info = &track->frag_info[track->nb_frag_info - 1];
5873 178 info->offset = avio_tell(pb);
5874 178 info->size = size;
5875 // Try to recreate the original pts for the first packet
5876 // from the fields we have stored
5877 178 info->time = track->cluster[0].dts + track->cluster[0].cts;
5878 178 info->duration = track->end_pts -
5879 178 (track->cluster[0].dts + track->cluster[0].cts);
5880 // If the pts is less than zero, we will have trimmed
5881 // away parts of the media track using an edit list,
5882 // and the corresponding start presentation time is zero.
5883
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 170 times.
178 if (info->time < 0) {
5884 8 info->duration += info->time;
5885 8 info->time = 0;
5886 }
5887 178 info->tfrf_offset = 0;
5888 178 mov_write_tfrf_tags(pb, mov, track);
5889 }
5890 118 return 0;
5891 }
5892
5893 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5894 {
5895 int i;
5896 for (i = 0; i < mov->nb_tracks; i++) {
5897 MOVTrack *track = &mov->tracks[i];
5898 if ((tracks >= 0 && i != tracks) || !track->entry)
5899 continue;
5900 if (track->nb_frag_info > max) {
5901 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5902 track->nb_frag_info = max;
5903 }
5904 }
5905 }
5906
5907 276 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5908 {
5909 276 int64_t pos = avio_tell(pb);
5910
5911 276 avio_wb32(pb, 0); /* size */
5912 276 ffio_wfourcc(pb, "tfdt");
5913 276 avio_w8(pb, 1); /* version */
5914 276 avio_wb24(pb, 0);
5915 276 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5916 276 return update_size(pb, pos);
5917 }
5918
5919 358 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5920 MOVTrack *track, int64_t moof_offset,
5921 int moof_size)
5922 {
5923 358 int64_t pos = avio_tell(pb);
5924 358 int i, start = 0;
5925 358 avio_wb32(pb, 0); /* size placeholder */
5926 358 ffio_wfourcc(pb, "traf");
5927
5928 358 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5929
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (mov->mode != MODE_ISM)
5930 276 mov_write_tfdt_tag(pb, track);
5931
2/2
✓ Branch 0 taken 12382 times.
✓ Branch 1 taken 358 times.
12740 for (i = 1; i < track->entry; i++) {
5932
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) {
5933 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5934 2 start = i;
5935 }
5936 }
5937 358 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5938
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 276 times.
358 if (mov->mode == MODE_ISM) {
5939 82 mov_write_tfxd_tag(pb, track);
5940
5941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5942 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5943
5944 if (track->nb_frag_info > 0) {
5945 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5946 if (!info->tfrf_offset)
5947 info->tfrf_offset = avio_tell(pb);
5948 }
5949 avio_wb32(pb, 8 + size);
5950 ffio_wfourcc(pb, "free");
5951 ffio_fill(pb, 0, size);
5952 }
5953 }
5954
5955
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))
5956 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5957
5958 358 return update_size(pb, pos);
5959 }
5960
5961 238 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5962 int tracks, int moof_size)
5963 {
5964 238 int64_t pos = avio_tell(pb);
5965 int i;
5966
5967 238 avio_wb32(pb, 0); /* size placeholder */
5968 238 ffio_wfourcc(pb, "moof");
5969 238 mov->first_trun = 1;
5970
5971 238 mov_write_mfhd_tag(pb, mov);
5972
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 238 times.
682 for (i = 0; i < mov->nb_tracks; i++) {
5973 444 MOVTrack *track = &mov->tracks[i];
5974
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)
5975 76 continue;
5976
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 358 times.
368 if (!track->entry)
5977 10 continue;
5978
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))
5979 mov_write_pssh_tag(pb, track->st);
5980 358 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5981 }
5982
5983 238 return update_size(pb, pos);
5984 }
5985
5986 78 static int mov_write_sidx_tag(AVIOContext *pb,
5987 MOVTrack *track, int ref_size, int total_sidx_size)
5988 {
5989 78 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5990 int64_t presentation_time, duration, offset;
5991 unsigned starts_with_SAP;
5992 int i, entries;
5993
5994
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 if (track->entry) {
5995 78 entries = 1;
5996 78 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
5997 78 duration = track->end_pts -
5998 78 (track->cluster[0].dts + track->cluster[0].cts);
5999 78 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6000
6001 // pts<0 should be cut away using edts
6002
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 72 times.
78 if (presentation_time < 0) {
6003 6 duration += presentation_time;
6004 6 presentation_time = 0;
6005 }
6006 } else {
6007 entries = track->nb_frag_info;
6008 if (entries <= 0)
6009 return 0;
6010 presentation_time = track->frag_info[0].time;
6011 }
6012
6013 78 avio_wb32(pb, 0); /* size */
6014 78 ffio_wfourcc(pb, "sidx");
6015 78 avio_w8(pb, 1); /* version */
6016 78 avio_wb24(pb, 0);
6017 78 avio_wb32(pb, track->track_id); /* reference_ID */
6018 78 avio_wb32(pb, track->timescale); /* timescale */
6019 78 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
6020 78 offset_pos = avio_tell(pb);
6021 78 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
6022 78 avio_wb16(pb, 0); /* reserved */
6023
6024 78 avio_wb16(pb, entries); /* reference_count */
6025
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 78 times.
156 for (i = 0; i < entries; i++) {
6026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (!track->entry) {
6027 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
6028 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
6029 }
6030 duration = track->frag_info[i].duration;
6031 ref_size = track->frag_info[i].size;
6032 starts_with_SAP = 1;
6033 }
6034 78 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
6035 78 avio_wb32(pb, duration); /* subsegment_duration */
6036 78 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
6037 }
6038
6039 78 end_pos = avio_tell(pb);
6040 78 offset = pos + total_sidx_size - end_pos;
6041 78 avio_seek(pb, offset_pos, SEEK_SET);
6042 78 avio_wb64(pb, offset);
6043 78 avio_seek(pb, end_pos, SEEK_SET);
6044 78 return update_size(pb, pos);
6045 }
6046
6047 24 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
6048 int tracks, int ref_size)
6049 {
6050 int i, round, ret;
6051 AVIOContext *avio_buf;
6052 24 int total_size = 0;
6053
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 for (round = 0; round < 2; round++) {
6054 // First run one round to calculate the total size of all
6055 // sidx atoms.
6056 // This would be much simpler if we'd only write one sidx
6057 // atom, for the first track in the moof.
6058
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (round == 0) {
6059
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6060 return ret;
6061 } else {
6062 24 avio_buf = pb;
6063 }
6064
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 48 times.
126 for (i = 0; i < mov->nb_tracks; i++) {
6065 78 MOVTrack *track = &mov->tracks[i];
6066
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)
6067 continue;
6068 // When writing a sidx for the full file, entry is 0, but
6069 // we want to include all tracks. ref_size is 0 in this case,
6070 // since we read it from frag_info instead.
6071
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)
6072 continue;
6073 78 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
6074 total_size);
6075 }
6076
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (round == 0) {
6077 24 total_size = ffio_close_null_buf(avio_buf);
6078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (total_size < 0)
6079 return total_size;
6080 }
6081 }
6082 24 return 0;
6083 }
6084
6085 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
6086 {
6087 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
6088 MOVTrack *first_track;
6089 int flags = 24;
6090
6091 /* PRFT should be associated with at most one track. So, choosing only the
6092 * first track. */
6093 if (tracks > 0)
6094 return 0;
6095 first_track = &(mov->tracks[0]);
6096
6097 if (!first_track->entry) {
6098 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
6099 return 0;
6100 }
6101
6102 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
6103 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
6104 return 0;
6105 }
6106
6107 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
6108 if (first_track->cluster[0].prft.wallclock) {
6109 /* Round the NTP time to whole milliseconds. */
6110 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
6111 NTP_OFFSET_US);
6112 flags = first_track->cluster[0].prft.flags;
6113 } else
6114 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
6115 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
6116 pts_us = av_rescale_q(first_track->cluster[0].pts,
6117 first_track->st->time_base, AV_TIME_BASE_Q);
6118 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
6119 } else {
6120 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
6121 mov->write_prft);
6122 return 0;
6123 }
6124
6125 avio_wb32(pb, 0); // Size place holder
6126 ffio_wfourcc(pb, "prft"); // Type
6127 avio_w8(pb, 1); // Version
6128 avio_wb24(pb, flags); // Flags
6129 avio_wb32(pb, first_track->track_id); // reference track ID
6130 avio_wb64(pb, ntp_ts); // NTP time stamp
6131 avio_wb64(pb, first_track->cluster[0].pts); //media time
6132 return update_size(pb, pos);
6133 }
6134
6135 119 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
6136 int64_t mdat_size)
6137 {
6138 AVIOContext *avio_buf;
6139 int ret, moof_size;
6140
6141
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
119 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6142 return ret;
6143 119 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
6144 119 moof_size = ffio_close_null_buf(avio_buf);
6145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (moof_size < 0)
6146 return moof_size;
6147
6148
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 94 times.
119 if (mov->flags & FF_MOV_FLAG_DASH &&
6149
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)))
6150 24 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
6151
6152
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)
6153 mov_write_prft_tag(pb, mov, tracks);
6154
6155
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
6156
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 118 times.
119 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
6157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->ism_lookahead) {
6158
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)
6159 return ret;
6160
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
6161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
6162 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
6163 }
6164 }
6165
6166 119 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
6167 }
6168
6169 68 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
6170 {
6171 68 int64_t pos = avio_tell(pb);
6172 int i;
6173
6174 68 avio_wb32(pb, 0); /* size placeholder */
6175 68 ffio_wfourcc(pb, "tfra");
6176 68 avio_w8(pb, 1); /* version */
6177 68 avio_wb24(pb, 0);
6178
6179 68 avio_wb32(pb, track->track_id);
6180 68 avio_wb32(pb, 0); /* length of traf/trun/sample num */
6181 68 avio_wb32(pb, track->nb_frag_info);
6182
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 68 times.
240 for (i = 0; i < track->nb_frag_info; i++) {
6183 172 avio_wb64(pb, track->frag_info[i].time);
6184 172 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
6185 172 avio_w8(pb, 1); /* traf number */
6186 172 avio_w8(pb, 1); /* trun number */
6187 172 avio_w8(pb, 1); /* sample number */
6188 }
6189
6190 68 return update_size(pb, pos);
6191 }
6192
6193 39 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
6194 {
6195 AVIOContext *mfra_pb;
6196 int i, ret, sz;
6197 uint8_t *buf;
6198
6199 39 ret = avio_open_dyn_buf(&mfra_pb);
6200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0)
6201 return ret;
6202
6203 39 avio_wb32(mfra_pb, 0); /* size placeholder */
6204 39 ffio_wfourcc(mfra_pb, "mfra");
6205 /* An empty mfra atom is enough to indicate to the publishing point that
6206 * the stream has ended. */
6207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (mov->flags & FF_MOV_FLAG_ISML)
6208 goto done_mfra;
6209
6210
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 39 times.
111 for (i = 0; i < mov->nb_tracks; i++) {
6211 72 MOVTrack *track = &mov->tracks[i];
6212
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (track->nb_frag_info)
6213 68 mov_write_tfra_tag(mfra_pb, track);
6214 }
6215
6216 39 avio_wb32(mfra_pb, 16);
6217 39 ffio_wfourcc(mfra_pb, "mfro");
6218 39 avio_wb32(mfra_pb, 0); /* version + flags */
6219 39 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
6220
6221 39 done_mfra:
6222
6223 39 sz = update_size(mfra_pb, 0);
6224 39 ret = avio_get_dyn_buf(mfra_pb, &buf);
6225 39 avio_write(pb, buf, ret);
6226 39 ffio_free_dyn_buf(&mfra_pb);
6227
6228 39 return sz;
6229 }
6230
6231 205 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
6232 {
6233 205 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
6234
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 55 times.
205 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
6235
6236 205 mov->mdat_pos = avio_tell(pb);
6237 205 avio_wb32(pb, 0); /* size placeholder*/
6238 205 ffio_wfourcc(pb, "mdat");
6239 205 return 0;
6240 }
6241
6242 498 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
6243 int has_h264, int has_video, int write_minor)
6244 {
6245 498 MOVMuxContext *mov = s->priv_data;
6246 498 int minor = 0x200;
6247
6248
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (mov->major_brand && strlen(mov->major_brand) >= 4)
6249 ffio_wfourcc(pb, mov->major_brand);
6250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 else if (mov->mode == MODE_3GP) {
6251 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
6252 minor = has_h264 ? 0x100 : 0x200;
6253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 } else if (mov->mode == MODE_AVIF) {
6254 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
6255 minor = 0;
6256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 } else if (mov->mode & MODE_3G2) {
6257 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
6258 minor = has_h264 ? 0x20000 : 0x10000;
6259
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 496 times.
498 } else if (mov->mode == MODE_PSP)
6260 2 ffio_wfourcc(pb, "MSNV");
6261
4/4
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 106 times.
496 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
6262
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 66 times.
74 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6263 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
6264
4/4
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 142 times.
488 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6265 30 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
6266
3/4
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 142 times.
458 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6267 ffio_wfourcc(pb, "iso4");
6268
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 316 times.
458 else if (mov->mode == MODE_MP4)
6269 142 ffio_wfourcc(pb, "isom");
6270
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 314 times.
316 else if (mov->mode == MODE_IPOD)
6271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6272
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 304 times.
314 else if (mov->mode == MODE_ISM)
6273 10 ffio_wfourcc(pb, "isml");
6274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 304 times.
304 else if (mov->mode == MODE_F4V)
6275 ffio_wfourcc(pb, "f4v ");
6276 else
6277 304 ffio_wfourcc(pb, "qt ");
6278
6279
2/2
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 249 times.
498 if (write_minor)
6280 249 avio_wb32(pb, minor);
6281 498 }
6282
6283 249 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6284 {
6285 249 MOVMuxContext *mov = s->priv_data;
6286 249 int64_t pos = avio_tell(pb);
6287 249 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6288 249 int has_iamf = 0;
6289
6290 #if CONFIG_IAMFENC
6291
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 244 times.
249 for (int i = 0; i < s->nb_stream_groups; i++) {
6292 5 const AVStreamGroup *stg = s->stream_groups[i];
6293
6294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6295 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6296 5 has_iamf = 1;
6297 5 break;
6298 }
6299 }
6300 #endif
6301
2/2
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 249 times.
562 for (int i = 0; i < mov->nb_streams; i++) {
6302 313 AVStream *st = mov->tracks[i].st;
6303
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 311 times.
313 if (is_cover_image(st))
6304 2 continue;
6305
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 108 times.
311 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6306 203 has_video = 1;
6307
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 273 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6308 38 has_h264 = 1;
6309
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 309 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6310 2 has_av1 = 1;
6311
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 6 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6312
2/2
✓ Branch 0 taken 301 times.
✓ Branch 1 taken 4 times.
305 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6313
3/4
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 299 times.
602 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6314 301 av_packet_side_data_get(st->codecpar->coded_side_data,
6315 301 st->codecpar->nb_coded_side_data,
6316 AV_PKT_DATA_DOVI_CONF))
6317 12 has_dolby = 1;
6318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 311 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6319 has_id3 = 1;
6320 }
6321
6322 249 avio_wb32(pb, 0); /* size */
6323 249 ffio_wfourcc(pb, "ftyp");
6324
6325 // Write major brand
6326 249 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6327 // Write the major brand as the first compatible brand as well
6328 249 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6329
6330 // Write compatible brands, ensuring that we don't write the major brand as a
6331 // compatible brand a second time.
6332
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 244 times.
249 if (mov->mode == MODE_ISM) {
6333 5 ffio_wfourcc(pb, "piff");
6334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 } else if (mov->mode == MODE_AVIF) {
6335 const AVPixFmtDescriptor *pix_fmt_desc =
6336 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6337 const int depth = pix_fmt_desc->comp[0].depth;
6338 if (mov->is_animated_avif) {
6339 // For animated AVIF, major brand is "avis". Add "avif" as a
6340 // compatible brand.
6341 ffio_wfourcc(pb, "avif");
6342 ffio_wfourcc(pb, "msf1");
6343 ffio_wfourcc(pb, "iso8");
6344 }
6345 ffio_wfourcc(pb, "mif1");
6346 ffio_wfourcc(pb, "miaf");
6347 if (depth == 8 || depth == 10) {
6348 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6349 // computing that is based on chroma subsampling type. 420 chroma
6350 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6351 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6352 // 444 chroma subsampling.
6353 ffio_wfourcc(pb, "MA1A");
6354 } else {
6355 // 420 chroma subsampling.
6356 ffio_wfourcc(pb, "MA1B");
6357 }
6358 }
6359
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 152 times.
244 } else if (mov->mode != MODE_MOV) {
6360 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6361 // brand, if not already the major brand. This is compatible with users that
6362 // don't understand tfdt.
6363
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 2 times.
92 if (mov->mode == MODE_MP4) {
6364
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 88 times.
90 if (mov->flags & FF_MOV_FLAG_CMAF)
6365 2 ffio_wfourcc(pb, "cmfc");
6366
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 4 times.
90 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6367 33 ffio_wfourcc(pb, "iso6");
6368
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 88 times.
90 if (has_av1)
6369 2 ffio_wfourcc(pb, "av01");
6370
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 79 times.
90 if (has_dolby)
6371 11 ffio_wfourcc(pb, "dby1");
6372
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 85 times.
90 if (has_iamf)
6373 5 ffio_wfourcc(pb, "iamf");
6374 } else {
6375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6376 ffio_wfourcc(pb, "iso6");
6377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6378 ffio_wfourcc(pb, "iso5");
6379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6380 ffio_wfourcc(pb, "iso4");
6381 }
6382 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6383
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 17 times.
92 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6384 // write isom for mp4 only if it it's not the major brand already.
6385
4/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 71 times.
75 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6386 4 ffio_wfourcc(pb, "isom");
6387 75 ffio_wfourcc(pb, "iso2");
6388
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 51 times.
75 if (has_h264)
6389 24 ffio_wfourcc(pb, "avc1");
6390 }
6391 }
6392
6393
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 159 times.
249 if (mov->mode == MODE_MP4)
6394 90 ffio_wfourcc(pb, "mp41");
6395
6396
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 235 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
249 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6397 ffio_wfourcc(pb, "dash");
6398
6399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (has_id3)
6400 ffio_wfourcc(pb, "aid3");
6401
6402 249 return update_size(pb, pos);
6403 }
6404
6405 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6406 {
6407 1 AVStream *video_st = s->streams[0];
6408 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6409 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6410 1 int audio_rate = audio_par->sample_rate;
6411 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6412
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 :
6413 0;
6414 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6415 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6416
6417
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) {
6418 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6419 return AVERROR(EINVAL);
6420 }
6421
6422 1 avio_wb32(pb, 0x94); /* size */
6423 1 ffio_wfourcc(pb, "uuid");
6424 1 ffio_wfourcc(pb, "PROF");
6425
6426 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6427 1 avio_wb32(pb, 0xbb88695c);
6428 1 avio_wb32(pb, 0xfac9c740);
6429
6430 1 avio_wb32(pb, 0x0); /* ? */
6431 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6432
6433 1 avio_wb32(pb, 0x14); /* size */
6434 1 ffio_wfourcc(pb, "FPRF");
6435 1 avio_wb32(pb, 0x0); /* ? */
6436 1 avio_wb32(pb, 0x0); /* ? */
6437 1 avio_wb32(pb, 0x0); /* ? */
6438
6439 1 avio_wb32(pb, 0x2c); /* size */
6440 1 ffio_wfourcc(pb, "APRF"); /* audio */
6441 1 avio_wb32(pb, 0x0);
6442 1 avio_wb32(pb, 0x2); /* TrackID */
6443 1 ffio_wfourcc(pb, "mp4a");
6444 1 avio_wb32(pb, 0x20f);
6445 1 avio_wb32(pb, 0x0);
6446 1 avio_wb32(pb, audio_kbitrate);
6447 1 avio_wb32(pb, audio_kbitrate);
6448 1 avio_wb32(pb, audio_rate);
6449 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6450
6451 1 avio_wb32(pb, 0x34); /* size */
6452 1 ffio_wfourcc(pb, "VPRF"); /* video */
6453 1 avio_wb32(pb, 0x0);
6454 1 avio_wb32(pb, 0x1); /* TrackID */
6455
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6456 1 ffio_wfourcc(pb, "avc1");
6457 1 avio_wb16(pb, 0x014D);
6458 1 avio_wb16(pb, 0x0015);
6459 } else {
6460 ffio_wfourcc(pb, "mp4v");
6461 avio_wb16(pb, 0x0000);
6462 avio_wb16(pb, 0x0103);
6463 }
6464 1 avio_wb32(pb, 0x0);
6465 1 avio_wb32(pb, video_kbitrate);
6466 1 avio_wb32(pb, video_kbitrate);
6467 1 avio_wb32(pb, frame_rate);
6468 1 avio_wb32(pb, frame_rate);
6469 1 avio_wb16(pb, video_par->width);
6470 1 avio_wb16(pb, video_par->height);
6471 1 avio_wb32(pb, 0x010001); /* ? */
6472
6473 1 return 0;
6474 }
6475
6476 249 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6477 {
6478 249 MOVMuxContext *mov = s->priv_data;
6479 int i;
6480
6481 249 mov_write_ftyp_tag(pb,s);
6482
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 248 times.
249 if (mov->mode == MODE_PSP) {
6483 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6484
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6485 2 AVStream *st = mov->tracks[i].st;
6486
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6487 continue;
6488
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6489 1 video_streams_nb++;
6490
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6491 1 audio_streams_nb++;
6492 else
6493 other_streams_nb++;
6494 }
6495
6496
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) {
6497 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6498 return AVERROR(EINVAL);
6499 }
6500 1 return mov_write_uuidprof_tag(pb, s);
6501 }
6502 248 return 0;
6503 }
6504
6505 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6506 {
6507 8 uint32_t c = -1;
6508 8 int i, closed_gop = 0;
6509
6510
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6511 368 c = (c << 8) + pkt->data[i];
6512
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6513 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6514
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6515 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6516
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
6517 8 *flags = MOV_SYNC_SAMPLE;
6518 else
6519 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6520 8 break;
6521 }
6522 }
6523 8 return 0;
6524 }
6525
6526 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6527 {
6528 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6529 int seq = 0, entry = 0;
6530 int key = pkt->flags & AV_PKT_FLAG_KEY;
6531 start = find_next_marker(pkt->data, end);
6532 for (next = start; next < end; start = next) {
6533 next = find_next_marker(start + 4, end);
6534 switch (AV_RB32(start)) {
6535 case VC1_CODE_SEQHDR:
6536 seq = 1;
6537 break;
6538 case VC1_CODE_ENTRYPOINT:
6539 entry = 1;
6540 break;
6541 case VC1_CODE_SLICE:
6542 trk->vc1_info.slices = 1;
6543 break;
6544 }
6545 }
6546 if (!trk->entry && trk->vc1_info.first_packet_seen)
6547 trk->vc1_info.first_frag_written = 1;
6548 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6549 /* First packet in first fragment */
6550 trk->vc1_info.first_packet_seq = seq;
6551 trk->vc1_info.first_packet_entry = entry;
6552 trk->vc1_info.first_packet_seen = 1;
6553 } else if ((seq && !trk->vc1_info.packet_seq) ||
6554 (entry && !trk->vc1_info.packet_entry)) {
6555 int i;
6556 for (i = 0; i < trk->entry; i++)
6557 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6558 trk->has_keyframes = 0;
6559 if (seq)
6560 trk->vc1_info.packet_seq = 1;
6561 if (entry)
6562 trk->vc1_info.packet_entry = 1;
6563 if (!trk->vc1_info.first_frag_written) {
6564 /* First fragment */
6565 if ((!seq || trk->vc1_info.first_packet_seq) &&
6566 (!entry || trk->vc1_info.first_packet_entry)) {
6567 /* First packet had the same headers as this one, readd the
6568 * sync sample flag. */
6569 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6570 trk->has_keyframes = 1;
6571 }
6572 }
6573 }
6574 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6575 key = seq && entry;
6576 else if (trk->vc1_info.packet_seq)
6577 key = seq;
6578 else if (trk->vc1_info.packet_entry)
6579 key = entry;
6580 if (key) {
6581 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6582 trk->has_keyframes++;
6583 }
6584 }
6585
6586 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6587 {
6588 int length;
6589
6590 if (pkt->size < 8)
6591 return;
6592
6593 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6594 if (length < 8 || length > pkt->size)
6595 return;
6596
6597 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6598 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6599 trk->has_keyframes++;
6600 }
6601
6602 return;
6603 }
6604
6605 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6606 {
6607 89 MOVMuxContext *mov = s->priv_data;
6608 int ret, buf_size;
6609 uint8_t *buf;
6610 int i, offset;
6611
6612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if (!track->mdat_buf)
6613 return 0;
6614
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!mov->mdat_buf) {
6615
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6616 return ret;
6617 }
6618 89 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6619
6620 89 offset = avio_tell(mov->mdat_buf);
6621 89 avio_write(mov->mdat_buf, buf, buf_size);
6622 89 ffio_reset_dyn_buf(track->mdat_buf);
6623
6624
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 89 times.
177 for (i = track->entries_flushed; i < track->entry; i++)
6625 88 track->cluster[i].pos += offset;
6626 89 track->entries_flushed = track->entry;
6627 89 return 0;
6628 }
6629
6630 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6631 {
6632 28 MOVMuxContext *mov = s->priv_data;
6633 28 AVPacket *squashed_packet = mov->pkt;
6634 28 int ret = AVERROR_BUG;
6635
6636
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6637 28 case AV_CODEC_ID_TTML: {
6638 28 int had_packets = !!track->squashed_packet_queue.head;
6639
6640
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) {
6641 goto finish_squash;
6642 }
6643
6644 // We have generated a padding packet (no actual input packets in
6645 // queue) and its duration is zero. Skipping writing it.
6646
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) {
6647 goto finish_squash;
6648 }
6649
6650 28 track->end_reliable = 1;
6651 28 break;
6652 }
6653 default:
6654 ret = AVERROR(EINVAL);
6655 goto finish_squash;
6656 }
6657
6658 28 squashed_packet->stream_index = track->st->index;
6659
6660 28 ret = mov_write_single_packet(s, squashed_packet);
6661
6662 28 finish_squash:
6663 28 av_packet_unref(squashed_packet);
6664
6665 28 return ret;
6666 }
6667
6668 398 static int mov_write_squashed_packets(AVFormatContext *s)
6669 {
6670 398 MOVMuxContext *mov = s->priv_data;
6671
6672
2/2
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 398 times.
973 for (int i = 0; i < mov->nb_streams; i++) {
6673 575 MOVTrack *track = &mov->tracks[i];
6674 575 int ret = AVERROR_BUG;
6675
6676
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 545 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
575 if (track->squash_fragment_samples_to_one && !track->entry) {
6677
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6678 av_log(s, AV_LOG_ERROR,
6679 "Failed to write squashed packet for %s stream with "
6680 "index %d and track id %d. Error: %s\n",
6681 avcodec_get_name(track->st->codecpar->codec_id),
6682 track->st->index, track->track_id,
6683 av_err2str(ret));
6684 return ret;
6685 }
6686 }
6687 }
6688
6689 398 return 0;
6690 }
6691
6692 189 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6693 int64_t ref_pos)
6694 {
6695 int i;
6696
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 187 times.
189 if (!track->entry)
6697 2 return 0;
6698
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 179 times.
187 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6699
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6700 124 track->cluster[i].pos += ref_pos + track->data_offset;
6701
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6702 // First flush. Chunking for this fragment may already have been
6703 // done, either if we didn't use empty_moov, or if we did use
6704 // delay_moov. In either case, reset chunking here.
6705
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6706 63 track->cluster[i].chunkNum = 0;
6707 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6708 }
6709 }
6710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6711 8 track->entry_written + track->entry,
6712 sizeof(*track->cluster)))
6713 return AVERROR(ENOMEM);
6714 8 memcpy(&track->cluster_written[track->entry_written],
6715 8 track->cluster, track->entry * sizeof(*track->cluster));
6716 8 track->entry_written += track->entry;
6717 }
6718 187 track->entry = 0;
6719 187 track->entries_flushed = 0;
6720 187 track->end_reliable = 0;
6721 187 return 0;
6722 }
6723
6724 151 static int mov_flush_fragment(AVFormatContext *s, int force)
6725 {
6726 151 MOVMuxContext *mov = s->priv_data;
6727 151 int i, first_track = -1;
6728 151 int64_t mdat_size = 0, mdat_start = 0;
6729 int ret;
6730 151 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6731
6732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6733 return 0;
6734
6735 // Check if we have any tracks that require squashing.
6736 // In that case, we'll have to write the packet here.
6737
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 151 times.
151 if ((ret = mov_write_squashed_packets(s)) < 0)
6738 return ret;
6739
6740 // Try to fill in the duration of the last packet in each stream
6741 // from queued packets in the interleave queues. If the flushing
6742 // of fragments was triggered automatically by an AVPacket, we
6743 // already have reliable info for the end of that track, but other
6744 // tracks may need to be filled in.
6745
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 151 times.
417 for (i = 0; i < mov->nb_streams; i++) {
6746 266 MOVTrack *track = &mov->tracks[i];
6747
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 90 times.
266 if (!track->end_reliable) {
6748 176 const AVPacket *pkt = ff_interleaved_peek(s, i);
6749
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 170 times.
176 if (pkt) {
6750 int64_t offset, dts, pts;
6751 6 ff_get_muxer_ts_offset(s, i, &offset);
6752 6 pts = pkt->pts + offset;
6753 6 dts = pkt->dts + offset;
6754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6755 dts += track->dts_shift;
6756 6 track->track_duration = dts - track->start_dts;
6757
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6758 6 track->end_pts = pts;
6759 else
6760 track->end_pts = dts;
6761
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
6762 6 track->elst_end_pts = track->end_pts;
6763 }
6764 }
6765 }
6766
6767
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 151 times.
423 for (i = 0; i < mov->nb_tracks; i++) {
6768 272 MOVTrack *track = &mov->tracks[i];
6769
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 185 times.
272 if (track->entry <= 1)
6770 87 continue;
6771 // Sample durations are calculated as the diff of dts values,
6772 // but for the last sample in a fragment, we don't know the dts
6773 // of the first sample in the next fragment, so we have to rely
6774 // on what was set as duration in the AVPacket. Not all callers
6775 // set this though, so we might want to replace it with an
6776 // estimate if it currently is zero.
6777
2/2
✓ Branch 1 taken 183 times.
✓ Branch 2 taken 2 times.
185 if (get_cluster_duration(track, track->entry - 1) != 0)
6778 183 continue;
6779 // Use the duration (i.e. dts diff) of the second last sample for
6780 // the last one. This is a wild guess (and fatal if it turns out
6781 // to be too long), but probably the best we can do - having a zero
6782 // duration is bad as well.
6783 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6784 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6785
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6786 2 av_log(s, AV_LOG_WARNING,
6787 "Estimating the duration of the last packet in a "
6788 "fragment, consider setting the duration field in "
6789 "AVPacket instead.\n");
6790 2 mov->missing_duration_warned = 1;
6791 }
6792 }
6793
6794
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 122 times.
151 if (!mov->moov_written) {
6795 29 int64_t pos = avio_tell(s->pb);
6796 uint8_t *buf;
6797 int buf_size, moov_size;
6798
6799
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 22 times.
73 for (i = 0; i < mov->nb_tracks; i++)
6800
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))
6801 7 break;
6802 /* Don't write the initial moov unless all tracks have data */
6803
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)
6804 4 return 0;
6805
6806 25 moov_size = get_moov_size(s);
6807
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 25 times.
71 for (i = 0; i < mov->nb_tracks; i++)
6808 46 mov->tracks[i].data_offset = pos + moov_size + 8;
6809
6810 25 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6811
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6812
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6813 20 mov_write_identification(s->pb, s);
6814
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6815 return ret;
6816
6817
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6818
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6819 mov->reserved_header_pos = avio_tell(s->pb);
6820 20 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6821 20 mov->moov_written = 1;
6822 20 return 0;
6823 }
6824
6825
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (mov->mdat_buf) {
6826 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6827 4 avio_wb32(s->pb, buf_size + 8);
6828 4 ffio_wfourcc(s->pb, "mdat");
6829 4 avio_write(s->pb, buf, buf_size);
6830 4 ffio_reset_dyn_buf(mov->mdat_buf);
6831 }
6832
6833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6834 mov->reserved_header_pos = avio_tell(s->pb);
6835
6836 5 mov->moov_written = 1;
6837 5 mov->mdat_size = 0;
6838
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (i = 0; i < mov->nb_tracks; i++)
6839 10 mov_finish_fragment(mov, &mov->tracks[i], 0);
6840 5 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6841 5 return 0;
6842 }
6843
6844
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 120 times.
122 if (mov->frag_interleave) {
6845
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6846 4 MOVTrack *track = &mov->tracks[i];
6847 int ret;
6848
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6849 return ret;
6850 }
6851
6852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6853 return 0;
6854 2 mdat_size = avio_tell(mov->mdat_buf);
6855 }
6856
6857
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 122 times.
342 for (i = 0; i < mov->nb_tracks; i++) {
6858 220 MOVTrack *track = &mov->tracks[i];
6859
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)
6860 49 track->data_offset = 0;
6861 else
6862 171 track->data_offset = mdat_size;
6863
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 110 times.
220 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6864 110 has_video = 1;
6865
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 if (first_video_track) {
6866
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 16 times.
110 if (track->entry)
6867 94 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6868 110 first_video_track = 0;
6869 }
6870 }
6871
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 179 times.
220 if (!track->entry)
6872 41 continue;
6873
1/2
✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
179 if (track->mdat_buf)
6874 179 mdat_size += avio_tell(track->mdat_buf);
6875
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 77 times.
179 if (first_track < 0)
6876 102 first_track = i;
6877 }
6878
6879
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 102 times.
122 if (!mdat_size)
6880 20 return 0;
6881
6882
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
102 avio_write_marker(s->pb,
6883 102 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6884
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);
6885
6886
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 102 times.
289 for (i = first_track; i < mov->nb_tracks; i++) {
6887 187 MOVTrack *track = &mov->tracks[i];
6888 187 int buf_size, write_moof = 1, moof_tracks = -1;
6889 uint8_t *buf;
6890
6891
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 179 times.
187 if (!track->entry)
6892 8 continue;
6893
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 138 times.
179 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6894 41 mdat_size = avio_tell(track->mdat_buf);
6895 41 moof_tracks = i;
6896 } else {
6897 138 write_moof = i == first_track;
6898 }
6899
6900
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 60 times.
179 if (write_moof) {
6901 119 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6902
6903 119 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6904 119 mov->fragments++;
6905
6906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (track->cenc.aes_ctr)
6907 ff_mov_cenc_flush(&track->cenc);
6908
6909 119 avio_wb32(s->pb, mdat_size + 8);
6910 119 ffio_wfourcc(s->pb, "mdat");
6911 119 mdat_start = avio_tell(s->pb);
6912 }
6913
6914 179 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6915
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 3 times.
179 if (!mov->frag_interleave) {
6916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176 times.
176 if (!track->mdat_buf)
6917 continue;
6918 176 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6919 176 avio_write(s->pb, buf, buf_size);
6920 176 ffio_reset_dyn_buf(track->mdat_buf);
6921 } else {
6922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!mov->mdat_buf)
6923 continue;
6924 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6925 3 avio_write(s->pb, buf, buf_size);
6926 3 ffio_reset_dyn_buf(mov->mdat_buf);
6927 }
6928 }
6929
6930 102 mov->mdat_size = 0;
6931
6932 102 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6933 102 return 0;
6934 }
6935
6936 97 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6937 {
6938 97 MOVMuxContext *mov = s->priv_data;
6939 97 int had_moov = mov->moov_written;
6940 97 int ret = mov_flush_fragment(s, force);
6941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (ret < 0)
6942 return ret;
6943 // If using delay_moov, the first flush only wrote the moov,
6944 // not the actual moof+mdat pair, thus flush once again.
6945
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)
6946 10 ret = mov_flush_fragment(s, force);
6947 97 return ret;
6948 }
6949
6950 46163 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6951 {
6952 int64_t ref;
6953 uint64_t duration;
6954
6955
2/2
✓ Branch 0 taken 45367 times.
✓ Branch 1 taken 796 times.
46163 if (trk->entry) {
6956 45367 ref = trk->cluster[trk->entry - 1].dts;
6957
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 604 times.
796 } else if ( trk->start_dts != AV_NOPTS_VALUE
6958
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 8 times.
192 && !trk->frag_discont) {
6959 184 ref = trk->start_dts + trk->track_duration;
6960 } else
6961 612 ref = pkt->dts; // Skip tests for the first packet
6962
6963
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 42108 times.
46163 if (trk->dts_shift != AV_NOPTS_VALUE) {
6964 /* With negative CTS offsets we have set an offset to the DTS,
6965 * reverse this for the check. */
6966 4055 ref -= trk->dts_shift;
6967 }
6968
6969 46163 duration = pkt->dts - ref;
6970
2/4
✓ Branch 0 taken 46163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46163 times.
46163 if (pkt->dts < ref || duration >= INT_MAX) {
6971 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6972 duration, pkt->dts, pkt->stream_index);
6973
6974 pkt->dts = ref + 1;
6975 pkt->pts = AV_NOPTS_VALUE;
6976 }
6977
6978
2/4
✓ Branch 0 taken 46163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46163 times.
46163 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6979 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6980 return AVERROR(EINVAL);
6981 }
6982 46163 return 0;
6983 }
6984
6985 6 int ff_mov_set_fragment_end_hint(AVFormatContext *s, int stream_index,
6986 const AVPacket *pkt, AVRational src_time_base)
6987 {
6988 6 MOVMuxContext *mov = s->priv_data;
6989 AVStream *st;
6990 MOVTrack *track;
6991 int64_t offset, dts, pts, candidate_duration;
6992
6993
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) ||
6994
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 stream_index < 0 || stream_index >= s->nb_streams ||
6995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 pkt->dts == AV_NOPTS_VALUE)
6996 return 0;
6997
6998 6 st = s->streams[stream_index];
6999 6 track = st->priv_data;
7000
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)
7001 return 0;
7002
7003
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (ff_get_muxer_ts_offset(s, stream_index, &offset) < 0)
7004 return 0;
7005
7006 6 dts = av_rescale_q(pkt->dts, src_time_base, st->time_base) + offset;
7007 12 pts = pkt->pts == AV_NOPTS_VALUE
7008 ? AV_NOPTS_VALUE
7009
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 : av_rescale_q(pkt->pts, src_time_base, st->time_base) + offset;
7010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
7011 dts += track->dts_shift;
7012
7013 6 candidate_duration = dts - track->start_dts;
7014
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 ||
7015
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 candidate_duration < 0 || candidate_duration >= track->track_duration)
7016 6 return 0;
7017
7018 track->track_duration = candidate_duration;
7019 track->end_pts = pts != AV_NOPTS_VALUE ? pts : dts;
7020 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7021 track->elst_end_pts = track->end_pts;
7022 track->end_reliable = 1;
7023
7024 return 1;
7025 }
7026
7027 23100 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7028 {
7029 23100 MOVMuxContext *mov = s->priv_data;
7030 23100 AVIOContext *pb = s->pb;
7031 MOVTrack *trk;
7032 AVCodecParameters *par;
7033 AVProducerReferenceTime *prft;
7034 23100 unsigned int samples_in_chunk = 0;
7035 int64_t duration;
7036 23100 int size = pkt->size, ret = 0, offset = 0;
7037 size_t prft_size;
7038 23100 uint8_t *reformatted_data = NULL;
7039
7040
2/2
✓ Branch 0 taken 23054 times.
✓ Branch 1 taken 46 times.
23100 if (pkt->stream_index < s->nb_streams)
7041 23054 trk = s->streams[pkt->stream_index]->priv_data;
7042 else // Timecode or chapter
7043 46 trk = &mov->tracks[pkt->stream_index];
7044 23100 par = trk->par;
7045
7046 23100 ret = check_pkt(s, trk, pkt);
7047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 if (ret < 0)
7048 return ret;
7049
7050
2/2
✓ Branch 0 taken 22479 times.
✓ Branch 1 taken 621 times.
23100 if (pkt->pts != AV_NOPTS_VALUE &&
7051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22479 times.
22479 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
7052 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
7053 return AVERROR_PATCHWELCOME;
7054 }
7055
7056
3/4
✓ Branch 0 taken 16492 times.
✓ Branch 1 taken 6608 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16492 times.
23100 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
7057 int ret;
7058
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) {
7059
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) {
7060
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
7061
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
7062 return ret;
7063 }
7064 }
7065
7066
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 6297 times.
6370 if (!trk->mdat_buf) {
7067
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
73 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
7068 return ret;
7069 }
7070 6370 pb = trk->mdat_buf;
7071 } else {
7072
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
7073
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
7074 return ret;
7075 }
7076 238 pb = mov->mdat_buf;
7077 }
7078 }
7079
7080
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
7081 /* We must find out how many AMR blocks there are in one packet */
7082 static const uint16_t packed_size[16] =
7083 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
7084 int len = 0;
7085
7086 while (len < size && samples_in_chunk < 100) {
7087 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
7088 samples_in_chunk++;
7089 }
7090 if (samples_in_chunk > 1) {
7091 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
7092 return -1;
7093 }
7094
1/2
✓ Branch 0 taken 23100 times.
✗ Branch 1 not taken.
23100 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
7095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
7096 samples_in_chunk = trk->par->frame_size;
7097
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 21686 times.
23100 } else if (trk->sample_size)
7098 1414 samples_in_chunk = size / trk->sample_size;
7099 else
7100 21686 samples_in_chunk = 1;
7101
7102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 if (samples_in_chunk < 1) {
7103 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
7104 return AVERROR_PATCHWELCOME;
7105 }
7106
7107 /* copy extradata if it exists */
7108
3/4
✓ Branch 0 taken 7413 times.
✓ Branch 1 taken 15687 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7413 times.
23100 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
7109 !TAG_IS_AVCI(trk->tag) &&
7110 (par->codec_id != AV_CODEC_ID_DNXHD)) {
7111 trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
7112 if (!trk->extradata[0]) {
7113 ret = AVERROR(ENOMEM);
7114 goto err;
7115 }
7116 trk->extradata_size[0] = par->extradata_size;
7117 }
7118
7119
2/2
✓ Branch 0 taken 22985 times.
✓ Branch 1 taken 115 times.
23100 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
7120
2/2
✓ Branch 0 taken 20371 times.
✓ Branch 1 taken 2614 times.
22985 par->codec_id == AV_CODEC_ID_H264 ||
7121
2/2
✓ Branch 0 taken 19999 times.
✓ Branch 1 taken 372 times.
20371 par->codec_id == AV_CODEC_ID_HEVC ||
7122
2/2
✓ Branch 0 taken 19989 times.
✓ Branch 1 taken 10 times.
19999 par->codec_id == AV_CODEC_ID_VVC ||
7123
1/2
✓ Branch 0 taken 19989 times.
✗ Branch 1 not taken.
19989 par->codec_id == AV_CODEC_ID_VP9 ||
7124
2/2
✓ Branch 0 taken 19689 times.
✓ Branch 1 taken 300 times.
19989 par->codec_id == AV_CODEC_ID_EVC ||
7125
1/2
✓ Branch 0 taken 19689 times.
✗ Branch 1 not taken.
19689 par->codec_id == AV_CODEC_ID_LCEVC ||
7126
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19689 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3387 times.
23100 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
7127
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)) {
7128 /* copy frame to create needed atoms */
7129 24 trk->extradata_size[0] = size;
7130 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
7131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
7132 ret = AVERROR(ENOMEM);
7133 goto err;
7134 }
7135 24 memcpy(trk->extradata[0], pkt->data, size);
7136 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7137 }
7138
7139 23100 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
7140
4/6
✓ Branch 0 taken 23100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 23097 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
23100 if (pkt->size && sd && sd->size > 0) {
7141 int i;
7142
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < trk->stsd_count; i++) {
7143
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))
7144 1 break;
7145 }
7146
7147
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (i < trk->stsd_count)
7148 1 trk->last_stsd_index = i;
7149
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (trk->stsd_count <= INT_MAX - 1) {
7150 2 int new_count = trk->stsd_count + 1;
7151 2 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
7152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata)
7153 return AVERROR(ENOMEM);
7154 2 trk->extradata = extradata;
7155
7156 2 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
7157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata_size)
7158 return AVERROR(ENOMEM);
7159 2 trk->extradata_size = extradata_size;
7160
7161 2 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
7162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->extradata[trk->stsd_count])
7163 return AVERROR(ENOMEM);
7164
7165 2 trk->extradata_size[trk->stsd_count] = sd->size;
7166 2 trk->last_stsd_index = trk->stsd_count;
7167 2 trk->stsd_count = new_count;
7168 } else
7169 return AVERROR(ENOMEM);
7170 }
7171
7172
3/4
✓ Branch 0 taken 8186 times.
✓ Branch 1 taken 14914 times.
✓ Branch 2 taken 8186 times.
✗ Branch 3 not taken.
23100 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
7173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8186 times.
8186 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
7174 if (!trk->st->nb_frames) {
7175 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
7176 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
7177 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
7178 return -1;
7179 }
7180 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
7181 }
7182
3/4
✓ Branch 0 taken 2614 times.
✓ Branch 1 taken 20486 times.
✓ Branch 2 taken 2614 times.
✗ Branch 3 not taken.
23100 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
7183
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)) {
7184 /* from x264 or from bytestream H.264 */
7185 /* NAL reformatting needed */
7186
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) {
7187 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
7188 &size);
7189 if (ret < 0)
7190 return ret;
7191 avio_write(pb, reformatted_data, size);
7192 } else {
7193
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 498 times.
515 if (trk->cenc.aes_ctr) {
7194 17 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (size < 0) {
7196 ret = size;
7197 goto err;
7198 }
7199 } else {
7200 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7201 }
7202 }
7203
3/4
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 22213 times.
✓ Branch 2 taken 372 times.
✗ Branch 3 not taken.
22585 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7204
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)) {
7205 /* extradata is Annex B, assume the bitstream is too and convert it */
7206 355 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
7207
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) {
7208 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
7209 &size, filter_ps, NULL);
7210 if (ret < 0)
7211 return ret;
7212 avio_write(pb, reformatted_data, size);
7213 } else {
7214
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 354 times.
355 if (trk->cenc.aes_ctr) {
7215 1 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (size < 0) {
7217 ret = size;
7218 goto err;
7219 }
7220 } else {
7221 354 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
7222 }
7223 }
7224
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 22220 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
22230 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7225
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)) {
7226 /* extradata is Annex B, assume the bitstream is too and convert it */
7227
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) {
7228 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
7229 &size, 0, NULL);
7230 if (ret < 0)
7231 return ret;
7232 avio_write(pb, reformatted_data, size);
7233 } else {
7234 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
7235 }
7236
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22220 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22220 } else if (par->codec_id == AV_CODEC_ID_LCEVC && trk->extradata_size[trk->last_stsd_index] > 0 &&
7237 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1) {
7238 /* extradata is Annex B, assume the bitstream is too and convert it */
7239 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7240 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size);
7241 if (ret < 0)
7242 return ret;
7243 avio_write(pb, reformatted_data, size);
7244 } else {
7245 if (trk->cenc.aes_ctr) {
7246 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7247 if (size < 0) {
7248 ret = size;
7249 goto err;
7250 }
7251 } else {
7252 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7253 }
7254 }
7255
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 22192 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 24 times.
22220 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
7256
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) {
7257 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
7258 &size, &offset);
7259 if (ret < 0)
7260 return ret;
7261 avio_write(pb, reformatted_data, size);
7262 } else {
7263 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
7264
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]) {
7265 mov->avif_extent_length[pkt->stream_index] = size;
7266 }
7267 }
7268
7269
2/2
✓ Branch 0 taken 21593 times.
✓ Branch 1 taken 623 times.
22216 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
7270
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 20479 times.
21593 par->codec_id == AV_CODEC_ID_EAC3) {
7271 1737 size = handle_eac3(mov, pkt, trk);
7272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (size < 0)
7273 return size;
7274
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1736 times.
1737 else if (!size)
7275 1 goto end;
7276 1736 avio_write(pb, pkt->data, size);
7277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20479 times.
20479 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
7278 size = 8;
7279
7280 for (int i = 0; i < pkt->size; i += 3) {
7281 if (pkt->data[i] == 0xFC) {
7282 size += 2;
7283 }
7284 }
7285 avio_wb32(pb, size);
7286 ffio_wfourcc(pb, "cdat");
7287 for (int i = 0; i < pkt->size; i += 3) {
7288 if (pkt->data[i] == 0xFC) {
7289 avio_w8(pb, pkt->data[i + 1]);
7290 avio_w8(pb, pkt->data[i + 2]);
7291 }
7292 }
7293
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20476 times.
20479 } else if (par->codec_id == AV_CODEC_ID_APV) {
7294 3 ff_isom_parse_apvc(trk->apv, pkt, s);
7295 3 avio_wb32(s->pb, pkt->size);
7296 3 size += 4;
7297
7298 3 avio_write(s->pb, pkt->data, pkt->size);
7299 } else {
7300
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 20443 times.
20476 if (trk->cenc.aes_ctr) {
7301 33 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
7302 33 int extradata_size = trk->extradata_size[trk->last_stsd_index];
7303
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) {
7304 5 int nal_size_length = (extradata[4] & 0x3) + 1;
7305 5 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7306
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) {
7307 4 int nal_size_length = (extradata[21] & 0x3) + 1;
7308 4 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 } else if(par->codec_id == AV_CODEC_ID_VVC) {
7310 ret = AVERROR_PATCHWELCOME;
7311
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if(par->codec_id == AV_CODEC_ID_AV1) {
7312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 av_assert0(size == pkt->size);
7313 24 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
7314
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (ret > 0) {
7315 24 size = ret;
7316 24 ret = 0;
7317 }
7318 } else {
7319 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
7320 }
7321
7322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
7323 goto err;
7324 }
7325 } else {
7326 20443 avio_write(pb, pkt->data, size);
7327 }
7328 }
7329
7330
2/2
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 22786 times.
23099 if (trk->entry >= trk->cluster_capacity) {
7331 313 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
7332 313 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
7333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (!cluster) {
7334 ret = AVERROR(ENOMEM);
7335 goto err;
7336 }
7337 313 trk->cluster = cluster;
7338 313 trk->cluster_capacity = new_capacity;
7339 }
7340
7341 23099 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7342 23099 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7343 23099 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7344 23099 trk->cluster[trk->entry].chunkNum = 0;
7345 23099 trk->cluster[trk->entry].size = size;
7346 23099 trk->cluster[trk->entry].entries = samples_in_chunk;
7347 23099 trk->cluster[trk->entry].dts = pkt->dts;
7348 23099 trk->cluster[trk->entry].pts = pkt->pts;
7349
2/2
✓ Branch 0 taken 23071 times.
✓ Branch 1 taken 28 times.
23099 if (!trk->squash_fragment_samples_to_one &&
7350
4/4
✓ Branch 0 taken 398 times.
✓ Branch 1 taken 22673 times.
✓ Branch 2 taken 103 times.
✓ Branch 3 taken 295 times.
23071 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7351
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 4 times.
103 if (!trk->frag_discont) {
7352 /* First packet of a new fragment. We already wrote the duration
7353 * of the last packet of the previous fragment based on track_duration,
7354 * which might not exactly match our dts. Therefore adjust the dts
7355 * of this packet to be what the previous packets duration implies. */
7356 99 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7357 /* We also may have written the pts and the corresponding duration
7358 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7359 * the next fragment. This means the cts of the first sample must
7360 * be the same in all fragments, unless end_pts was updated by
7361 * the packet causing the fragment to be written. */
7362
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 83 times.
99 if ((mov->flags & FF_MOV_FLAG_DASH &&
7363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7364
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 61 times.
83 mov->mode == MODE_ISM)
7365 38 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7366 } else {
7367 /* New fragment, but discontinuous from previous fragments.
7368 * Pretend the duration sum of the earlier fragments is
7369 * pkt->dts - trk->start_dts. */
7370 4 trk->end_pts = trk->elst_end_pts = AV_NOPTS_VALUE;
7371 4 trk->frag_discont = 0;
7372 }
7373 }
7374
7375
6/6
✓ Branch 0 taken 426 times.
✓ Branch 1 taken 22673 times.
✓ Branch 2 taken 299 times.
✓ Branch 3 taken 127 times.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 262 times.
23099 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7376
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 15 times.
37 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7377 /* Not using edit lists and shifting the first track to start from zero.
7378 * If the other streams start from a later timestamp, we won't be able
7379 * to signal the difference in starting time without an edit list.
7380 * Thus move the timestamp for this first sample to 0, increasing
7381 * its duration instead. */
7382 22 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7383 }
7384
2/2
✓ Branch 0 taken 277 times.
✓ Branch 1 taken 22822 times.
23099 if (trk->start_dts == AV_NOPTS_VALUE) {
7385 277 trk->start_dts = pkt->dts;
7386
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 271 times.
277 if (trk->frag_discont) {
7387
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7388 /* Pretend the whole stream started at pts=0, with earlier fragments
7389 * already written. If the stream started at pts=0, the duration sum
7390 * of earlier fragments would have been pkt->pts. */
7391 4 trk->start_dts = pkt->dts - pkt->pts;
7392 } else {
7393 /* Pretend the whole stream started at dts=0, with earlier fragments
7394 * already written, with a duration summing up to pkt->dts. */
7395 2 trk->start_dts = 0;
7396 }
7397 6 trk->frag_discont = 0;
7398
4/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 219 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 50 times.
271 } else if (pkt->dts && mov->moov_written)
7399 2 av_log(s, AV_LOG_WARNING,
7400 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7401 "already has been written. Set the delay_moov flag to handle "
7402 "this case.\n",
7403 pkt->stream_index, pkt->dts);
7404 }
7405
7406 23099 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
7407
5/6
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 23059 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 1 times.
23138 if (sd && sd->size >= 10 && trk->par->frame_size) {
7408
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 },
7409 trk->st->time_base), pkt->duration);
7410
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (mov->use_editlist)
7411 39 pkt->duration = duration;
7412 39 duration -= av_rescale_q(AV_RL32(sd->data + 4), (AVRational){ 1, trk->par->sample_rate },
7413 39 trk->st->time_base);
7414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (duration < 0)
7415 return AVERROR_INVALIDDATA;
7416 } else
7417 23060 duration = pkt->duration;
7418
7419 23099 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7420 23099 trk->last_sample_is_subtitle_end = 0;
7421
7422
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 22478 times.
23099 if (pkt->pts == AV_NOPTS_VALUE) {
7423 621 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7424 621 pkt->pts = pkt->dts;
7425 }
7426
2/2
✓ Branch 0 taken 1401 times.
✓ Branch 1 taken 21698 times.
23099 if (pkt->dts != pkt->pts)
7427 1401 trk->flags |= MOV_TRACK_CTTS;
7428 23099 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7429 23099 trk->cluster[trk->entry].flags = 0;
7430
6/6
✓ Branch 0 taken 22800 times.
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 22732 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 63 times.
23099 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7431 304 trk->start_cts = pkt->pts - pkt->dts;
7432
2/2
✓ Branch 0 taken 303 times.
✓ Branch 1 taken 22796 times.
23099 if (trk->end_pts == AV_NOPTS_VALUE)
7433 303 trk->end_pts = trk->cluster[trk->entry].dts +
7434 303 trk->cluster[trk->entry].cts + duration;
7435 else
7436 22796 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7437 trk->cluster[trk->entry].cts +
7438 duration);
7439
2/2
✓ Branch 0 taken 23096 times.
✓ Branch 1 taken 3 times.
23099 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7440 23096 trk->elst_end_pts = trk->end_pts;
7441
7442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23099 times.
23099 if (par->codec_id == AV_CODEC_ID_VC1) {
7443 mov_parse_vc1_frame(pkt, trk);
7444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23099 times.
23099 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7445 mov_parse_truehd_frame(pkt, trk);
7446
2/2
✓ Branch 0 taken 17050 times.
✓ Branch 1 taken 6049 times.
23099 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7447
4/4
✓ Branch 0 taken 6267 times.
✓ Branch 1 taken 10783 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6258 times.
17050 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7448
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7449 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7451 trk->flags |= MOV_TRACK_STPS;
7452 } else {
7453 17042 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7454 }
7455
1/2
✓ Branch 0 taken 17050 times.
✗ Branch 1 not taken.
17050 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7456 17050 trk->has_keyframes++;
7457 }
7458
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 23092 times.
23099 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7459 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7460 7 trk->has_disposable++;
7461 }
7462
7463 23099 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7464
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23099 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23099 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7465 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7466 else
7467 23099 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7468
7469 23099 trk->entry++;
7470 23099 trk->sample_count += samples_in_chunk;
7471 23099 mov->mdat_size += size;
7472
7473
3/4
✓ Branch 0 taken 23017 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
23099 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7474 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7476 : NULL, size);
7477
7478 23100 end:
7479 23100 err:
7480
7481
1/2
✓ Branch 0 taken 23100 times.
✗ Branch 1 not taken.
23100 if (pkt->data != reformatted_data)
7482 23100 av_free(reformatted_data);
7483 23100 return ret;
7484 }
7485
7486 23063 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7487 {
7488 23063 MOVMuxContext *mov = s->priv_data;
7489 23063 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7490 23063 AVCodecParameters *par = trk->par;
7491 23063 int64_t frag_duration = 0;
7492 23063 int size = pkt->size;
7493
7494 23063 int ret = check_pkt(s, trk, pkt);
7495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23063 times.
23063 if (ret < 0)
7496 return ret;
7497
7498
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 23058 times.
23063 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7499
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7500 10 mov->tracks[i].frag_discont = 1;
7501 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7502 }
7503
7504
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 21051 times.
23063 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7505
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7506 15 trk->dts_shift = pkt->pts - pkt->dts;
7507 2012 pkt->dts += trk->dts_shift;
7508 }
7509
7510
1/2
✓ Branch 0 taken 23063 times.
✗ Branch 1 not taken.
23063 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7511
2/2
✓ Branch 0 taken 14875 times.
✓ Branch 1 taken 8188 times.
23063 trk->par->codec_id == AV_CODEC_ID_AAC ||
7512
2/2
✓ Branch 0 taken 14847 times.
✓ Branch 1 taken 28 times.
14875 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7513
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 14787 times.
14847 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7514 size_t side_size;
7515 8276 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7516 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7517
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])) {
7518 6 void *newextra = av_malloc(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7520 return AVERROR(ENOMEM);
7521 6 memset((uint8_t*)newextra + side_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7522 6 memcpy(newextra, side, side_size);
7523 6 av_free(trk->extradata[trk->last_stsd_index]);
7524 6 trk->extradata[trk->last_stsd_index] = newextra;
7525 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7526 }
7527 }
7528
7529
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23054 times.
23063 if (!pkt->size) {
7530
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) {
7531 4 trk->start_dts = pkt->dts;
7532
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7533 4 trk->start_cts = pkt->pts - pkt->dts;
7534 else
7535 trk->start_cts = 0;
7536 }
7537
7538 9 return 0; /* Discard 0 sized packets */
7539 }
7540
7541
4/4
✓ Branch 0 taken 22689 times.
✓ Branch 1 taken 365 times.
✓ Branch 2 taken 22665 times.
✓ Branch 3 taken 24 times.
23054 if (trk->entry && pkt->stream_index < mov->nb_streams)
7542 22665 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7543 22665 s->streams[pkt->stream_index]->time_base,
7544 22665 AV_TIME_BASE_Q);
7545
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 22793 times.
23054 if ((mov->max_fragment_duration &&
7546
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7547
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23050 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23050 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7548
2/2
✓ Branch 0 taken 4885 times.
✓ Branch 1 taken 18165 times.
23050 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7549
2/2
✓ Branch 0 taken 2311 times.
✓ Branch 1 taken 2574 times.
4885 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7550
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) ||
7551
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22999 times.
23000 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7552
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (frag_duration >= mov->min_fragment_duration) {
7553
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1 times.
55 if (trk->entry) {
7554 // Set the duration of this track to line up with the next
7555 // sample in this track. This avoids relying on AVPacket
7556 // duration, but only helps for this particular track, not
7557 // for the other ones that are flushed at the same time.
7558 //
7559 // If we have trk->entry == 0, no fragment will be written
7560 // for this track, and we can't adjust the track end here.
7561 54 trk->track_duration = pkt->dts - trk->start_dts;
7562
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (pkt->pts != AV_NOPTS_VALUE)
7563 54 trk->end_pts = pkt->pts;
7564 else
7565 trk->end_pts = pkt->dts;
7566
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7567 54 trk->elst_end_pts = trk->end_pts;
7568 54 trk->end_reliable = 1;
7569 }
7570 55 mov_auto_flush_fragment(s, 0);
7571 }
7572 }
7573
7574 23054 return ff_mov_write_packet(s, pkt);
7575 }
7576
7577 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7578 int stream_index,
7579 int64_t dts) {
7580 3 MOVMuxContext *mov = s->priv_data;
7581 3 AVPacket *end = mov->pkt;
7582 3 uint8_t data[2] = {0};
7583 int ret;
7584
7585 3 end->size = sizeof(data);
7586 3 end->data = data;
7587 3 end->pts = dts;
7588 3 end->dts = dts;
7589 3 end->duration = 0;
7590 3 end->stream_index = stream_index;
7591
7592 3 ret = mov_write_single_packet(s, end);
7593 3 av_packet_unref(end);
7594
7595 3 return ret;
7596 }
7597
7598 #if CONFIG_IAMFENC
7599 300 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7600 {
7601 uint8_t *data;
7602 int ret;
7603
7604
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 240 times.
300 if (pkt->stream_index == trk->first_iamf_idx) {
7605 60 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (ret < 0)
7607 return ret;
7608 }
7609
7610 300 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7611 300 s->streams[pkt->stream_index]->id, pkt);
7612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (ret < 0)
7613 return ret;
7614
7615
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (pkt->stream_index != trk->last_iamf_idx)
7616 240 return AVERROR(EAGAIN);
7617
7618 60 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7619 60 trk->iamf_buf = NULL;
7620
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
60 if (!ret) {
7621
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7622 // Either all or none of the packets for a single
7623 // IA Sample may be empty.
7624 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7625 "stream #%d\n", pkt->stream_index);
7626 ret = AVERROR_INVALIDDATA;
7627 }
7628 5 av_free(data);
7629 5 return ret;
7630 }
7631
7632 55 av_buffer_unref(&pkt->buf);
7633 55 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7634
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (!pkt->buf) {
7635 av_free(data);
7636 return AVERROR(ENOMEM);
7637 }
7638 55 pkt->data = data;
7639 55 pkt->size = ret;
7640 55 pkt->stream_index = trk->first_iamf_idx;
7641
7642 55 return avio_open_dyn_buf(&trk->iamf_buf);
7643 }
7644 #endif
7645
7646 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7647 {
7648 2 int64_t pos = avio_tell(pb);
7649 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7650 2 const char *value = "";
7651
7652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7653
7654 2 avio_write_marker(pb,
7655 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7656 AVIO_DATA_MARKER_BOUNDARY_POINT);
7657
7658 2 avio_wb32(pb, 0); /* size */
7659 2 ffio_wfourcc(pb, "emsg");
7660 2 avio_w8(pb, 1); /* version */
7661 2 avio_wb24(pb, 0);
7662 2 avio_wb32(pb, st->time_base.den); /* timescale */
7663 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7664 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7665 2 avio_wb32(pb, 0); /* id */
7666 /* null terminated UTF8 strings */
7667 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7668 2 avio_write(pb, value, strlen(value) + 1);
7669 2 avio_write(pb, pkt->data, pkt->size);
7670
7671 2 return update_size(pb, pos);
7672 }
7673
7674 23468 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7675 {
7676 23468 MOVMuxContext *mov = s->priv_data;
7677 MOVTrack *trk;
7678
7679
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 23424 times.
23468 if (!pkt) {
7680 44 mov_flush_fragment(s, 1);
7681 44 return 1;
7682 }
7683
7684
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23422 times.
23424 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7685 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7686 2 return 0;
7687 }
7688
7689 23422 trk = s->streams[pkt->stream_index]->priv_data;
7690
7691 #if CONFIG_IAMFENC
7692
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 23122 times.
23422 if (trk->iamf) {
7693 300 int ret = mov_build_iamf_packet(s, trk, pkt);
7694
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (ret < 0) {
7695
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if (ret == AVERROR(EAGAIN))
7696 240 return 0;
7697 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7698 "for stream #%d\n", trk->st->index);
7699 return ret;
7700 }
7701 }
7702 #endif
7703
7704
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 23180 times.
23182 if (is_cover_image(trk->st)) {
7705 int ret;
7706
7707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7708 if (trk->st->nb_frames == 1)
7709 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7710 " ignoring.\n", pkt->stream_index);
7711 return 0;
7712 }
7713
7714
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7715 return ret;
7716
7717 2 return 0;
7718 } else {
7719 int i;
7720
7721
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23171 times.
23180 if (!pkt->size)
7722 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7723
7724 /*
7725 * Subtitles require special handling.
7726 *
7727 * 1) For full compliance, every track must have a sample at
7728 * dts == 0, which is rarely true for subtitles. So, as soon
7729 * as we see any packet with dts > 0, write an empty subtitle
7730 * at dts == 0 for any subtitle track with no samples in it.
7731 *
7732 * 2) For each subtitle track, check if the current packet's
7733 * dts is past the duration of the last subtitle sample. If
7734 * so, we now need to write an end sample for that subtitle.
7735 *
7736 * This must be done conditionally to allow for subtitles that
7737 * immediately replace each other, in which case an end sample
7738 * is not needed, and is, in fact, actively harmful.
7739 *
7740 * 3) See mov_write_trailer for how the final end sample is
7741 * handled.
7742 */
7743
2/2
✓ Branch 0 taken 39165 times.
✓ Branch 1 taken 23171 times.
62336 for (i = 0; i < mov->nb_tracks; i++) {
7744 39165 MOVTrack *trk = &mov->tracks[i];
7745 int ret;
7746
7747
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39162 times.
39165 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7748
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7749
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)) {
7750 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7752 2 trk->last_sample_is_subtitle_end = 1;
7753 }
7754 }
7755
7756
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 23023 times.
23171 if (trk->squash_fragment_samples_to_one) {
7757 /*
7758 * If the track has to have its samples squashed into one sample,
7759 * we just take it into the track's queue.
7760 * This will then be utilized as the samples get written in either
7761 * mov_flush_fragment or when the mux is finalized in
7762 * mov_write_trailer.
7763 */
7764 148 int ret = AVERROR_BUG;
7765
7766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7767 av_log(s, AV_LOG_ERROR,
7768 "Packets without a valid presentation timestamp are "
7769 "not supported with packet squashing!\n");
7770 return AVERROR(EINVAL);
7771 }
7772
7773 /* The following will reset pkt and is only allowed to be used
7774 * because we return immediately. afterwards. */
7775
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = ff_packet_list_put(&trk->squashed_packet_queue,
7776 pkt, NULL, 0)) < 0) {
7777 return ret;
7778 }
7779
7780 148 return 0;
7781 }
7782
7783
7784
4/4
✓ Branch 0 taken 7939 times.
✓ Branch 1 taken 15084 times.
✓ Branch 2 taken 3917 times.
✓ Branch 3 taken 4022 times.
23023 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7785 3917 AVPacket *opkt = pkt;
7786 int reshuffle_ret, ret;
7787
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3892 times.
3917 if (trk->is_unaligned_qt_rgb) {
7788
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;
7789 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7790 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7791
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7792 return reshuffle_ret;
7793 } else
7794 3892 reshuffle_ret = 0;
7795
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) {
7796 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7798 goto fail;
7799
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7800 5 trk->pal_done++;
7801
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 3087 times.
3912 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7802
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7804 ret = av_packet_make_writable(pkt);
7805 if (ret < 0)
7806 goto fail;
7807 for (i = 0; i < pkt->size; i++)
7808 pkt->data[i] = ~pkt->data[i];
7809 }
7810
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3917 times.
3917 if (reshuffle_ret) {
7811 ret = mov_write_single_packet(s, pkt);
7812 fail:
7813 if (reshuffle_ret)
7814 av_packet_free(&pkt);
7815 return ret;
7816 }
7817 }
7818
7819 23023 return mov_write_single_packet(s, pkt);
7820 }
7821 }
7822
7823 // QuickTime chapters involve an additional text track with the chapter names
7824 // as samples, and a tref pointing from the other tracks to the chapter one.
7825 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7826 {
7827 static const uint8_t stub_header[] = {
7828 // TextSampleEntry
7829 0x00, 0x00, 0x00, 0x01, // displayFlags
7830 0x00, 0x00, // horizontal + vertical justification
7831 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7832 // BoxRecord
7833 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7834 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7835 // StyleRecord
7836 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7837 0x00, 0x01, // fontID
7838 0x00, 0x00, // fontStyleFlags + fontSize
7839 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7840 // FontTableBox
7841 0x00, 0x00, 0x00, 0x0D, // box size
7842 'f', 't', 'a', 'b', // box atom name
7843 0x00, 0x01, // entry count
7844 // FontRecord
7845 0x00, 0x01, // font ID
7846 0x00, // font name length
7847 };
7848 1 MOVMuxContext *mov = s->priv_data;
7849 1 MOVTrack *track = &mov->tracks[tracknum];
7850 1 AVPacket *pkt = mov->pkt;
7851 int i, len;
7852 int ret;
7853
7854 1 track->mode = mov->mode;
7855 1 track->tag = MKTAG('t','e','x','t');
7856 1 track->timescale = mov->movie_timescale;
7857 1 track->par = avcodec_parameters_alloc();
7858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7859 return AVERROR(ENOMEM);
7860 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7861 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7863 return ret;
7864 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7865
7866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7867 track->stsd_count = 1;
7868 track->extradata = av_calloc(1, sizeof(*track->extradata));
7869 track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7870 if (!track->extradata || !track->extradata_size)
7871 return AVERROR(ENOMEM);
7872 }
7873
7874 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7876 return AVERROR(ENOMEM);
7877 1 track->extradata_size[0] = sizeof(stub_header);
7878
7879 1 pkt->stream_index = tracknum;
7880 1 pkt->flags = AV_PKT_FLAG_KEY;
7881
7882
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7883 4 AVChapter *c = s->chapters[i];
7884 AVDictionaryEntry *t;
7885
7886 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7887 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7888 4 pkt->duration = end - pkt->dts;
7889
7890
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7891 static const char encd[12] = {
7892 0x00, 0x00, 0x00, 0x0C,
7893 'e', 'n', 'c', 'd',
7894 0x00, 0x00, 0x01, 0x00 };
7895 4 len = strlen(t->value);
7896 4 pkt->size = len + 2 + 12;
7897 4 pkt->data = av_malloc(pkt->size);
7898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7899 av_packet_unref(pkt);
7900 return AVERROR(ENOMEM);
7901 }
7902 4 AV_WB16(pkt->data, len);
7903 4 memcpy(pkt->data + 2, t->value, len);
7904 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7905 4 ff_mov_write_packet(s, pkt);
7906 4 av_freep(&pkt->data);
7907 }
7908 }
7909
7910 1 av_packet_unref(mov->pkt);
7911
7912 1 return 0;
7913 }
7914
7915
7916 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7917 {
7918 int ret;
7919
7920 /* compute the frame number */
7921 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7922 13 return ret;
7923 }
7924
7925 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7926 {
7927 6 MOVMuxContext *mov = s->priv_data;
7928 6 MOVTrack *track = &mov->tracks[index];
7929 6 AVStream *src_st = mov->tracks[src_index].st;
7930 uint8_t data[4];
7931 6 AVPacket *pkt = mov->pkt;
7932 6 AVRational rate = src_st->avg_frame_rate;
7933 int ret;
7934
7935 /* tmcd track based on video stream */
7936 6 track->mode = mov->mode;
7937 6 track->tag = MKTAG('t','m','c','d');
7938 6 track->src_track = av_malloc(sizeof(*track->src_track));
7939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->src_track)
7940 return AVERROR(ENOMEM);
7941 6 *track->src_track = src_index;
7942 6 track->nb_src_track = 1;
7943
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7944 3 track->timescale = tc.fps * 1000;
7945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (tc.rate.den == 1001)
7946 track->timescale = tc.rate.num;
7947 else
7948 3 track->timescale = tc.fps;
7949
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7950 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7951
7952 /* set st to src_st for metadata access*/
7953 6 track->st = src_st;
7954
7955 /* encode context: tmcd data stream */
7956 6 track->par = avcodec_parameters_alloc();
7957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7958 return AVERROR(ENOMEM);
7959 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7960 6 track->par->codec_tag = track->tag;
7961 6 track->st->avg_frame_rate = rate;
7962
7963 /* the tmcd track just contains one packet with the frame number */
7964 6 pkt->data = data;
7965 6 pkt->stream_index = index;
7966 6 pkt->flags = AV_PKT_FLAG_KEY;
7967 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){ 1, track->timescale });
7968 6 pkt->size = 4;
7969 6 AV_WB32(pkt->data, tc.start);
7970 6 ret = ff_mov_write_packet(s, pkt);
7971 6 av_packet_unref(pkt);
7972 6 return ret;
7973 }
7974
7975 /*
7976 * st->disposition controls the "enabled" flag in the tkhd tag.
7977 * QuickTime will not play a track if it is not enabled. So make sure
7978 * that one track of each type (audio, video, subtitle) is enabled.
7979 *
7980 * Subtitles are special. For audio and video, setting "enabled" also
7981 * makes the track "default" (i.e. it is rendered when played). For
7982 * subtitles, an "enabled" subtitle is not rendered by default, but
7983 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7984 * empty!
7985 */
7986 247 static void enable_tracks(AVFormatContext *s)
7987 {
7988 247 MOVMuxContext *mov = s->priv_data;
7989 int i;
7990 int enabled[AVMEDIA_TYPE_NB];
7991 int first[AVMEDIA_TYPE_NB];
7992
7993
2/2
✓ Branch 0 taken 1235 times.
✓ Branch 1 taken 247 times.
1482 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7994 1235 enabled[i] = 0;
7995 1235 first[i] = -1;
7996 }
7997
7998
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 247 times.
556 for (i = 0; i < mov->nb_streams; i++) {
7999 309 AVStream *st = mov->tracks[i].st;
8000
8001
1/2
✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
309 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
8002
3/4
✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 307 times.
618 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
8003 309 is_cover_image(st))
8004 2 continue;
8005
8006
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 15 times.
307 if (first[st->codecpar->codec_type] < 0)
8007 292 first[st->codecpar->codec_type] = i;
8008
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 271 times.
307 if (st->disposition & AV_DISPOSITION_DEFAULT) {
8009 36 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
8010 36 enabled[st->codecpar->codec_type]++;
8011 }
8012 }
8013
8014
2/2
✓ Branch 0 taken 1235 times.
✓ Branch 1 taken 247 times.
1482 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8015
2/2
✓ Branch 0 taken 741 times.
✓ Branch 1 taken 494 times.
1235 switch (i) {
8016 741 case AVMEDIA_TYPE_VIDEO:
8017 case AVMEDIA_TYPE_AUDIO:
8018 case AVMEDIA_TYPE_SUBTITLE:
8019
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 740 times.
741 if (enabled[i] > 1)
8020 1 mov->per_stream_grouping = 1;
8021
4/4
✓ Branch 0 taken 710 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 259 times.
✓ Branch 3 taken 451 times.
741 if (!enabled[i] && first[i] >= 0)
8022 259 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
8023 741 break;
8024 }
8025 }
8026 247 }
8027
8028 247 static void mov_free(AVFormatContext *s)
8029 {
8030 247 MOVMuxContext *mov = s->priv_data;
8031
8032
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (int i = 0; i < s->nb_streams; i++)
8033 330 s->streams[i]->priv_data = NULL;
8034
8035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (!mov->tracks)
8036 return;
8037
8038
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->chapter_track) {
8039 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
8040 }
8041
8042
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (int i = 0; i < mov->nb_tracks; i++) {
8043 318 MOVTrack *const track = &mov->tracks[i];
8044
8045
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 316 times.
318 if (track->tag == MKTAG('r','t','p',' '))
8046 2 ff_mov_close_hinting(track);
8047
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
316 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
8048 6 av_freep(&track->par);
8049 318 av_freep(&track->cluster);
8050 318 av_freep(&track->cluster_written);
8051 318 av_freep(&track->frag_info);
8052 318 av_packet_free(&track->cover_image);
8053
8054
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 308 times.
318 if (track->eac3_priv) {
8055 10 struct eac3_info *info = track->eac3_priv;
8056 10 av_packet_free(&info->pkt);
8057 10 av_freep(&track->eac3_priv);
8058 }
8059
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 318 times.
638 for (int j = 0; j < track->stsd_count; j++)
8060 320 av_freep(&track->extradata[j]);
8061 318 av_freep(&track->extradata);
8062 318 av_freep(&track->extradata_size);
8063
8064
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 318 times.
328 for (int i = 0; i < track->nb_tref_tags; i++)
8065 10 av_freep(&track->tref_tags[i].id);
8066 318 av_freep(&track->tref_tags);
8067 318 av_freep(&track->src_track);
8068
8069 318 ff_mov_cenc_free(&track->cenc);
8070 318 ffio_free_dyn_buf(&track->mdat_buf);
8071
8072 #if CONFIG_IAMFENC
8073 318 ffio_free_dyn_buf(&track->iamf_buf);
8074
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 313 times.
318 if (track->iamf)
8075 5 ff_iamf_uninit_context(track->iamf);
8076 318 av_freep(&track->iamf);
8077 #endif
8078 318 ff_isom_close_apvc(&track->apv);
8079
8080 318 ff_packet_list_free(&track->squashed_packet_queue);
8081 }
8082
8083 247 av_freep(&mov->tracks);
8084 247 ffio_free_dyn_buf(&mov->mdat_buf);
8085 }
8086
8087 static uint32_t rgb_to_yuv(uint32_t rgb)
8088 {
8089 uint8_t r, g, b;
8090 int y, cb, cr;
8091
8092 r = (rgb >> 16) & 0xFF;
8093 g = (rgb >> 8) & 0xFF;
8094 b = (rgb ) & 0xFF;
8095
8096 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
8097 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
8098 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
8099
8100 return (y << 16) | (cr << 8) | cb;
8101 }
8102
8103 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
8104 AVStream *st)
8105 {
8106 int i, width = 720, height = 480;
8107 int have_palette = 0, have_size = 0;
8108 uint32_t palette[16];
8109 char *cur = st->codecpar->extradata;
8110
8111 while (cur && *cur) {
8112 if (strncmp("palette:", cur, 8) == 0) {
8113 int i, count;
8114 count = sscanf(cur + 8,
8115 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8116 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8117 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8118 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
8119 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
8120 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
8121 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
8122 &palette[12], &palette[13], &palette[14], &palette[15]);
8123
8124 for (i = 0; i < count; i++) {
8125 palette[i] = rgb_to_yuv(palette[i]);
8126 }
8127 have_palette = 1;
8128 } else if (!strncmp("size:", cur, 5)) {
8129 sscanf(cur + 5, "%dx%d", &width, &height);
8130 have_size = 1;
8131 }
8132 if (have_palette && have_size)
8133 break;
8134 cur += strcspn(cur, "\n\r");
8135 cur += strspn(cur, "\n\r");
8136 }
8137 if (have_palette) {
8138 track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
8139 if (!track->extradata[track->last_stsd_index])
8140 return AVERROR(ENOMEM);
8141 for (i = 0; i < 16; i++) {
8142 AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
8143 }
8144 memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8145 track->extradata_size[track->last_stsd_index] = 16 * 4;
8146 }
8147 st->codecpar->width = width;
8148 st->codecpar->height = track->height = height;
8149
8150 return 0;
8151 }
8152
8153 #if CONFIG_IAMFENC
8154 247 static int mov_init_iamf_track(AVFormatContext *s)
8155 {
8156 247 MOVMuxContext *mov = s->priv_data;
8157 MOVTrack *track;
8158 IAMFContext *iamf;
8159 247 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
8160 247 int nb_audio_elements = 0, nb_mix_presentations = 0;
8161 int ret;
8162
8163
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 247 times.
257 for (int i = 0; i < s->nb_stream_groups; i++) {
8164 10 const AVStreamGroup *stg = s->stream_groups[i];
8165
8166
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8167 5 nb_audio_elements++;
8168
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
8169 5 nb_mix_presentations++;
8170 }
8171
8172
3/4
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 242 times.
✗ Branch 3 not taken.
247 if (!nb_audio_elements && !nb_mix_presentations)
8173 242 return 0;
8174
8175
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) {
8176 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
8177 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
8178 return AVERROR(EINVAL);
8179 }
8180
8181 5 iamf = av_mallocz(sizeof(*iamf));
8182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
8183 return AVERROR(ENOMEM);
8184
8185
8186
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8187 10 const AVStreamGroup *stg = s->stream_groups[i];
8188
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
8189 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
8190
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8191 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
8192 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
8193 }
8194
8195 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
8196 5 break;
8197 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
8198 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
8199 5 break;
8200 default:
8201 av_assert0(0);
8202 }
8203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
8204 ff_iamf_uninit_context(iamf);
8205 av_free(iamf);
8206 return ret;
8207 }
8208 }
8209
8210 5 track = &mov->tracks[first_iamf_idx];
8211 5 track->iamf = iamf;
8212 5 track->first_iamf_idx = first_iamf_idx;
8213 5 track->last_iamf_idx = last_iamf_idx;
8214 5 track->tag = MKTAG('i','a','m','f');
8215
8216
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8217 10 AVStreamGroup *stg = s->stream_groups[i];
8218
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8219 5 continue;
8220
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
8221 25 stg->streams[j]->priv_data = track;
8222 }
8223
8224 5 ret = avio_open_dyn_buf(&track->iamf_buf);
8225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
8226 return ret;
8227
8228 5 return 0;
8229 }
8230 #endif
8231
8232 247 static int mov_init(AVFormatContext *s)
8233 {
8234 247 MOVMuxContext *mov = s->priv_data;
8235 247 int has_iamf = 0;
8236 int i, ret;
8237
8238 247 mov->fc = s;
8239 247 mov->pkt = ffformatcontext(s)->pkt;
8240
8241 /* Default mode == MP4 */
8242 247 mov->mode = MODE_MP4;
8243
8244 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
8245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
8246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
8247
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 96 times.
247 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
8248
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
8249
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 94 times.
95 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
8250
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 89 times.
94 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
8251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
8252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
8253 #undef IS_MODE
8254
8255
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 227 times.
247 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
8256 20 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
8257
8258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->mode == MODE_AVIF)
8259 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
8260
8261 /* Set the FRAGMENT flag if any of the fragmentation methods are
8262 * enabled. */
8263
3/4
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 245 times.
✗ Branch 3 not taken.
247 if (mov->max_fragment_duration || mov->max_fragment_size ||
8264
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 211 times.
245 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
8265 FF_MOV_FLAG_FRAG_KEYFRAME |
8266 FF_MOV_FLAG_FRAG_CUSTOM |
8267 FF_MOV_FLAG_FRAG_EVERY_FRAME))
8268 36 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8269
8270
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
247 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
8271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
8272 av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
8273 return AVERROR(EINVAL);
8274 }
8275
8276 /* Set other implicit flags immediately */
8277
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
247 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8278 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8279
8280
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 242 times.
247 if (mov->mode == MODE_ISM)
8281 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
8282 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8283
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 233 times.
247 if (mov->flags & FF_MOV_FLAG_DASH)
8284 14 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8285 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
8286
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
247 if (mov->flags & FF_MOV_FLAG_CMAF)
8287 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8288 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8289
8290
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 3 times.
247 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
8291 34 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
8292 34 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
8293 }
8294
8295
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
247 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
8296 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
8297 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
8298 }
8299
8300
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 244 times.
247 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8301 3 mov->reserved_moov_size = -1;
8302 }
8303
8304
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 7 times.
247 if (mov->use_editlist < 0) {
8305 240 mov->use_editlist = 1;
8306
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 205 times.
240 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8307
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 18 times.
35 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8308 // If we can avoid needing an edit list by shifting the
8309 // tracks, prefer that over (trying to) write edit lists
8310 // in fragmented output.
8311
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
8312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
8313 16 mov->use_editlist = 0;
8314 }
8315 }
8316
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 210 times.
247 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8317
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)
8318 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
8319
8320
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
247 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist)
8321 mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8322
8323
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 1 times.
247 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
8324
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
21 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
8325 13 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
8326
8327 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
8328 * if the latter is set that's enough and omit_tfhd_offset doesn't
8329 * add anything extra on top of that. */
8330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
8331 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
8332 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
8333
8334
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->frag_interleave &&
8335
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)) {
8336 av_log(s, AV_LOG_ERROR,
8337 "Sample interleaving in fragments is mutually exclusive with "
8338 "omit_tfhd_offset and separate_moof\n");
8339 return AVERROR(EINVAL);
8340 }
8341
8342 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8343 * is enabled, we don't support non-seekable output at all. */
8344
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 218 times.
247 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
8345
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 ||
8346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 mov->mode == MODE_AVIF)) {
8347 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
8348 return AVERROR(EINVAL);
8349 }
8350
8351 /* AVIF output must have at most two video streams (one for YUV and one for
8352 * alpha). */
8353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->mode == MODE_AVIF) {
8354 if (s->nb_streams > 2) {
8355 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
8356 return AVERROR(EINVAL);
8357 }
8358 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
8359 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
8360 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
8361 return AVERROR(EINVAL);
8362 }
8363 if (s->nb_streams > 1) {
8364 const AVPixFmtDescriptor *pixdesc =
8365 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
8366 if (pixdesc->nb_components != 1) {
8367 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8368 return AVERROR(EINVAL);
8369 }
8370 }
8371 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
8372 }
8373
8374
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 247 times.
257 for (i = 0; i < s->nb_stream_groups; i++) {
8375 10 AVStreamGroup *stg = s->stream_groups[i];
8376
8377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_LCEVC) {
8378 if (stg->nb_streams != 2) {
8379 av_log(s, AV_LOG_ERROR, "Exactly two Streams are supported for Stream Groups of type LCEVC\n");
8380 return AVERROR(EINVAL);
8381 }
8382 AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8383 if (lcevc->el_index > 1)
8384 return AVERROR(EINVAL);
8385 AVStream *st = stg->streams[lcevc->el_index];
8386 if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) {
8387 av_log(s, AV_LOG_ERROR, "Stream #%u is not an LCEVC stream\n", lcevc->el_index);
8388 return AVERROR(EINVAL);
8389 }
8390 }
8391
8392 #if CONFIG_IAMFENC
8393
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8394 5 continue;
8395
8396
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8397 25 AVStream *st = stg->streams[j];
8398
8399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8400 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8401 "IAMF Audio Element\n", j);
8402 return AVERROR(EINVAL);
8403 }
8404 25 st->priv_data = st;
8405 }
8406 5 has_iamf = 1;
8407
8408
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
8409 5 mov->nb_tracks++;
8410 #endif
8411 }
8412
8413
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8414 330 AVStream *st = s->streams[i];
8415
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 305 times.
330 if (st->priv_data)
8416 25 continue;
8417 // Don't produce a track in the output file for timed ID3 streams.
8418
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 304 times.
305 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8419 // Leave priv_data set to NULL for these AVStreams that don't
8420 // have a corresponding track.
8421 1 continue;
8422 }
8423 304 st->priv_data = st;
8424 304 mov->nb_tracks++;
8425 }
8426
8427 247 mov->nb_streams = mov->nb_tracks;
8428
8429
4/4
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 240 times.
247 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8430 1 mov->chapter_track = mov->nb_tracks++;
8431
8432
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8433
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8434
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8435 2 mov->nb_tracks++;
8436 }
8437
8438
1/2
✓ Branch 0 taken 247 times.
✗ Branch 1 not taken.
247 if (mov->write_btrt < 0) {
8439 247 mov->write_btrt = mov->mode == MODE_MP4;
8440 }
8441
8442
6/6
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 151 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 89 times.
247 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8443
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8444 243 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8445 NULL, 0);
8446
8447 /* +1 tmcd track for each video stream with a timecode */
8448
2/2
✓ Branch 0 taken 323 times.
✓ Branch 1 taken 243 times.
566 for (i = 0; i < s->nb_streams; i++) {
8449 323 AVStream *st = s->streams[i];
8450 323 AVDictionaryEntry *t = global_tcr;
8451
4/4
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 6 times.
323 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8452
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 193 times.
194 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8453 AVTimecode tc;
8454 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8455
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8456 7 mov->nb_meta_tmcd++;
8457 }
8458 }
8459
8460 /* check if there is already a tmcd track to remux */
8461
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 236 times.
243 if (mov->nb_meta_tmcd) {
8462
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8463 13 AVStream *st = s->streams[i];
8464
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8465 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8466 "so timecode metadata are now ignored\n");
8467 3 mov->nb_meta_tmcd = 0;
8468 }
8469 }
8470 }
8471
8472 243 mov->nb_tracks += mov->nb_meta_tmcd;
8473 }
8474
8475 // Reserve an extra stream for chapters for the case where chapters
8476 // are written in the trailer
8477 247 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (!mov->tracks)
8479 return AVERROR(ENOMEM);
8480
8481
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (i = 0; i < mov->nb_tracks; i++) {
8482 318 MOVTrack *track = &mov->tracks[i];
8483
8484 318 track->stsd_count = 1;
8485 318 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8486 318 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8487
2/4
✓ Branch 0 taken 318 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 318 times.
318 if (!track->extradata || !track->extradata_size)
8488 return AVERROR(ENOMEM);
8489 }
8490
8491
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 242 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
247 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8492
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8493 5 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8494
8495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8496 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8497 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8498 return AVERROR(EINVAL);
8499 }
8500
8501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8502 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8503 mov->encryption_kid_len, CENC_KID_SIZE);
8504 return AVERROR(EINVAL);
8505 }
8506 } else {
8507 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8508 mov->encryption_scheme_str);
8509 return AVERROR(EINVAL);
8510 }
8511 }
8512
8513 #if CONFIG_IAMFENC
8514 247 ret = mov_init_iamf_track(s);
8515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (ret < 0)
8516 return ret;
8517 #endif
8518
8519
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8520 330 AVStream *st = s->streams[j];
8521
8522
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 304 times.
330 if (st != st->priv_data) {
8523
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8524 5 i += has_iamf--;
8525 26 continue;
8526 }
8527 304 st->priv_data = &mov->tracks[i++];
8528 }
8529
8530 247 AVRational movie_timescale = (AVRational) { 0, 1 };
8531
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8532 330 AVStream *st= s->streams[i];
8533 330 MOVTrack *track = st->priv_data;
8534
8535
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 329 times.
330 if (!track)
8536 1 continue;
8537
8538
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 20 times.
329 if (!track->st) {
8539 309 track->st = st;
8540 309 track->par = st->codecpar;
8541 }
8542
8543 329 movie_timescale = av_gcd_q(movie_timescale, st->time_base, INT_MAX, (AVRational){1,0});
8544 }
8545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (!movie_timescale.den)
8546 movie_timescale = MOV_TIMESCALE_Q;
8547
8548
1/2
✓ Branch 0 taken 247 times.
✗ Branch 1 not taken.
247 if (!mov->movie_timescale)
8549 247 mov->movie_timescale = FFMAX(movie_timescale.den, MOV_TIMESCALE);
8550
8551
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8552 330 AVStream *st= s->streams[i];
8553 330 MOVTrack *track = st->priv_data;
8554 330 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8555
8556
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 329 times.
330 if (!track)
8557 1 continue;
8558
8559
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 299 times.
329 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8560
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 171 times.
329 if (track->language < 0)
8561 158 track->language = 32767; // Unspecified Macintosh language code
8562 329 track->mode = mov->mode;
8563
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 25 times.
329 if (!track->tag)
8564 304 track->tag = mov_find_codec_tag(s, track);
8565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 329 times.
329 if (!track->tag) {
8566 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8567 "codec not currently supported in container\n",
8568 avcodec_get_name(st->codecpar->codec_id), i);
8569 return AVERROR(EINVAL);
8570 }
8571 /* If hinting of this track is enabled by a later hint track,
8572 * this is updated. */
8573 329 track->hint_track = -1;
8574 329 track->start_dts = AV_NOPTS_VALUE;
8575 329 track->start_cts = AV_NOPTS_VALUE;
8576 329 track->end_pts = AV_NOPTS_VALUE;
8577 329 track->dts_shift = AV_NOPTS_VALUE;
8578
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 126 times.
329 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8579
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') ||
8580
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') ||
8581
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')) {
8582 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8583 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8584 return AVERROR(EINVAL);
8585 }
8586 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8587 }
8588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 if (mov->video_track_timescale) {
8589 track->timescale = mov->video_track_timescale;
8590 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8591 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8592 } else {
8593 203 track->timescale = st->time_base.den;
8594
2/2
✓ Branch 0 taken 1594 times.
✓ Branch 1 taken 203 times.
1797 while(track->timescale < 10000)
8595 1594 track->timescale *= 2;
8596 }
8597
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) {
8598 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8599 return AVERROR(EINVAL);
8600 }
8601
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)
8602 5 av_log(s, AV_LOG_WARNING,
8603 "WARNING codec timebase is very high. If duration is too long,\n"
8604 "file may not be playable by quicktime. Specify a shorter timebase\n"
8605 "or choose different container.\n");
8606
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 67 times.
203 if (track->mode == MODE_MOV &&
8607
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 119 times.
136 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8608
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8609 1 enum AVPixelFormat pix_fmt = track->par->format;
8610
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)
8611 pix_fmt = AV_PIX_FMT_MONOWHITE;
8612 1 track->is_unaligned_qt_rgb =
8613 pix_fmt == AV_PIX_FMT_RGB24 ||
8614 pix_fmt == AV_PIX_FMT_BGR24 ||
8615 pix_fmt == AV_PIX_FMT_PAL8 ||
8616 pix_fmt == AV_PIX_FMT_GRAY8 ||
8617
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 ||
8618 pix_fmt == AV_PIX_FMT_MONOBLACK;
8619 }
8620
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) {
8621 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8622 return AVERROR(EINVAL);
8623
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 201 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8624
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) {
8625 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8626 return AVERROR(EINVAL);
8627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8628 /* altref frames handling is not defined in the spec as of version v1.0,
8629 * so just forbid muxing VP8 streams altogether until a new version does */
8630 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8631 return AVERROR_PATCHWELCOME;
8632
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 202 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8633 1 ret = ff_isom_init_apvc(&track->apv, s);
8634
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8635 return ret;
8636 }
8637
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 201 times.
203 if (is_cover_image(st)) {
8638 2 track->cover_image = av_packet_alloc();
8639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8640 return AVERROR(ENOMEM);
8641 }
8642
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 9 times.
126 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8643 117 track->timescale = st->codecpar->sample_rate;
8644
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 84 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 26 times.
117 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8645 7 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8646 7 track->audio_vbr = 1;
8647
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8648
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8650 if (!st->codecpar->block_align) {
8651 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8652 return AVERROR(EINVAL);
8653 }
8654 track->sample_size = st->codecpar->block_align;
8655
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 26 times.
110 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8656 84 track->audio_vbr = 1;
8657 }else{
8658 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8659 26 st->codecpar->ch_layout.nb_channels;
8660 }
8661
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8663 track->audio_vbr = 1;
8664 }
8665
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 31 times.
117 if (track->mode != MODE_MOV &&
8666
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
86 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8667 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8668 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8669 i, track->par->sample_rate);
8670 return AVERROR(EINVAL);
8671 } else {
8672 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8673 i, track->par->sample_rate);
8674 }
8675 }
8676
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 25 times.
117 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8677
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 track->par->codec_id == AV_CODEC_ID_OPUS) {
8679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8680 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8681 return AVERROR(EINVAL);
8682 }
8683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8684 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8685 av_log(s, AV_LOG_ERROR,
8686 "%s in MP4 support is experimental, add "
8687 "'-strict %d' if you want to use it.\n",
8688 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8689 return AVERROR_EXPERIMENTAL;
8690 }
8691 }
8692
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8693 5 track->timescale = st->time_base.den;
8694
8695
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8696 /* 14496-30 requires us to use a single sample per fragment
8697 for TTML, for which we define a per-track flag.
8698
8699 We set the flag in case we are receiving TTML paragraphs
8700 from the input, in other words in case we are not doing
8701 stream copy. */
8702 4 track->squash_fragment_samples_to_one =
8703 4 ff_is_ttml_stream_paragraph_based(track->par);
8704
8705
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8706
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8708 av_log(s, AV_LOG_ERROR,
8709 "ISMV style TTML support with the 'dfxp' tag in "
8710 "non-ISMV formats is not officially supported. Add "
8711 "'-strict unofficial' if you want to use it.\n");
8712 return AVERROR_EXPERIMENTAL;
8713 }
8714 }
8715
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8716 4 track->timescale = st->time_base.den;
8717
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->tag == MKTAG('t','m','c','d') &&
8718
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->extradata_size >= 8)
8719 3 track->timecode_flags = AV_RB32(st->codecpar->extradata + 4);
8720 } else {
8721 track->timescale = mov->movie_timescale;
8722 }
8723
1/2
✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
329 if (!track->height)
8724 329 track->height = st->codecpar->height;
8725 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8726 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8727 for video tracks, so if user-set, it isn't overwritten */
8728
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 322 times.
329 if (mov->mode == MODE_ISM &&
8729
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8730
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))) {
8731 7 track->timescale = 10000000;
8732 }
8733
8734 329 avpriv_set_pts_info(st, 64, 1, track->timescale);
8735
8736
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 324 times.
329 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8737 5 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8738
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 ||
8739
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),
8740
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret)
8742 return ret;
8743 }
8744 }
8745
8746
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 247 times.
257 for (i = 0; i < s->nb_stream_groups; i++) {
8747 10 AVStreamGroup *stg = s->stream_groups[i];
8748
8749
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 switch (stg->type) {
8750 case AV_STREAM_GROUP_PARAMS_LCEVC: {
8751 AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8752 AVStream *st = stg->streams[lcevc->el_index];
8753 MOVTrack *track = st->priv_data;
8754
8755 for (int j = 0; j < mov->nb_tracks; j++) {
8756 MOVTrack *trk = &mov->tracks[j];
8757
8758 if (trk->st == stg->streams[!lcevc->el_index]) {
8759 track->src_track = av_malloc(sizeof(*track->src_track));
8760 if (!track->src_track)
8761 return AVERROR(ENOMEM);
8762 *track->src_track = j;
8763 track->nb_src_track = 1;
8764 break;
8765 }
8766 }
8767
8768 track->par->width = lcevc->width;
8769 track->par->height = track->height = lcevc->height;
8770 break;
8771 }
8772 case AV_STREAM_GROUP_PARAMS_TREF: {
8773 const AVStreamGroupTREF *tref = stg->params.tref;
8774 MOVTrack *track;
8775
8776 if (tref->metadata_index >= stg->nb_streams)
8777 return AVERROR(EINVAL);
8778
8779 track = stg->streams[tref->metadata_index]->priv_data;
8780 for (int j = 0; j < stg->nb_streams; j++) {
8781 const AVStream *st2 = stg->streams[j];
8782 int index = -1;
8783
8784 if (j == tref->metadata_index)
8785 continue;
8786
8787 for (int k = 0; k < mov->nb_tracks; k++) {
8788 if (mov->tracks[k].st != st2)
8789 continue;
8790 index = k;
8791 break;
8792 }
8793 if (index < 0)
8794 return AVERROR(EINVAL);
8795
8796 int *tmp = av_realloc(track->src_track,
8797 (track->nb_src_track + 1) * sizeof(*track->src_track));
8798 if (!tmp)
8799 return AVERROR(ENOMEM);
8800 track->src_track = tmp;
8801 track->src_track[track->nb_src_track++] = index;
8802 }
8803 break;
8804 }
8805 10 default:
8806 10 break;
8807 }
8808 }
8809
8810 /* fill src_track for tmcd tracks not covered by stream groups or
8811 * created by this muxer, retaining the old behavior of src_track
8812 * being arbitrarily 0. */
8813
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8814 330 AVStream *st = s->streams[i];
8815 330 MOVTrack *track = st->priv_data;
8816
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 327 times.
330 if (st->codecpar->codec_tag != MKTAG('t','m','c','d') ||
8817
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 track->nb_src_track)
8818 327 continue;
8819
8820 3 track->src_track = av_malloc(sizeof(*track->src_track));
8821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!track->src_track)
8822 return AVERROR(ENOMEM);
8823 3 *track->src_track = 0;
8824 3 track->nb_src_track = 1;
8825 }
8826
8827 247 enable_tracks(s);
8828 247 return 0;
8829 }
8830
8831 247 static int mov_write_header(AVFormatContext *s)
8832 {
8833 247 AVIOContext *pb = s->pb;
8834 247 MOVMuxContext *mov = s->priv_data;
8835 247 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8836
8837
4/4
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 240 times.
247 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8838 1 nb_tracks++;
8839
8840
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8841 1 hint_track = nb_tracks;
8842
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8843
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8844 2 nb_tracks++;
8845 }
8846 }
8847
8848
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 241 times.
247 if (mov->nb_meta_tmcd)
8849 6 tmcd_track = nb_tracks;
8850
8851
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 247 times.
556 for (int i = 0; i < mov->nb_streams; i++) {
8852 309 MOVTrack *track = &mov->tracks[i];
8853 309 AVStream *st = track->st;
8854
8855 /* copy extradata if it exists */
8856
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 164 times.
309 if (st->codecpar->extradata_size) {
8857
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
145 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8858 mov_create_dvd_sub_decoder_specific_info(track, st);
8859
15/30
✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 145 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 145 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 145 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 145 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 145 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 145 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 145 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 145 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 145 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 145 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 145 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 145 times.
✗ Branch 29 not taken.
145 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8860 145 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8861 290 track->extradata[track->last_stsd_index] =
8862 145 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
145 if (!track->extradata[track->last_stsd_index]) {
8864 return AVERROR(ENOMEM);
8865 }
8866 145 memcpy(track->extradata[track->last_stsd_index],
8867 145 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8868 145 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8869 0, AV_INPUT_BUFFER_PADDING_SIZE);
8870 }
8871 }
8872
8873
4/4
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 14 times.
406 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8874 97 av_channel_layout_compare(&track->par->ch_layout,
8875 97 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8876 295 continue;
8877
8878
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
46 for (int j = 0; j < mov->nb_streams; j++) {
8879 32 AVStream *stj= mov->tracks[j].st;
8880 32 MOVTrack *trackj= &mov->tracks[j];
8881
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 18 times.
32 if (j == i)
8882 14 continue;
8883
8884
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
18 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8885
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 ||
8886 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8887 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8888 )
8889 4 track->mono_as_fc = -1;
8890
8891
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 &&
8892 11 av_channel_layout_compare(&trackj->par->ch_layout,
8893 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8894
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
8895 )
8896 7 track->mono_as_fc++;
8897
8898
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 ||
8899 11 av_channel_layout_compare(&trackj->par->ch_layout,
8900 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8901 trackj->language != track->language ||
8902 trackj->tag != track->tag
8903 )
8904 18 continue;
8905 track->multichannel_as_mono++;
8906 }
8907 }
8908
8909
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 227 times.
247 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8911
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 227 times.
227 if ((ret = mov_write_identification(pb, s)) < 0)
8912 return ret;
8913 }
8914
8915
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 244 times.
247 if (mov->reserved_moov_size){
8916 3 mov->reserved_header_pos = avio_tell(pb);
8917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8918 avio_skip(pb, mov->reserved_moov_size);
8919 }
8920
8921
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 205 times.
247 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8922 /* If no fragmentation options have been set, set a default. */
8923
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 35 times.
42 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8924 FF_MOV_FLAG_FRAG_CUSTOM |
8925 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8926
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)
8927 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8928
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8929 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8930
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8931 2 mov->mdat_pos = avio_tell(pb);
8932 // The free/wide header that later will be converted into an
8933 // mdat, covering the initial moov and all the fragments.
8934 2 avio_wb32(pb, 0);
8935
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8936 // Write an ftyp atom, hidden in a free/wide. This is neither
8937 // exposed while the file is written, as fragmented, nor when the
8938 // file is finalized into non-fragmented form. However, this allows
8939 // accessing a pristine, sequential ftyp+moov init segment, even
8940 // after the file is finalized. It also allows dumping the whole
8941 // contents of the mdat box, to get the fragmented form of the
8942 // file.
8943
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_identification(pb, s)) < 0)
8944 return ret;
8945 2 update_size(pb, mov->mdat_pos);
8946 }
8947
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 } else if (mov->mode != MODE_AVIF) {
8948
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 202 times.
205 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8949 3 mov->reserved_header_pos = avio_tell(pb);
8950 205 mov_write_mdat_tag(pb, mov);
8951 }
8952
8953 247 ff_parse_creation_time_metadata(s, &mov->time, 1);
8954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->time)
8955 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8956
8957
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->chapter_track)
8958
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8959 return ret;
8960
8961
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8962
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8963
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8964
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8965 return ret;
8966 2 hint_track++;
8967 }
8968 }
8969 }
8970
8971
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 241 times.
247 if (mov->nb_meta_tmcd) {
8972 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8973 "timecode", NULL, 0);
8974 /* Initialize the tmcd tracks */
8975
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8976 8 AVStream *st = mov->tracks[i].st;
8977 8 t = global_tcr;
8978
8979
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8980 AVTimecode tc;
8981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8982 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8983
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8984 continue;
8985
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8986 continue;
8987
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8988 return ret;
8989 6 tmcd_track++;
8990 }
8991 }
8992 }
8993
8994 247 avio_flush(pb);
8995
8996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->flags & FF_MOV_FLAG_ISML)
8997 mov_write_isml_manifest(pb, mov, s);
8998
8999
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 210 times.
247 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
9000
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 20 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
9001
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9002 return ret;
9003 17 mov->moov_written = 1;
9004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
9005 mov->reserved_header_pos = avio_tell(pb);
9006 }
9007
9008 247 return 0;
9009 }
9010
9011 31 static int get_moov_size(AVFormatContext *s)
9012 {
9013 int ret;
9014 AVIOContext *moov_buf;
9015 31 MOVMuxContext *mov = s->priv_data;
9016
9017
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
9018 return ret;
9019
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
9020 return ret;
9021 31 return ffio_close_null_buf(moov_buf);
9022 }
9023
9024 static int get_sidx_size(AVFormatContext *s)
9025 {
9026 int ret;
9027 AVIOContext *buf;
9028 MOVMuxContext *mov = s->priv_data;
9029
9030 if ((ret = ffio_open_null_buf(&buf)) < 0)
9031 return ret;
9032 mov_write_sidx_tags(buf, mov, -1, 0);
9033 return ffio_close_null_buf(buf);
9034 }
9035
9036 /*
9037 * This function gets the moov size if moved to the top of the file: the chunk
9038 * offset table can switch between stco (32-bit entries) to co64 (64-bit
9039 * entries) when the moov is moved to the beginning, so the size of the moov
9040 * would change. It also updates the chunk offset tables.
9041 */
9042 3 static int compute_moov_size(AVFormatContext *s)
9043 {
9044 int i, moov_size, moov_size2;
9045 3 MOVMuxContext *mov = s->priv_data;
9046
9047 3 moov_size = get_moov_size(s);
9048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9049 return moov_size;
9050
9051
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
9052 8 mov->tracks[i].data_offset += moov_size;
9053
9054 3 moov_size2 = get_moov_size(s);
9055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
9056 return moov_size2;
9057
9058 /* if the size changed, we just switched from stco to co64 and need to
9059 * update the offsets */
9060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
9061 for (i = 0; i < mov->nb_tracks; i++)
9062 mov->tracks[i].data_offset += moov_size2 - moov_size;
9063
9064 3 return moov_size2;
9065 }
9066
9067 static int compute_sidx_size(AVFormatContext *s)
9068 {
9069 int i, sidx_size;
9070 MOVMuxContext *mov = s->priv_data;
9071
9072 sidx_size = get_sidx_size(s);
9073 if (sidx_size < 0)
9074 return sidx_size;
9075
9076 for (i = 0; i < mov->nb_tracks; i++)
9077 mov->tracks[i].data_offset += sidx_size;
9078
9079 return sidx_size;
9080 }
9081
9082 3 static int shift_data(AVFormatContext *s)
9083 {
9084 int moov_size;
9085 3 MOVMuxContext *mov = s->priv_data;
9086
9087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
9088 moov_size = compute_sidx_size(s);
9089 else
9090 3 moov_size = compute_moov_size(s);
9091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9092 return moov_size;
9093
9094 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
9095 }
9096
9097 207 static void mov_write_mdat_size(AVFormatContext *s)
9098 {
9099 207 MOVMuxContext *mov = s->priv_data;
9100 207 AVIOContext *pb = s->pb;
9101
9102 /* Write size of mdat tag */
9103
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 if (mov->mdat_size + 8 <= UINT32_MAX) {
9104 207 avio_seek(pb, mov->mdat_pos, SEEK_SET);
9105 207 avio_wb32(pb, mov->mdat_size + 8);
9106
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 205 times.
207 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
9107 2 ffio_wfourcc(pb, "mdat"); // overwrite the original free/wide into a mdat
9108 } else {
9109 /* overwrite 'wide' placeholder atom */
9110 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
9111 /* special value: real atom size will be 64 bit value after
9112 * tag field */
9113 avio_wb32(pb, 1);
9114 ffio_wfourcc(pb, "mdat");
9115 avio_wb64(pb, mov->mdat_size + 16);
9116 }
9117 207 }
9118
9119 247 static int mov_write_trailer(AVFormatContext *s)
9120 {
9121 247 MOVMuxContext *mov = s->priv_data;
9122 247 AVIOContext *pb = s->pb;
9123 247 int res = 0;
9124 int i;
9125 int64_t moov_pos;
9126
9127 /*
9128 * Before actually writing the trailer, make sure that there are no
9129 * dangling subtitles, that need a terminating sample.
9130 */
9131
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (i = 0; i < mov->nb_tracks; i++) {
9132 318 MOVTrack *trk = &mov->tracks[i];
9133
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 317 times.
318 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
9134
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
9135 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
9136 1 trk->last_sample_is_subtitle_end = 1;
9137 }
9138 }
9139
9140 //Also check for a buffered EAC3 packet
9141
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (i = 0; i < mov->nb_tracks; i++) {
9142 318 MOVTrack *trk = &mov->tracks[i];
9143
2/2
✓ Branch 0 taken 314 times.
✓ Branch 1 taken 4 times.
318 if (trk->par->codec_id != AV_CODEC_ID_EAC3)
9144 314 continue;
9145 4 struct eac3_info *info = trk->eac3_priv;
9146
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)
9147 4 continue;
9148
9149 av_packet_move_ref(mov->pkt, info->pkt);
9150 info->eof = 1;
9151 res = mov_write_single_packet(s, mov->pkt);
9152 if (res < 0)
9153 return res;
9154
9155 av_packet_unref(mov->pkt);
9156 }
9157
9158 // Check if we have any tracks that require squashing.
9159 // In that case, we'll have to write the packet here.
9160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 247 times.
247 if ((res = mov_write_squashed_packets(s)) < 0)
9161 return res;
9162
9163 // If there were no chapters when the header was written, but there
9164 // are chapters now, write them in the trailer. This only works
9165 // when we are not doing fragments.
9166
4/4
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 204 times.
✓ Branch 3 taken 42 times.
247 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
9167
3/4
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
204 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
9168 mov->chapter_track = mov->nb_tracks++;
9169 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9170 return res;
9171 }
9172 }
9173
9174
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 205 times.
247 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
9175
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9176
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 205 times.
207 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9177 2 mov_auto_flush_fragment(s, 1);
9178 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
9179
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
9180 4 MOVTrack *track = &mov->tracks[i];
9181 4 track->data_offset = 0;
9182 4 av_free(track->cluster);
9183 4 track->cluster = track->cluster_written;
9184 4 track->entry = track->entry_written;
9185 4 track->cluster_written = NULL;
9186 4 track->entry_written = 0;
9187 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
9188 }
9189 // Clear the empty_moov flag, as we do want the moov to include
9190 // all the samples at this point.
9191 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
9192 }
9193
9194 207 moov_pos = avio_tell(pb);
9195
9196
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 2 times.
207 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
9197 205 mov_write_mdat_size(s);
9198
9199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
9200
9201
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 204 times.
207 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
9202 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
9203 3 res = shift_data(s);
9204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
9205 return res;
9206 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9207
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9208 return res;
9209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 } else if (mov->reserved_moov_size > 0) {
9210 int64_t size;
9211 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9212 return res;
9213 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
9214 if (size < 8){
9215 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
9216 return AVERROR(EINVAL);
9217 }
9218 avio_wb32(pb, size);
9219 ffio_wfourcc(pb, "free");
9220 ffio_fill(pb, 0, size - 8);
9221 avio_seek(pb, moov_pos, SEEK_SET);
9222 } else {
9223
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
204 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9224 return res;
9225 }
9226
9227
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 205 times.
207 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9228 // With hybrid fragmentation, only write the mdat size (hiding
9229 // the original moov and all the fragments within the mdat)
9230 // after we've successfully written the complete moov, to avoid
9231 // risk for an unreadable file if writing the final moov fails.
9232 2 mov_write_mdat_size(s);
9233 }
9234
9235 207 res = 0;
9236 } else {
9237 40 mov_auto_flush_fragment(s, 1);
9238
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 40 times.
113 for (i = 0; i < mov->nb_tracks; i++)
9239 73 mov->tracks[i].data_offset = 0;
9240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
9241 int64_t end;
9242 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
9243 res = shift_data(s);
9244 if (res < 0)
9245 return res;
9246 end = avio_tell(pb);
9247 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9248 mov_write_sidx_tags(pb, mov, -1, 0);
9249 avio_seek(pb, end, SEEK_SET);
9250 }
9251
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1 times.
40 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
9252 39 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
9253 39 res = mov_write_mfra_tag(pb, mov);
9254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (res < 0)
9255 return res;
9256 }
9257 }
9258
9259 247 return res;
9260 }
9261
9262 263 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
9263 const AVPacket *pkt)
9264 {
9265 263 int ret = 1;
9266
9267
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 246 times.
263 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
9268
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)
9269 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
9270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
9271 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
9272 }
9273
9274 263 return ret;
9275 }
9276
9277 #if CONFIG_AVIF_MUXER
9278 static int avif_write_trailer(AVFormatContext *s)
9279 {
9280 AVIOContext *pb = s->pb;
9281 MOVMuxContext *mov = s->priv_data;
9282 int64_t pos_backup, extent_offsets[2];
9283 uint8_t *buf;
9284 int buf_size, moov_size;
9285
9286 if (mov->moov_written) return 0;
9287
9288 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
9289 if (mov->is_animated_avif && mov->nb_streams > 1) {
9290 // For animated avif with alpha channel, we need to write a tref tag
9291 // with type "auxl".
9292 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[1], MKTAG('a', 'u', 'x', 'l'));
9293 if (!tag)
9294 return AVERROR(ENOMEM);
9295
9296 int ret = mov_add_tref_id(mov, tag, 1);
9297 if (ret < 0)
9298 return ret;
9299 }
9300 mov_write_identification(pb, s);
9301 mov_write_meta_tag(pb, mov, s);
9302
9303 moov_size = get_moov_size(s);
9304 for (int i = 0; i < mov->nb_tracks; i++)
9305 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
9306
9307 if (mov->is_animated_avif) {
9308 int ret;
9309 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9310 return ret;
9311 }
9312
9313 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
9314 avio_wb32(pb, buf_size + 8);
9315 ffio_wfourcc(pb, "mdat");
9316
9317 // The offset for the YUV planes is the starting position of mdat.
9318 extent_offsets[0] = avio_tell(pb);
9319 // The offset for alpha plane is YUV offset + YUV size.
9320 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
9321
9322 avio_write(pb, buf, buf_size);
9323
9324 // write extent offsets.
9325 pos_backup = avio_tell(pb);
9326 for (int i = 0; i < mov->nb_streams; i++) {
9327 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
9328 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
9329 return AVERROR_INVALIDDATA;
9330 }
9331 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
9332 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
9333 }
9334 avio_seek(pb, pos_backup, SEEK_SET);
9335
9336 return 0;
9337 }
9338 #endif
9339
9340 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
9341 static const AVCodecTag codec_3gp_tags[] = {
9342 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
9343 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9344 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9345 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9346 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
9347 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
9348 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9349 { AV_CODEC_ID_NONE, 0 },
9350 };
9351 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
9352 #endif
9353
9354 static const AVCodecTag codec_mp4_tags[] = {
9355 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
9356 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
9357 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
9358 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
9359 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
9360 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
9361 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
9362 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
9363 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
9364 { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') },
9365 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
9366 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
9367 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
9368 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
9369 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
9370 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
9371 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
9372 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
9373 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
9374 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
9375 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
9376 { AV_CODEC_ID_AV1, MKTAG('d', 'a', 'v', '1') },
9377 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
9378 { AV_CODEC_ID_APPLE_APAC, MKTAG('a', 'p', 'a', 'c') },
9379 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
9380 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
9381 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
9382 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
9383 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
9384 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
9385 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
9386 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
9387 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
9388 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
9389 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
9390 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
9391 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
9392 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
9393 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
9394 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
9395 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
9396 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
9397 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
9398 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
9399
9400 /* ISO/IEC 23003-5 integer formats */
9401 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
9402 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
9403 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
9404 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
9405 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
9406 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
9407 /* ISO/IEC 23003-5 floating-point formats */
9408 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
9409 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
9410 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
9411 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
9412
9413 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
9414
9415 { AV_CODEC_ID_NONE, 0 },
9416 };
9417 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
9418 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
9419 #endif
9420
9421 static const AVCodecTag codec_ism_tags[] = {
9422 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
9423 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
9424 { AV_CODEC_ID_NONE , 0 },
9425 };
9426
9427 static const AVCodecTag codec_ipod_tags[] = {
9428 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9429 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9430 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9431 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
9432 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
9433 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9434 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
9435 { AV_CODEC_ID_NONE, 0 },
9436 };
9437
9438 static const AVCodecTag codec_f4v_tags[] = {
9439 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
9440 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9441 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9442 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
9443 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
9444 { AV_CODEC_ID_NONE, 0 },
9445 };
9446
9447 #if CONFIG_AVIF_MUXER
9448
9449 static const AVOption avif_options[] = {
9450 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
9451 { "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 },
9452 { NULL },
9453 };
9454 static const AVCodecTag codec_avif_tags[] = {
9455 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
9456 { AV_CODEC_ID_NONE, 0 },
9457 };
9458 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
9459
9460 static const AVClass mov_avif_muxer_class = {
9461 .class_name = "avif muxer",
9462 .item_name = av_default_item_name,
9463 .option = avif_options,
9464 .version = LIBAVUTIL_VERSION_INT,
9465 };
9466 #endif
9467
9468 #if CONFIG_MOV_MUXER
9469 const FFOutputFormat ff_mov_muxer = {
9470 .p.name = "mov",
9471 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
9472 .p.extensions = "mov",
9473 .priv_data_size = sizeof(MOVMuxContext),
9474 .p.audio_codec = AV_CODEC_ID_AAC,
9475 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9476 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9477 .init = mov_init,
9478 .write_header = mov_write_header,
9479 .write_packet = mov_write_packet,
9480 .write_trailer = mov_write_trailer,
9481 .deinit = mov_free,
9482 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9483 .p.codec_tag = (const AVCodecTag* const []){
9484 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
9485 },
9486 .check_bitstream = mov_check_bitstream,
9487 .p.priv_class = &mov_isobmff_muxer_class,
9488 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9489 };
9490 #endif
9491 #if CONFIG_TGP_MUXER
9492 const FFOutputFormat ff_tgp_muxer = {
9493 .p.name = "3gp",
9494 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9495 .p.extensions = "3gp",
9496 .priv_data_size = sizeof(MOVMuxContext),
9497 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9498 .p.video_codec = AV_CODEC_ID_H263,
9499 .init = mov_init,
9500 .write_header = mov_write_header,
9501 .write_packet = mov_write_packet,
9502 .write_trailer = mov_write_trailer,
9503 .deinit = mov_free,
9504 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9505 .p.codec_tag = codec_3gp_tags_list,
9506 .check_bitstream = mov_check_bitstream,
9507 .p.priv_class = &mov_isobmff_muxer_class,
9508 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9509 };
9510 #endif
9511 #if CONFIG_MP4_MUXER
9512 const FFOutputFormat ff_mp4_muxer = {
9513 .p.name = "mp4",
9514 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9515 .p.mime_type = "video/mp4",
9516 .p.extensions = "mp4",
9517 .priv_data_size = sizeof(MOVMuxContext),
9518 .p.audio_codec = AV_CODEC_ID_AAC,
9519 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9520 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9521 .init = mov_init,
9522 .write_header = mov_write_header,
9523 .write_packet = mov_write_packet,
9524 .write_trailer = mov_write_trailer,
9525 .deinit = mov_free,
9526 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9527 .p.codec_tag = mp4_codec_tags_list,
9528 .check_bitstream = mov_check_bitstream,
9529 .p.priv_class = &mov_isobmff_muxer_class,
9530 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9531 };
9532 #endif
9533 #if CONFIG_PSP_MUXER
9534 const FFOutputFormat ff_psp_muxer = {
9535 .p.name = "psp",
9536 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9537 .p.extensions = "mp4,psp",
9538 .priv_data_size = sizeof(MOVMuxContext),
9539 .p.audio_codec = AV_CODEC_ID_AAC,
9540 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9541 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9542 .init = mov_init,
9543 .write_header = mov_write_header,
9544 .write_packet = mov_write_packet,
9545 .write_trailer = mov_write_trailer,
9546 .deinit = mov_free,
9547 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9548 .p.codec_tag = mp4_codec_tags_list,
9549 .check_bitstream = mov_check_bitstream,
9550 .p.priv_class = &mov_isobmff_muxer_class,
9551 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9552 };
9553 #endif
9554 #if CONFIG_TG2_MUXER
9555 const FFOutputFormat ff_tg2_muxer = {
9556 .p.name = "3g2",
9557 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9558 .p.extensions = "3g2",
9559 .priv_data_size = sizeof(MOVMuxContext),
9560 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9561 .p.video_codec = AV_CODEC_ID_H263,
9562 .init = mov_init,
9563 .write_header = mov_write_header,
9564 .write_packet = mov_write_packet,
9565 .write_trailer = mov_write_trailer,
9566 .deinit = mov_free,
9567 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9568 .p.codec_tag = codec_3gp_tags_list,
9569 .check_bitstream = mov_check_bitstream,
9570 .p.priv_class = &mov_isobmff_muxer_class,
9571 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9572 };
9573 #endif
9574 #if CONFIG_IPOD_MUXER
9575 const FFOutputFormat ff_ipod_muxer = {
9576 .p.name = "ipod",
9577 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9578 .p.mime_type = "video/mp4",
9579 .p.extensions = "m4v,m4a,m4b",
9580 .priv_data_size = sizeof(MOVMuxContext),
9581 .p.audio_codec = AV_CODEC_ID_AAC,
9582 .p.video_codec = AV_CODEC_ID_H264,
9583 .init = mov_init,
9584 .write_header = mov_write_header,
9585 .write_packet = mov_write_packet,
9586 .write_trailer = mov_write_trailer,
9587 .deinit = mov_free,
9588 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9589 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9590 .check_bitstream = mov_check_bitstream,
9591 .p.priv_class = &mov_isobmff_muxer_class,
9592 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9593 };
9594 #endif
9595 #if CONFIG_ISMV_MUXER
9596 const FFOutputFormat ff_ismv_muxer = {
9597 .p.name = "ismv",
9598 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9599 .p.mime_type = "video/mp4",
9600 .p.extensions = "ismv,isma",
9601 .priv_data_size = sizeof(MOVMuxContext),
9602 .p.audio_codec = AV_CODEC_ID_AAC,
9603 .p.video_codec = AV_CODEC_ID_H264,
9604 .init = mov_init,
9605 .write_header = mov_write_header,
9606 .write_packet = mov_write_packet,
9607 .write_trailer = mov_write_trailer,
9608 .deinit = mov_free,
9609 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9610 .p.codec_tag = (const AVCodecTag* const []){
9611 codec_mp4_tags, codec_ism_tags, 0 },
9612 .check_bitstream = mov_check_bitstream,
9613 .p.priv_class = &mov_isobmff_muxer_class,
9614 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9615 };
9616 #endif
9617 #if CONFIG_F4V_MUXER
9618 const FFOutputFormat ff_f4v_muxer = {
9619 .p.name = "f4v",
9620 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9621 .p.mime_type = "application/f4v",
9622 .p.extensions = "f4v",
9623 .priv_data_size = sizeof(MOVMuxContext),
9624 .p.audio_codec = AV_CODEC_ID_AAC,
9625 .p.video_codec = AV_CODEC_ID_H264,
9626 .init = mov_init,
9627 .write_header = mov_write_header,
9628 .write_packet = mov_write_packet,
9629 .write_trailer = mov_write_trailer,
9630 .deinit = mov_free,
9631 .p.flags = AVFMT_GLOBALHEADER,
9632 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9633 .check_bitstream = mov_check_bitstream,
9634 .p.priv_class = &mov_isobmff_muxer_class,
9635 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9636 };
9637 #endif
9638 #if CONFIG_AVIF_MUXER
9639 const FFOutputFormat ff_avif_muxer = {
9640 .p.name = "avif",
9641 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9642 .p.mime_type = "image/avif",
9643 .p.extensions = "avif",
9644 .priv_data_size = sizeof(MOVMuxContext),
9645 .p.video_codec = AV_CODEC_ID_AV1,
9646 .init = mov_init,
9647 .write_header = mov_write_header,
9648 .write_packet = mov_write_packet,
9649 .write_trailer = avif_write_trailer,
9650 .deinit = mov_free,
9651 .p.flags = AVFMT_GLOBALHEADER,
9652 .p.codec_tag = codec_avif_tags_list,
9653 .p.priv_class = &mov_avif_muxer_class,
9654 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9655 };
9656 #endif
9657