FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2026-04-24 19:58:39
Exec Total Coverage
Lines: 3750 5602 66.9%
Functions: 178 233 76.4%
Branches: 2207 3845 57.4%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "apv.h"
41 #include "lcevc.h"
42 #include "libavcodec/ac3_parser_internal.h"
43 #include "libavcodec/dnxhddata.h"
44 #include "libavcodec/flac.h"
45 #include "libavcodec/get_bits.h"
46
47 #include "libavcodec/internal.h"
48 #include "libavcodec/put_bits.h"
49 #include "libavcodec/vc1_common.h"
50 #include "libavcodec/raw.h"
51 #include "internal.h"
52 #include "libavutil/avstring.h"
53 #include "libavutil/channel_layout.h"
54 #include "libavutil/csp.h"
55 #include "libavutil/intfloat.h"
56 #include "libavutil/mathematics.h"
57 #include "libavutil/libm.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 = MOV_TIMESCALE}, 1, 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 29 static int utf8len(const uint8_t *b)
144 {
145 29 int len = 0;
146 int val;
147
2/2
✓ Branch 0 taken 552 times.
✓ Branch 1 taken 29 times.
581 while (*b) {
148
3/8
✓ Branch 0 taken 552 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 552 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 552 times.
552 GET_UTF8(val, *b++, return -1;)
149 552 len++;
150 }
151 29 return len;
152 }
153
154 //FIXME support 64 bit variant with wide placeholders
155 6657 static int64_t update_size(AVIOContext *pb, int64_t pos)
156 {
157 6657 int64_t curpos = avio_tell(pb);
158 6657 avio_seek(pb, pos, SEEK_SET);
159 6657 avio_wb32(pb, curpos - pos); /* rewrite size */
160 6657 avio_seek(pb, curpos, SEEK_SET);
161
162 6657 return curpos - pos;
163 }
164
165 350 static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version)
166 {
167 350 int64_t curpos = avio_tell(pb);
168 350 avio_seek(pb, pos, SEEK_SET);
169 350 avio_wb32(pb, curpos - pos); /* rewrite size */
170 350 avio_skip(pb, 4);
171 350 avio_w8(pb, version); /* rewrite version */
172 350 avio_seek(pb, curpos, SEEK_SET);
173
174 350 return curpos - pos;
175 }
176
177 350 static int co64_required(const MOVTrack *track)
178 {
179
3/4
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 252 times.
350 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
180 return 1;
181 350 return 0;
182 }
183
184 20960 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 20960 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 20948 times.
20960 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 350 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
202 {
203 int i;
204 350 int mode64 = co64_required(track); // use 32 bit size variant if possible
205 350 int64_t pos = avio_tell(pb);
206 350 avio_wb32(pb, 0); /* size */
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (mode64)
208 ffio_wfourcc(pb, "co64");
209 else
210 350 ffio_wfourcc(pb, "stco");
211 350 avio_wb32(pb, 0); /* version & flags */
212 350 avio_wb32(pb, track->chunkCount); /* entry count */
213
2/2
✓ Branch 0 taken 13918 times.
✓ Branch 1 taken 350 times.
14268 for (i = 0; i < track->entry; i++) {
214
2/2
✓ Branch 0 taken 10778 times.
✓ Branch 1 taken 3140 times.
13918 if (!track->cluster[i].chunkNum)
215 10778 continue;
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3140 times.
3140 if (mode64 == 1)
217 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
218 else
219 3140 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
220 }
221 350 return update_size(pb, pos);
222 }
223
224 /* Sample size atom */
225 350 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
226 {
227 350 int equalChunks = 1;
228 350 int i, j, entries = 0, tst = -1, oldtst = -1;
229
230 350 int64_t pos = avio_tell(pb);
231 350 avio_wb32(pb, 0); /* size */
232 350 ffio_wfourcc(pb, "stsz");
233 350 avio_wb32(pb, 0); /* version & flags */
234
235
2/2
✓ Branch 0 taken 13918 times.
✓ Branch 1 taken 350 times.
14268 for (i = 0; i < track->entry; i++) {
236 13918 tst = track->cluster[i].size / track->cluster[i].entries;
237
4/4
✓ Branch 0 taken 13666 times.
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 8943 times.
✓ Branch 3 taken 4723 times.
13918 if (oldtst != -1 && tst != oldtst)
238 8943 equalChunks = 0;
239 13918 oldtst = tst;
240 13918 entries += track->cluster[i].entries;
241 }
242
4/4
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 98 times.
463 if (equalChunks && track->entry) {
243
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
244 113 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
245 113 avio_wb32(pb, sSize); // sample size
246 113 avio_wb32(pb, entries); // sample count
247 } else {
248 237 avio_wb32(pb, 0); // sample size
249 237 avio_wb32(pb, entries); // sample count
250
2/2
✓ Branch 0 taken 10109 times.
✓ Branch 1 taken 237 times.
10346 for (i = 0; i < track->entry; i++) {
251
2/2
✓ Branch 0 taken 10109 times.
✓ Branch 1 taken 10109 times.
20218 for (j = 0; j < track->cluster[i].entries; j++) {
252 10109 avio_wb32(pb, track->cluster[i].size /
253 10109 track->cluster[i].entries);
254 }
255 }
256 }
257 350 return update_size(pb, pos);
258 }
259
260 /* Sample to chunk atom */
261 350 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
262 {
263 350 int index = 0, oldidx = -1, oldval = -1, i;
264 int64_t entryPos, curpos;
265
266 350 int64_t pos = avio_tell(pb);
267 350 avio_wb32(pb, 0); /* size */
268 350 ffio_wfourcc(pb, "stsc");
269 350 avio_wb32(pb, 0); // version & flags
270 350 entryPos = avio_tell(pb);
271 350 avio_wb32(pb, track->chunkCount); // entry count
272
2/2
✓ Branch 0 taken 13918 times.
✓ Branch 1 taken 350 times.
14268 for (i = 0; i < track->entry; i++) {
273
2/2
✓ Branch 0 taken 2313 times.
✓ Branch 1 taken 11605 times.
13918 if ((oldval != track->cluster[i].samples_in_chunk ||
274
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2312 times.
✓ Branch 2 taken 828 times.
✓ Branch 3 taken 10778 times.
13918 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
275 828 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
276 828 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
277 828 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
278 828 oldval = track->cluster[i].samples_in_chunk;
279 828 oldidx = track->cluster[i].stsd_index;
280 828 index++;
281 }
282 }
283 350 curpos = avio_tell(pb);
284 350 avio_seek(pb, entryPos, SEEK_SET);
285 350 avio_wb32(pb, index); // rewrite size
286 350 avio_seek(pb, curpos, SEEK_SET);
287
288 350 return update_size(pb, pos);
289 }
290
291 /* Sync sample atom */
292 62 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
293 {
294 int64_t curpos, entryPos;
295 62 int i, index = 0;
296 62 int64_t pos = avio_tell(pb);
297 62 avio_wb32(pb, 0); // size
298
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
299 62 avio_wb32(pb, 0); // version & flags
300 62 entryPos = avio_tell(pb);
301 62 avio_wb32(pb, track->entry); // entry count
302
2/2
✓ Branch 0 taken 3423 times.
✓ Branch 1 taken 62 times.
3485 for (i = 0; i < track->entry; i++) {
303
2/2
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 3205 times.
3423 if (track->cluster[i].flags & flag) {
304 218 avio_wb32(pb, i + 1);
305 218 index++;
306 }
307 }
308 62 curpos = avio_tell(pb);
309 62 avio_seek(pb, entryPos, SEEK_SET);
310 62 avio_wb32(pb, index); // rewrite size
311 62 avio_seek(pb, curpos, SEEK_SET);
312 62 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 return ret;
357
358 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
359 5 ffio_write_leb(pb, dyn_size);
360 5 avio_write(pb, dyn_buf, dyn_size);
361 5 av_free(dyn_buf);
362
363 5 return update_size(pb, pos);
364 }
365 #endif
366
367 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
368 {
369 avio_wb32(pb, 0x11); /* size */
370 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
371 else ffio_wfourcc(pb, "damr");
372 ffio_wfourcc(pb, "FFMP");
373 avio_w8(pb, 0); /* decoder version */
374
375 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
376 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
377 avio_w8(pb, 0x01); /* Frames per sample */
378 return 0x11;
379 }
380
381 struct eac3_info {
382 AVPacket *pkt;
383 uint8_t ec3_done;
384 uint8_t num_blocks;
385
386 /* Layout of the EC3SpecificBox */
387 /* maximum bitrate */
388 uint16_t data_rate;
389 int8_t ac3_bit_rate_code;
390 /* number of independent substreams */
391 uint8_t num_ind_sub;
392 struct {
393 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
394 uint8_t fscod;
395 /* bit stream identification 5 bits */
396 uint8_t bsid;
397 /* one bit reserved */
398 /* audio service mixing (not supported yet) 1 bit */
399 /* bit stream mode 3 bits */
400 uint8_t bsmod;
401 /* audio coding mode 3 bits */
402 uint8_t acmod;
403 /* sub woofer on 1 bit */
404 uint8_t lfeon;
405 /* 3 bits reserved */
406 /* number of dependent substreams associated with this substream 4 bits */
407 uint8_t num_dep_sub;
408 /* channel locations of the dependent substream(s), if any, 9 bits */
409 uint16_t chan_loc;
410 /* if there is no dependent substream, then one bit reserved instead */
411 } substream[1]; /* TODO: support 8 independent substreams */
412 /* indicates the decoding complexity, 8 bits */
413 uint8_t complexity_index_type_a;
414 };
415
416 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
417 {
418 5 struct eac3_info *info = track->eac3_priv;
419 PutBitContext pbc;
420 uint8_t buf[3];
421
422
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!info || !info->ec3_done) {
423 av_log(s, AV_LOG_ERROR,
424 "Cannot write moov atom before AC3 packets."
425 " Set the delay_moov flag to fix this.\n");
426 return AVERROR(EINVAL);
427 }
428
429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
430 av_log(s, AV_LOG_ERROR,
431 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
432 "ISOBMFF specification in ETSI TS 102 366!\n",
433 info->substream[0].bsid);
434 return AVERROR(EINVAL);
435 }
436
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
438 av_log(s, AV_LOG_ERROR,
439 "No valid AC3 bit rate code for data rate of %d!\n",
440 info->data_rate);
441 return AVERROR(EINVAL);
442 }
443
444 5 avio_wb32(pb, 11);
445 5 ffio_wfourcc(pb, "dac3");
446
447 5 init_put_bits(&pbc, buf, sizeof(buf));
448 5 put_bits(&pbc, 2, info->substream[0].fscod);
449 5 put_bits(&pbc, 5, info->substream[0].bsid);
450 5 put_bits(&pbc, 3, info->substream[0].bsmod);
451 5 put_bits(&pbc, 3, info->substream[0].acmod);
452 5 put_bits(&pbc, 1, info->substream[0].lfeon);
453 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
454 5 put_bits(&pbc, 5, 0); // reserved
455
456 5 flush_put_bits(&pbc);
457 5 avio_write(pb, buf, sizeof(buf));
458
459 5 return 11;
460 }
461
462 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
463 {
464 1039 AC3HeaderInfo *hdr = NULL;
465 struct eac3_info *info;
466 int num_blocks, ret;
467
468
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
469
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
470 return AVERROR(ENOMEM);
471
472 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
473 }
474 1039 info = track->eac3_priv;
475
476
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
1039 if (!info->pkt && !(info->pkt = av_packet_alloc()))
477 return AVERROR(ENOMEM);
478
479
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1038 times.
1039 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
481 goto end;
482
483 /* drop the packets until we see a good one */
484
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
485 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
486 1 ret = 0;
487 } else
488 ret = AVERROR_INVALIDDATA;
489 1 goto end;
490 }
491
492 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
493 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
494 hdr->ac3_bit_rate_code);
495 1038 info->complexity_index_type_a = hdr->complexity_index_type_a;
496
497 1038 num_blocks = hdr->num_blocks;
498
499
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
500 /* AC-3 substream must be the first one */
501
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
502 ret = AVERROR(EINVAL);
503 goto end;
504 }
505
506 /* this should always be the case, given that our AC-3 parser
507 * concatenates dependent frames to their independent parent */
508
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
509
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
510 /* substream ids must be incremental */
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
512 ret = AVERROR(EINVAL);
513 goto end;
514 }
515
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
517 //info->num_ind_sub++;
518 avpriv_request_sample(mov->fc, "Multiple independent substreams");
519 ret = AVERROR_PATCHWELCOME;
520 goto end;
521
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
522
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 hdr->substreamid == 0 && info->substream[0].bsid) {
523 1 info->ec3_done = 1;
524 1 goto concatenate;
525 }
526 } else {
527 if (hdr->substreamid != 0) {
528 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
529 ret = AVERROR_PATCHWELCOME;
530 goto end;
531 }
532 }
533
534 /* fill the info needed for the "dec3" atom */
535 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
536 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
537 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
538 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
539 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
540
541
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
542 // with AC-3 we only require the information of a single packet,
543 // so we can finish as soon as the basic values of the bit stream
544 // have been set to the track's informational structure.
545 4 info->ec3_done = 1;
546 4 goto concatenate;
547 }
548
549 /* Parse dependent substream(s), if any */
550
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
551 int cumul_size = hdr->frame_size;
552 int parent = hdr->substreamid;
553
554 while (cumul_size != pkt->size) {
555 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
556 if (ret < 0)
557 goto end;
558 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
559 ret = AVERROR(EINVAL);
560 goto end;
561 }
562 info->substream[parent].num_dep_sub++;
563 ret /= 8;
564
565 /* get the dependent stream channel map, if exists */
566 if (hdr->channel_map_present)
567 info->substream[parent].chan_loc |= (hdr->channel_map >> 5) & 0x1f;
568 else
569 info->substream[parent].chan_loc |= hdr->channel_mode;
570 cumul_size += hdr->frame_size;
571 }
572 }
573 }
574
575 1033 concatenate:
576
2/4
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
1038 if (!info->num_blocks && num_blocks == 6) {
577 1038 ret = pkt->size;
578 1038 goto end;
579 }
580 else if (info->num_blocks + num_blocks > 6) {
581 ret = AVERROR_INVALIDDATA;
582 goto end;
583 }
584
585 if (!info->num_blocks) {
586 ret = av_packet_ref(info->pkt, pkt);
587 if (!ret)
588 info->num_blocks = num_blocks;
589 goto end;
590 } else {
591 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
592 goto end;
593 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
594 info->num_blocks += num_blocks;
595 info->pkt->duration += pkt->duration;
596 if (info->num_blocks != 6)
597 goto end;
598 av_packet_unref(pkt);
599 av_packet_move_ref(pkt, info->pkt);
600 info->num_blocks = 0;
601 }
602 ret = pkt->size;
603
604 1039 end:
605 1039 av_free(hdr);
606
607 1039 return ret;
608 }
609
610 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
611 {
612 PutBitContext pbc;
613 uint8_t *buf;
614 struct eac3_info *info;
615 int size, i;
616
617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
618 av_log(s, AV_LOG_ERROR,
619 "Cannot write moov atom before EAC3 packets parsed.\n");
620 return AVERROR(EINVAL);
621 }
622
623 1 info = track->eac3_priv;
624
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
625 1 buf = av_malloc(size);
626
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
627 return AVERROR(ENOMEM);
628 }
629
630 1 init_put_bits(&pbc, buf, size);
631 1 put_bits(&pbc, 13, info->data_rate);
632 1 put_bits(&pbc, 3, info->num_ind_sub);
633
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
634 1 put_bits(&pbc, 2, info->substream[i].fscod);
635 1 put_bits(&pbc, 5, info->substream[i].bsid);
636 1 put_bits(&pbc, 1, 0); /* reserved */
637 1 put_bits(&pbc, 1, 0); /* asvc */
638 1 put_bits(&pbc, 3, info->substream[i].bsmod);
639 1 put_bits(&pbc, 3, info->substream[i].acmod);
640 1 put_bits(&pbc, 1, info->substream[i].lfeon);
641 1 put_bits(&pbc, 3, 0); /* reserved */
642 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
643
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
644 1 put_bits(&pbc, 1, 0); /* reserved */
645 } else {
646 put_bits(&pbc, 9, info->substream[i].chan_loc);
647 }
648 }
649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (info->complexity_index_type_a) {
650 put_bits(&pbc, 7, 0); /* reserved */
651 put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
652 put_bits(&pbc, 8, info->complexity_index_type_a);
653 }
654 1 flush_put_bits(&pbc);
655 1 size = put_bytes_output(&pbc);
656
657 1 avio_wb32(pb, size + 8);
658 1 ffio_wfourcc(pb, "dec3");
659 1 avio_write(pb, buf, size);
660
661 1 av_free(buf);
662
663 1 return size;
664 }
665
666 /**
667 * This function writes extradata "as is".
668 * Extradata must be formatted like a valid atom (with size and tag).
669 */
670 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
671 {
672 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
673 12 return track->extradata_size[track->last_stsd_index];
674 }
675
676 static int mov_write_enda_tag(AVIOContext *pb)
677 {
678 avio_wb32(pb, 10);
679 ffio_wfourcc(pb, "enda");
680 avio_wb16(pb, 1); /* little endian */
681 return 10;
682 }
683
684 2 static int mov_write_enda_tag_be(AVIOContext *pb)
685 {
686 2 avio_wb32(pb, 10);
687 2 ffio_wfourcc(pb, "enda");
688 2 avio_wb16(pb, 0); /* big endian */
689 2 return 10;
690 }
691
692 336 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
693 {
694 336 int i = 3;
695 336 avio_w8(pb, tag);
696
2/2
✓ Branch 0 taken 1008 times.
✓ Branch 1 taken 336 times.
1344 for (; i > 0; i--)
697 1008 avio_w8(pb, (size >> (7 * i)) | 0x80);
698 336 avio_w8(pb, size & 0x7F);
699 336 }
700
701 227 static unsigned compute_avg_bitrate(MOVTrack *track)
702 {
703 227 uint64_t size = 0;
704 int i;
705
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 183 times.
227 if (!track->track_duration)
706 44 return 0;
707
2/2
✓ Branch 0 taken 9104 times.
✓ Branch 1 taken 183 times.
9287 for (i = 0; i < track->entry; i++)
708 9104 size += track->cluster[i].size;
709 183 return size * 8 * track->timescale / track->track_duration;
710 }
711
712 struct mpeg4_bit_rate_values {
713 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
714 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
715 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
716 };
717
718 227 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
719 {
720 454 const AVPacketSideData *sd = track->st ?
721 226 av_packet_side_data_get(track->st->codecpar->coded_side_data,
722 226 track->st->codecpar->nb_coded_side_data,
723
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 1 times.
227 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
724
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 190 times.
227 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
725 227 struct mpeg4_bit_rate_values bit_rates = { 0 };
726
727 227 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
728
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 89 times.
227 if (!bit_rates.avg_bit_rate) {
729 // if the average bit rate cannot be calculated at this point, such as
730 // in the case of fragmented MP4, utilize the following values as
731 // fall-back in priority order:
732 //
733 // 1. average bit rate property
734 // 2. bit rate (usually average over the whole clip)
735 // 3. maximum bit rate property
736
737
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
138 if (props && props->avg_bitrate) {
738 6 bit_rates.avg_bit_rate = props->avg_bitrate;
739
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 123 times.
132 } else if (track->par->bit_rate) {
740 9 bit_rates.avg_bit_rate = track->par->bit_rate;
741
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
123 } else if (props && props->max_bitrate) {
742 bit_rates.avg_bit_rate = props->max_bitrate;
743 }
744 }
745
746 // (FIXME should be max rate in any 1 sec window)
747 227 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
748 bit_rates.avg_bit_rate);
749
750 // utilize values from properties if we have them available
751
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 190 times.
227 if (props) {
752 // no avg_bitrate signals that the track is VBR
753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (!props->avg_bitrate)
754 bit_rates.avg_bit_rate = props->avg_bitrate;
755 37 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
756 props->max_bitrate);
757 37 bit_rates.buffer_size = props->buffer_size / 8;
758 }
759
760 227 return bit_rates;
761 }
762
763 85 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
764 {
765 85 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
766 85 int64_t pos = avio_tell(pb);
767 170 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
768
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 4 times.
85 5 + track->extradata_size[track->last_stsd_index] : 0;
769
770 85 avio_wb32(pb, 0); // size
771 85 ffio_wfourcc(pb, "esds");
772 85 avio_wb32(pb, 0); // Version
773
774 // ES descriptor
775 85 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
776 85 avio_wb16(pb, track->track_id);
777 85 avio_w8(pb, 0x00); // flags (= no flags)
778
779 // DecoderConfig descriptor
780 85 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
781
782 // Object type indication
783
1/2
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
85 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 track->par->codec_id == AV_CODEC_ID_MP3) &&
785 track->par->sample_rate > 24000)
786 avio_w8(pb, 0x6B); // 11172-3
787 else
788 85 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
789
790 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
791 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
793 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
794
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 29 times.
85 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
795 56 avio_w8(pb, 0x15); // flags (= Audiostream)
796 else
797 29 avio_w8(pb, 0x11); // flags (= Visualstream)
798
799 85 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
800 85 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
801 85 avio_wb32(pb, bit_rates.avg_bit_rate);
802
803
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 4 times.
85 if (track->extradata_size[track->last_stsd_index]) {
804 // DecoderSpecific info descriptor
805 81 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
806 81 avio_write(pb, track->extradata[track->last_stsd_index],
807 81 track->extradata_size[track->last_stsd_index]);
808 }
809
810 // SL descriptor
811 85 put_descr(pb, 0x06, 1);
812 85 avio_w8(pb, 0x02);
813 85 return update_size(pb, pos);
814 }
815
816 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
817 {
818
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
819
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
820
2/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
154 codec_id == AV_CODEC_ID_PCM_F32LE ||
821 codec_id == AV_CODEC_ID_PCM_F64LE;
822 }
823
824 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
825 {
826
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
827
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
828
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
150 codec_id == AV_CODEC_ID_PCM_F32BE ||
829 codec_id == AV_CODEC_ID_PCM_F64BE;
830 }
831
832 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
833 {
834 int ret;
835 int64_t pos = avio_tell(pb);
836 avio_wb32(pb, 0);
837 avio_wl32(pb, track->tag); // store it byteswapped
838 track->par->codec_tag = av_bswap16(track->tag >> 16);
839 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
840 return ret;
841 return update_size(pb, pos);
842 }
843
844 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
845 {
846 int ret;
847 int64_t pos = avio_tell(pb);
848 avio_wb32(pb, 0);
849 ffio_wfourcc(pb, "wfex");
850 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
851 return ret;
852 return update_size(pb, pos);
853 }
854
855 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
856 {
857 int64_t pos = avio_tell(pb);
858 avio_wb32(pb, 0);
859 ffio_wfourcc(pb, "dfLa");
860 avio_w8(pb, 0); /* version */
861 avio_wb24(pb, 0); /* flags */
862
863 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
864 if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
865 return AVERROR_INVALIDDATA;
866
867 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
868 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
869 avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
870 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
871
872 return update_size(pb, pos);
873 }
874
875 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
876 {
877 int64_t pos = avio_tell(pb);
878 int channels, channel_map;
879 avio_wb32(pb, 0);
880 ffio_wfourcc(pb, "dOps");
881 avio_w8(pb, 0); /* Version */
882 if (track->extradata_size[track->last_stsd_index] < 19) {
883 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
884 return AVERROR_INVALIDDATA;
885 }
886 /* extradata contains an Ogg OpusHead, other than byte-ordering and
887 OpusHead's preceding magic/version, OpusSpecificBox is currently
888 identical. */
889 channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
890 channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
891
892 avio_w8(pb, channels); /* OuputChannelCount */
893 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
894 avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
895 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
896 avio_w8(pb, channel_map); /* ChannelMappingFamily */
897 /* Write the rest of the header out without byte-swapping. */
898 if (channel_map) {
899 if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
900 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
901 return AVERROR_INVALIDDATA;
902 }
903 avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
904 }
905
906 return update_size(pb, pos);
907 }
908
909 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
910 {
911 int64_t pos = avio_tell(pb);
912 int length;
913 avio_wb32(pb, 0);
914 ffio_wfourcc(pb, "dmlp");
915
916 if (track->extradata_size[track->last_stsd_index] < 20) {
917 av_log(s, AV_LOG_ERROR,
918 "Cannot write moov atom before TrueHD packets."
919 " Set the delay_moov flag to fix this.\n");
920 return AVERROR(EINVAL);
921 }
922
923 length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
924 if (length < 20 || length > track->extradata_size[track->last_stsd_index])
925 return AVERROR_INVALIDDATA;
926
927 // Only TrueHD is supported
928 if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
929 return AVERROR_INVALIDDATA;
930
931 avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
932 avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
933 avio_wb32(pb, 0); /* reserved */
934
935 return update_size(pb, pos);
936 }
937
938 69 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
939 {
940 69 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
941 69 AVChannelLayout ch_layout = { 0 };
942 int64_t pos;
943 int ambisonic_order, ambi_channels, non_diegetic_channels;
944 int i, ret;
945
946
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if (!str)
947 69 return 0;
948
949 ret = av_channel_layout_from_string(&ch_layout, str->value);
950 if (ret < 0) {
951 if (ret == AVERROR(EINVAL)) {
952 invalid:
953 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
954 ret = 0;
955 }
956 av_channel_layout_uninit(&ch_layout);
957 return ret;
958 }
959
960 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
961 goto invalid;
962
963 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
964 if (ambisonic_order < 0)
965 goto invalid;
966
967 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
968 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
969 if (non_diegetic_channels &&
970 (non_diegetic_channels != 2 ||
971 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
972 goto invalid;
973
974 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
975
976 pos = avio_tell(pb);
977
978 avio_wb32(pb, 0); // Size
979 ffio_wfourcc(pb, "SA3D");
980 avio_w8(pb, 0); // version
981 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
982 avio_wb32(pb, ambisonic_order); // ambisonic_order
983 avio_w8(pb, 0); // ambisonic_channel_ordering
984 avio_w8(pb, 0); // ambisonic_normalization
985 avio_wb32(pb, ch_layout.nb_channels); // num_channels
986 for (i = 0; i < ambi_channels; i++)
987 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
988 for (; i < ch_layout.nb_channels; i++)
989 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
990
991 av_channel_layout_uninit(&ch_layout);
992
993 return update_size(pb, pos);
994 }
995
996 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
997 {
998 uint32_t layout_tag, bitmap, *channel_desc;
999 40 int64_t pos = avio_tell(pb);
1000 int num_desc, ret;
1001
1002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
1003 return 0;
1004
1005 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
1006 &bitmap, &channel_desc);
1007
1008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
1009 if (ret == AVERROR(ENOSYS)) {
1010 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
1011 "lack of channel information\n");
1012 ret = 0;
1013 }
1014
1015 return ret;
1016 }
1017
1018
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
40 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1020 1 channel_desc = av_malloc(sizeof(*channel_desc));
1021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1022 return AVERROR(ENOMEM);
1023
1024 1 layout_tag = 0;
1025 1 bitmap = 0;
1026 1 *channel_desc = 3; // channel label "Center"
1027 }
1028
1029
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1030
1031 40 avio_wb32(pb, 0); // Size
1032 40 ffio_wfourcc(pb, "chan"); // Type
1033 40 avio_w8(pb, 0); // Version
1034 40 avio_wb24(pb, 0); // Flags
1035 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1036 40 avio_wb32(pb, bitmap); // mChannelBitmap
1037 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1038
1039
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1040 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1041 3 avio_wb32(pb, 0); // mChannelFlags
1042 3 avio_wl32(pb, 0); // mCoordinates[0]
1043 3 avio_wl32(pb, 0); // mCoordinates[1]
1044 3 avio_wl32(pb, 0); // mCoordinates[2]
1045 }
1046
1047 40 av_free(channel_desc);
1048
1049 40 return update_size(pb, pos);
1050 }
1051
1052 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1053 {
1054 15 int64_t pos = avio_tell(pb);
1055
1056 15 avio_wb32(pb, 0); /* size */
1057 15 ffio_wfourcc(pb, "wave");
1058
1059
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1060 15 avio_wb32(pb, 12); /* size */
1061 15 ffio_wfourcc(pb, "frma");
1062 15 avio_wl32(pb, track->tag);
1063 }
1064
1065
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1066 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1067 3 avio_wb32(pb, 12); /* size */
1068 3 ffio_wfourcc(pb, "mp4a");
1069 3 avio_wb32(pb, 0);
1070 3 mov_write_esds_tag(pb, track);
1071
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1072 mov_write_enda_tag(pb);
1073
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1074 2 mov_write_enda_tag_be(pb);
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1076 mov_write_amr_tag(pb, track);
1077
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1078 1 mov_write_ac3_tag(s, pb, track);
1079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1080 mov_write_eac3_tag(s, pb, track);
1081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1082 track->par->codec_id == AV_CODEC_ID_QDM2) {
1083 9 mov_write_extradata_tag(pb, track);
1084 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1085 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1086 mov_write_ms_tag(s, pb, track);
1087 }
1088
1089 15 avio_wb32(pb, 8); /* size */
1090 15 avio_wb32(pb, 0); /* null tag */
1091
1092 15 return update_size(pb, pos);
1093 }
1094
1095 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1096 {
1097 uint8_t *unescaped;
1098 const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1099 track->extradata_size[track->last_stsd_index];
1100 int unescaped_size, seq_found = 0;
1101 int level = 0, interlace = 0;
1102 int packet_seq = track->vc1_info.packet_seq;
1103 int packet_entry = track->vc1_info.packet_entry;
1104 int slices = track->vc1_info.slices;
1105 PutBitContext pbc;
1106
1107 if (track->start_dts == AV_NOPTS_VALUE) {
1108 /* No packets written yet, vc1_info isn't authoritative yet. */
1109 /* Assume inline sequence and entry headers. */
1110 packet_seq = packet_entry = 1;
1111 av_log(NULL, AV_LOG_WARNING,
1112 "moov atom written before any packets, unable to write correct "
1113 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1114 }
1115
1116 unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1117 if (!unescaped)
1118 return AVERROR(ENOMEM);
1119 start = find_next_marker(track->extradata[track->last_stsd_index], end);
1120 for (next = start; next < end; start = next) {
1121 GetBitContext gb;
1122 int size;
1123 next = find_next_marker(start + 4, end);
1124 size = next - start - 4;
1125 if (size <= 0)
1126 continue;
1127 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1128 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1129 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1130 int profile = get_bits(&gb, 2);
1131 if (profile != PROFILE_ADVANCED) {
1132 av_free(unescaped);
1133 return AVERROR(ENOSYS);
1134 }
1135 seq_found = 1;
1136 level = get_bits(&gb, 3);
1137 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1138 * width, height */
1139 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1140 skip_bits(&gb, 1); /* broadcast */
1141 interlace = get_bits1(&gb);
1142 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1143 }
1144 }
1145 if (!seq_found) {
1146 av_free(unescaped);
1147 return AVERROR(ENOSYS);
1148 }
1149
1150 init_put_bits(&pbc, buf, 7);
1151 /* VC1DecSpecStruc */
1152 put_bits(&pbc, 4, 12); /* profile - advanced */
1153 put_bits(&pbc, 3, level);
1154 put_bits(&pbc, 1, 0); /* reserved */
1155 /* VC1AdvDecSpecStruc */
1156 put_bits(&pbc, 3, level);
1157 put_bits(&pbc, 1, 0); /* cbr */
1158 put_bits(&pbc, 6, 0); /* reserved */
1159 put_bits(&pbc, 1, !interlace); /* no interlace */
1160 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1161 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1162 put_bits(&pbc, 1, !slices); /* no slice code */
1163 put_bits(&pbc, 1, 0); /* no bframe */
1164 put_bits(&pbc, 1, 0); /* reserved */
1165
1166 /* framerate */
1167 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1168 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1169 else
1170 put_bits32(&pbc, 0xffffffff);
1171
1172 flush_put_bits(&pbc);
1173
1174 av_free(unescaped);
1175
1176 return 0;
1177 }
1178
1179 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1180 {
1181 uint8_t buf[7] = { 0 };
1182 int ret;
1183
1184 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1185 return ret;
1186
1187 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1188 ffio_wfourcc(pb, "dvc1");
1189 avio_write(pb, buf, sizeof(buf));
1190 avio_write(pb, track->extradata[track->last_stsd_index],
1191 track->extradata_size[track->last_stsd_index]);
1192
1193 return 0;
1194 }
1195
1196 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1197 {
1198 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1199 4 ffio_wfourcc(pb, "glbl");
1200 4 avio_write(pb, track->extradata[track->last_stsd_index],
1201 4 track->extradata_size[track->last_stsd_index]);
1202 4 return 8 + track->extradata_size[track->last_stsd_index];
1203 }
1204
1205 /**
1206 * Compute flags for 'lpcm' tag.
1207 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1208 */
1209 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1210 {
1211
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) {
1212 case AV_CODEC_ID_PCM_F32BE:
1213 case AV_CODEC_ID_PCM_F64BE:
1214 return 11;
1215 case AV_CODEC_ID_PCM_F32LE:
1216 case AV_CODEC_ID_PCM_F64LE:
1217 return 9;
1218 case AV_CODEC_ID_PCM_U8:
1219 return 10;
1220 case AV_CODEC_ID_PCM_S16BE:
1221 case AV_CODEC_ID_PCM_S24BE:
1222 case AV_CODEC_ID_PCM_S32BE:
1223 return 14;
1224 case AV_CODEC_ID_PCM_S8:
1225 case AV_CODEC_ID_PCM_S16LE:
1226 case AV_CODEC_ID_PCM_S24LE:
1227 case AV_CODEC_ID_PCM_S32LE:
1228 return 12;
1229 8 default:
1230 8 return 0;
1231 }
1232 }
1233
1234 29475 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1235 {
1236 int64_t next_dts;
1237
1238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29475 times.
29475 if (cluster_idx >= track->entry)
1239 return 0;
1240
1241
2/2
✓ Branch 0 taken 875 times.
✓ Branch 1 taken 28600 times.
29475 if (cluster_idx + 1 == track->entry)
1242 875 next_dts = track->track_duration + track->start_dts;
1243 else
1244 28600 next_dts = track->cluster[cluster_idx + 1].dts;
1245
1246 29475 next_dts -= track->cluster[cluster_idx].dts;
1247
1248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29475 times.
29475 av_assert0(next_dts >= 0);
1249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29475 times.
29475 av_assert0(next_dts <= INT_MAX);
1250
1251 29475 return next_dts;
1252 }
1253
1254 4 static int get_samples_per_packet(MOVTrack *track)
1255 {
1256 int i, first_duration;
1257
1258 /* use 1 for raw PCM */
1259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1260 return 1;
1261
1262 /* check to see if duration is constant for all clusters */
1263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1264 return 0;
1265 4 first_duration = get_cluster_duration(track, 0);
1266
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1267
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1268 4 return 0;
1269 }
1270 return first_duration;
1271 }
1272
1273 142 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1274 {
1275 142 int64_t pos = avio_tell(pb);
1276 142 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1277
3/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
142 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1278
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 !bit_rates.buffer_size)
1279 // no useful data to be written, skip
1280 82 return 0;
1281
1282 60 avio_wb32(pb, 0); /* size */
1283 60 ffio_wfourcc(pb, "btrt");
1284
1285 60 avio_wb32(pb, bit_rates.buffer_size);
1286 60 avio_wb32(pb, bit_rates.max_bit_rate);
1287 60 avio_wb32(pb, bit_rates.avg_bit_rate);
1288
1289 60 return update_size(pb, pos);
1290 }
1291
1292 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1293 {
1294 7 int64_t pos = avio_tell(pb);
1295 7 int config = 0;
1296 int ret;
1297 7 uint8_t *speaker_pos = NULL;
1298 7 const AVChannelLayout *layout = &track->par->ch_layout;
1299
1300 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1301
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) {
1302 4 config = 0;
1303 4 speaker_pos = av_malloc(layout->nb_channels);
1304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1305 return AVERROR(ENOMEM);
1306 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1307 4 speaker_pos, layout->nb_channels);
1308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1309 char buf[128] = {0};
1310
1311 av_freep(&speaker_pos);
1312 av_channel_layout_describe(layout, buf, sizeof(buf));
1313 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1314 return ret;
1315 }
1316 }
1317
1318 7 avio_wb32(pb, 0); /* size */
1319 7 ffio_wfourcc(pb, "chnl");
1320 7 avio_wb32(pb, 0); /* version & flags */
1321
1322 7 avio_w8(pb, 1); /* stream_structure */
1323 7 avio_w8(pb, config);
1324
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1325 3 avio_wb64(pb, 0);
1326 } else {
1327 4 avio_write(pb, speaker_pos, layout->nb_channels);
1328 4 av_freep(&speaker_pos);
1329 }
1330
1331 7 return update_size(pb, pos);
1332 }
1333
1334 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1335 {
1336 9 int64_t pos = avio_tell(pb);
1337 int format_flags;
1338 int sample_size;
1339
1340 9 avio_wb32(pb, 0); /* size */
1341 9 ffio_wfourcc(pb, "pcmC");
1342 9 avio_wb32(pb, 0); /* version & flags */
1343
1344 /* 0x01: indicates little-endian format */
1345 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1346
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1348
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 ||
1349 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1350 9 avio_w8(pb, format_flags);
1351 9 sample_size = track->par->bits_per_raw_sample;
1352
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1353 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1355 9 avio_w8(pb, sample_size);
1356
1357 9 return update_size(pb, pos);
1358 }
1359
1360 5 static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track)
1361 {
1362 5 int64_t pos = avio_tell(pb);
1363 5 avio_wb32(pb, 0); /* size */
1364 5 ffio_wfourcc(pb, "srat");
1365 5 avio_wb32(pb, 0); /* version & flags */
1366
1367 5 avio_wb32(pb, track->par->sample_rate);
1368
1369 5 return update_size(pb, pos);
1370 }
1371
1372 112 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1373 {
1374 112 int64_t pos = avio_tell(pb);
1375 112 int version = 0;
1376 112 uint32_t tag = track->tag;
1377 112 int ret = 0;
1378
1379
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
112 if (track->mode == MODE_MOV) {
1380
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
40 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1381
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1382 tag = AV_RL32("lpcm");
1383 4 version = 2;
1384
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
62 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1385 26 mov_pcm_be_gt16(track->par->codec_id) ||
1386
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1387
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1389 12 version = 1;
1390 }
1391
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 3 times.
72 } else if (track->mode == MODE_MP4) {
1392
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
69 if (track->par->sample_rate > UINT16_MAX &&
1393 (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG))
1394 5 version = 1;
1395 }
1396
1397 112 avio_wb32(pb, 0); /* size */
1398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (mov->encryption_scheme != MOV_ENC_NONE) {
1399 ffio_wfourcc(pb, "enca");
1400 } else {
1401 112 avio_wl32(pb, tag); // store it byteswapped
1402 }
1403 112 avio_wb32(pb, 0); /* Reserved */
1404 112 avio_wb16(pb, 0); /* Reserved */
1405 112 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1406
1407 /* SoundDescription */
1408 112 avio_wb16(pb, version); /* Version */
1409 112 avio_wb16(pb, 0); /* Revision level */
1410 112 avio_wb32(pb, 0); /* Reserved */
1411
1412
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 108 times.
112 if (version == 2) {
1413 4 avio_wb16(pb, 3);
1414 4 avio_wb16(pb, 16);
1415 4 avio_wb16(pb, 0xfffe);
1416 4 avio_wb16(pb, 0);
1417 4 avio_wb32(pb, 0x00010000);
1418 4 avio_wb32(pb, 72);
1419 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1420 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1421 4 avio_wb32(pb, 0x7F000000);
1422 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1423 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1424 4 avio_wb32(pb, track->sample_size);
1425 4 avio_wb32(pb, get_samples_per_packet(track));
1426 } else {
1427 108 unsigned sample_rate = track->par->sample_rate;
1428
1429
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 72 times.
108 if (track->mode == MODE_MOV) {
1430 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1431
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1432
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1433 1 avio_wb16(pb, 8); /* bits per sample */
1434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1435 avio_wb16(pb, track->par->bits_per_coded_sample);
1436 else
1437 35 avio_wb16(pb, 16);
1438
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1439 } else { /* reserved for mp4/3gp */
1440
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
139 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1441 67 0 : track->par->ch_layout.nb_channels);
1442
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
72 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 track->par->codec_id == AV_CODEC_ID_ALAC) {
1444 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1445 } else {
1446 67 avio_wb16(pb, 16);
1447 }
1448 72 avio_wb16(pb, 0);
1449
1450
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 72 times.
77 while (sample_rate > UINT16_MAX)
1451 5 sample_rate >>= 1;
1452 }
1453
1454 108 avio_wb16(pb, 0); /* packet size (= 0) */
1455
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 103 times.
108 if (track->tag == MKTAG('i','a','m','f'))
1456 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1458 avio_wb16(pb, 48000);
1459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1460 avio_wb32(pb, track->par->sample_rate);
1461 else
1462 103 avio_wb16(pb, sample_rate);
1463
1464
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1465 108 avio_wb16(pb, 0); /* Reserved */
1466 }
1467
1468
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 28 times.
112 if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */
1469
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
24 if (mov_pcm_le_gt16(track->par->codec_id) ||
1470 12 mov_pcm_be_gt16(track->par->codec_id))
1471 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1472 else
1473 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1474 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1475 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1476 12 avio_wb32(pb, 2); /* Bytes per sample */
1477 }
1478
1479
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
112 if (track->mode == MODE_MOV &&
1480
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1481
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1482
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1483
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1484
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1485
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1486
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1487
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 ||
1488
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) ||
1489
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1490 15 ret = mov_write_wave_tag(s, pb, track);
1491
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 44 times.
97 else if (track->tag == MKTAG('m','p','4','a'))
1492 53 ret = mov_write_esds_tag(pb, track);
1493 #if CONFIG_IAMFENC
1494
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 39 times.
44 else if (track->tag == MKTAG('i','a','m','f'))
1495 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1496 #endif
1497
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1498 ret = mov_write_amr_tag(pb, track);
1499
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1500 4 ret = mov_write_ac3_tag(s, pb, track);
1501
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1502 1 ret = mov_write_eac3_tag(s, pb, track);
1503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1504 ret = mov_write_extradata_tag(pb, track);
1505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1506 ret = mov_write_wfex_tag(s, pb, track);
1507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1508 ret = mov_write_dfla_tag(pb, track);
1509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1510 ret = mov_write_dops_tag(s, pb, track);
1511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1512 ret = mov_write_dmlp_tag(s, pb, track);
1513
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) {
1514
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (track->par->sample_rate > UINT16_MAX)
1515 5 mov_write_srat_tag(pb, track);
1516
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1517 7 ret = mov_write_chnl_tag(s, pb, track);
1518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1519 return ret;
1520 9 ret = mov_write_pcmc_tag(s, pb, track);
1521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1522 ret = mov_write_glbl_tag(pb, track);
1523
1524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (ret < 0)
1525 return ret;
1526
1527
3/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
112 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1528
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
69 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1529 return ret;
1530 }
1531
1532
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
112 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1533
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1534 return ret;
1535 }
1536
1537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (mov->encryption_scheme != MOV_ENC_NONE
1538 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1539 return ret;
1540 }
1541
1542
3/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
181 if (mov->write_btrt &&
1543 69 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1544 return ret;
1545
1546
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 43 times.
112 if (track->mode == MODE_MP4)
1547 69 track->entry_version = version;
1548
1549 112 ret = update_size(pb, pos);
1550 112 return ret;
1551 }
1552
1553 static int mov_write_d263_tag(AVIOContext *pb)
1554 {
1555 avio_wb32(pb, 0xf); /* size */
1556 ffio_wfourcc(pb, "d263");
1557 ffio_wfourcc(pb, "FFMP");
1558 avio_w8(pb, 0); /* decoder version */
1559 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1560 avio_w8(pb, 0xa); /* level */
1561 avio_w8(pb, 0); /* profile */
1562 return 0xf;
1563 }
1564
1565 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1566 {
1567 1 int64_t pos = avio_tell(pb);
1568
1569 1 avio_wb32(pb, 0);
1570 1 ffio_wfourcc(pb, "av1C");
1571 1 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1572 1 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1573 1 return update_size(pb, pos);
1574 }
1575
1576 55 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1577 {
1578 55 int64_t pos = avio_tell(pb);
1579
1580 55 avio_wb32(pb, 0);
1581 55 ffio_wfourcc(pb, "avcC");
1582 55 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1583 55 track->extradata_size[track->last_stsd_index]);
1584 55 return update_size(pb, pos);
1585 }
1586
1587 /* AVS3 Intelligent Media Coding
1588 * Information Technology - Intelligent Media Coding
1589 * Part 6: Intelligent Media Format
1590 */
1591 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1592 {
1593 if (len < 4)
1594 return AVERROR_INVALIDDATA;
1595
1596 if (data[0] == 1) {
1597 // In Avs3DecoderConfigurationRecord format
1598 avio_write(pb, data, len);
1599 return 0;
1600 }
1601
1602 avio_w8(pb, 1); // version
1603 avio_wb16(pb, len); // sequence_header_length
1604 avio_write(pb, data, len); // sequence_header
1605 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1606
1607 return 0;
1608 }
1609
1610 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1611 {
1612 int64_t pos = avio_tell(pb);
1613 avio_wb32(pb, 0);
1614 ffio_wfourcc(pb, "av3c");
1615 mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1616 track->extradata_size[track->last_stsd_index]);
1617 return update_size(pb, pos);
1618 }
1619
1620 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1621 {
1622 int64_t pos = avio_tell(pb);
1623
1624 avio_wb32(pb, 0);
1625 ffio_wfourcc(pb, "vpcC");
1626 ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1627 track->extradata_size[track->last_stsd_index], track->par);
1628 return update_size(pb, pos);
1629 }
1630
1631 6 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1632 {
1633 6 int64_t pos = avio_tell(pb);
1634
1635 6 avio_wb32(pb, 0);
1636 6 ffio_wfourcc(pb, "hvcC");
1637
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('h','v','c','1'))
1638 1 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1639 1 track->extradata_size[track->last_stsd_index], 1, s);
1640 else
1641 5 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1642 5 track->extradata_size[track->last_stsd_index], 0, s);
1643 6 return update_size(pb, pos);
1644 }
1645
1646 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1647 {
1648 1 int64_t pos = avio_tell(pb);
1649 int ret;
1650
1651 1 avio_wb32(pb, 0);
1652 1 ffio_wfourcc(pb, "lhvC");
1653
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1654 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1655 1 track->extradata_size[track->last_stsd_index], 1, s);
1656 else
1657 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1658 track->extradata_size[track->last_stsd_index], 0, s);
1659
1660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1661 avio_seek(pb, pos, SEEK_SET);
1662 return ret;
1663 }
1664
1665 1 return update_size(pb, pos);
1666 }
1667
1668 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1669 {
1670 1 int64_t pos = avio_tell(pb);
1671
1672 1 avio_wb32(pb, 0);
1673 1 ffio_wfourcc(pb, "evcC");
1674
1675
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1676 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1677 1 track->extradata_size[track->last_stsd_index], 1);
1678 else
1679 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1680 track->extradata_size[track->last_stsd_index], 0);
1681
1682 1 return update_size(pb, pos);
1683 }
1684
1685 static int mov_write_lvcc_tag(AVIOContext *pb, MOVTrack *track)
1686 {
1687 int64_t pos = avio_tell(pb);
1688
1689 avio_wb32(pb, 0);
1690 ffio_wfourcc(pb, "lvcC");
1691
1692 ff_isom_write_lvcc(pb, track->extradata[track->last_stsd_index],
1693 track->extradata_size[track->last_stsd_index]);
1694
1695 return update_size(pb, pos);
1696 }
1697
1698 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1699 {
1700 1 int64_t pos = avio_tell(pb);
1701
1702 1 avio_wb32(pb, 0);
1703 1 ffio_wfourcc(pb, "vvcC");
1704
1705 1 avio_w8 (pb, 0); /* version */
1706 1 avio_wb24(pb, 0); /* flags */
1707
1708
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1709 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1710 1 track->extradata_size[track->last_stsd_index], 1);
1711 else
1712 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1713 track->extradata_size[track->last_stsd_index], 0);
1714 1 return update_size(pb, pos);
1715 }
1716
1717 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1718 {
1719 1 int64_t pos = avio_tell(pb);
1720
1721 1 avio_wb32(pb, 0);
1722 1 ffio_wfourcc(pb, "apvC");
1723
1724 1 avio_w8 (pb, 0); /* version */
1725 1 avio_wb24(pb, 0); /* flags */
1726
1727 1 ff_isom_write_apvc(pb, track->apv, s);
1728
1729 1 return update_size(pb, pos);
1730 }
1731
1732 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1733 /* https://community.avid.com/forums/t/136517.aspx */
1734 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1735 {
1736 int interlaced;
1737 int cid;
1738 23 int display_width = track->par->width;
1739 const uint8_t *extradata;
1740
1741
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) {
1742
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) {
1743 /* looks like a DNxHD bit stream */
1744 23 extradata = track->extradata[track->last_stsd_index];
1745 } else {
1746 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1747 return 0;
1748 }
1749 } else {
1750 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1751 return 0;
1752 }
1753
1754 23 cid = AV_RB32(extradata + 0x28);
1755
1756 23 avio_wb32(pb, 24); /* size */
1757 23 ffio_wfourcc(pb, "ACLR");
1758 23 ffio_wfourcc(pb, "ACLR");
1759 23 ffio_wfourcc(pb, "0001");
1760 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1761 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1763 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1764 23 avio_wb32(pb, 1);
1765 } else {
1766 avio_wb32(pb, 2);
1767 }
1768 23 avio_wb32(pb, 0); /* reserved */
1769
1770
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1771 12 int alp = extradata[0x07] & 1;
1772 12 int pma = (extradata[0x07] >> 2) & 1;
1773 12 int sbd = (extradata[0x21] >> 5) & 3;
1774 12 int ssc = (extradata[0x2C] >> 5) & 3;
1775 12 int clv = (extradata[0x2C] >> 1) & 3;
1776 12 int clf = extradata[0x2C] & 1;
1777
1778 12 avio_wb32(pb, 32);
1779 12 ffio_wfourcc(pb, "ADHR");
1780 12 ffio_wfourcc(pb, "0001");
1781 12 avio_wb32(pb, cid); // Compression ID
1782 // 0: 4:2:2 Sub Sampling
1783 // 1: 4:2:0 Sub Sampling
1784 // 2: 4:4:4 Sub Sampling
1785 12 avio_wb32(pb, ssc); // Sub Sampling Control
1786 // 1: 8-bits per sample
1787 // 2: 10-bits per sample
1788 // 3: 12-bits per sample
1789 12 avio_wb32(pb, sbd); // Sample Bit Depth
1790 // 0: Bitstream is encoded using the YCBCR format rules and tables
1791 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1792 12 avio_wb16(pb, clf); // Color Format
1793 // 0: ITU-R BT.709
1794 // 1: ITU-R BT.2020
1795 // 2: ITU-R BT.2020 C
1796 // 3: Out-of-band
1797 12 avio_wb16(pb, clv); // Color Volume
1798 // 0: Alpha channel not present
1799 // 1: Alpha channel present
1800 12 avio_wb16(pb, alp); // Alpha Present
1801 // 0: Alpha has not been applied to video channels
1802 // 1: Alpha has been applied to the video channels prior to encoding
1803 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1804 12 return 0;
1805 }
1806
1807 11 interlaced = extradata[5] & 2;
1808
1809 11 avio_wb32(pb, 24); /* size */
1810 11 ffio_wfourcc(pb, "APRG");
1811 11 ffio_wfourcc(pb, "APRG");
1812 11 ffio_wfourcc(pb, "0001");
1813 // 1 for progressive or 2 for interlaced
1814
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1815 11 avio_wb32(pb, 2);
1816 else
1817 avio_wb32(pb, 1);
1818 11 avio_wb32(pb, 0); /* reserved */
1819
1820 11 avio_wb32(pb, 120); /* size */
1821 11 ffio_wfourcc(pb, "ARES");
1822 11 ffio_wfourcc(pb, "ARES");
1823 11 ffio_wfourcc(pb, "0001");
1824 11 avio_wb32(pb, cid); /* cid */
1825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1826 && track->par->sample_aspect_ratio.den > 0)
1827 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1828 11 avio_wb32(pb, display_width); // field width
1829
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1830 11 avio_wb32(pb, track->par->height / 2); // field height
1831 11 avio_wb32(pb, 2); // num fields
1832 11 avio_wb32(pb, 0); // num black lines (must be 0)
1833 // 4: HD1080i
1834 // 5: HD1080P
1835 // 6: HD720P
1836 11 avio_wb32(pb, 4); // video format
1837 } else {
1838 avio_wb32(pb, track->par->height);
1839 avio_wb32(pb, 1); // num fields
1840 avio_wb32(pb, 0);
1841 if (track->par->height == 1080)
1842 avio_wb32(pb, 5);
1843 else
1844 avio_wb32(pb, 6);
1845 }
1846 /* padding */
1847 11 ffio_fill(pb, 0, 10 * 8);
1848
1849 11 return 0;
1850 }
1851
1852 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1853 {
1854 avio_wb32(pb, 12);
1855 ffio_wfourcc(pb, "DpxE");
1856 if (track->extradata_size[track->last_stsd_index] >= 12 &&
1857 !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1858 avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1859 } else {
1860 avio_wb32(pb, 1);
1861 }
1862 return 0;
1863 }
1864
1865 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1866 {
1867 int tag;
1868
1869
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1870
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1871
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');
1872 1 else tag = MKTAG('d','v','c',' ');
1873 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1874 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1875 else tag = MKTAG('d','v','p','p');
1876 } else if (track->par->height == 720) { /* HD 720 line */
1877 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1878 else tag = MKTAG('d','v','h','p');
1879 } else if (track->par->height == 1080) { /* HD 1080 line */
1880 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1881 else tag = MKTAG('d','v','h','6');
1882 } else {
1883 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1884 return 0;
1885 }
1886
1887 1 return tag;
1888 }
1889
1890 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1891 {
1892 3 AVRational rational_framerate = st->avg_frame_rate;
1893 3 int rate = 0;
1894
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1895 3 rate = av_q2d(rational_framerate);
1896 3 return rate;
1897 }
1898
1899 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1900 {
1901 1 int tag = track->par->codec_tag;
1902 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1903 1 AVStream *st = track->st;
1904 1 int rate = defined_frame_rate(s, st);
1905
1906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1907 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1908
1909
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1910
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) {
1911 if (!interlaced) {
1912 if (rate == 24) tag = MKTAG('x','d','v','4');
1913 else if (rate == 25) tag = MKTAG('x','d','v','5');
1914 else if (rate == 30) tag = MKTAG('x','d','v','1');
1915 else if (rate == 50) tag = MKTAG('x','d','v','a');
1916 else if (rate == 60) tag = MKTAG('x','d','v','9');
1917 }
1918
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) {
1919 if (!interlaced) {
1920 if (rate == 24) tag = MKTAG('x','d','v','6');
1921 else if (rate == 25) tag = MKTAG('x','d','v','7');
1922 else if (rate == 30) tag = MKTAG('x','d','v','8');
1923 } else {
1924 if (rate == 25) tag = MKTAG('x','d','v','3');
1925 else if (rate == 30) tag = MKTAG('x','d','v','2');
1926 }
1927
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) {
1928 if (!interlaced) {
1929 if (rate == 24) tag = MKTAG('x','d','v','d');
1930 else if (rate == 25) tag = MKTAG('x','d','v','e');
1931 else if (rate == 30) tag = MKTAG('x','d','v','f');
1932 } else {
1933 if (rate == 25) tag = MKTAG('x','d','v','c');
1934 else if (rate == 30) tag = MKTAG('x','d','v','b');
1935 }
1936 }
1937 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1938 if (track->par->width == 1280 && track->par->height == 720) {
1939 if (!interlaced) {
1940 if (rate == 24) tag = MKTAG('x','d','5','4');
1941 else if (rate == 25) tag = MKTAG('x','d','5','5');
1942 else if (rate == 30) tag = MKTAG('x','d','5','1');
1943 else if (rate == 50) tag = MKTAG('x','d','5','a');
1944 else if (rate == 60) tag = MKTAG('x','d','5','9');
1945 }
1946 } else if (track->par->width == 1920 && track->par->height == 1080) {
1947 if (!interlaced) {
1948 if (rate == 24) tag = MKTAG('x','d','5','d');
1949 else if (rate == 25) tag = MKTAG('x','d','5','e');
1950 else if (rate == 30) tag = MKTAG('x','d','5','f');
1951 } else {
1952 if (rate == 25) tag = MKTAG('x','d','5','c');
1953 else if (rate == 30) tag = MKTAG('x','d','5','b');
1954 }
1955 }
1956 }
1957
1958 1 return tag;
1959 }
1960
1961 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1962 {
1963 2 int tag = track->par->codec_tag;
1964 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1965 2 AVStream *st = track->st;
1966 2 int rate = defined_frame_rate(s, st);
1967
1968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1969 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1970
1971
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
1972
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
1973 2 return tag;
1974
1975 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1976 if (track->par->width == 960 && track->par->height == 720) {
1977 if (!interlaced) {
1978 if (rate == 24) tag = MKTAG('a','i','5','p');
1979 else if (rate == 25) tag = MKTAG('a','i','5','q');
1980 else if (rate == 30) tag = MKTAG('a','i','5','p');
1981 else if (rate == 50) tag = MKTAG('a','i','5','q');
1982 else if (rate == 60) tag = MKTAG('a','i','5','p');
1983 }
1984 } else if (track->par->width == 1440 && track->par->height == 1080) {
1985 if (!interlaced) {
1986 if (rate == 24) tag = MKTAG('a','i','5','3');
1987 else if (rate == 25) tag = MKTAG('a','i','5','2');
1988 else if (rate == 30) tag = MKTAG('a','i','5','3');
1989 } else {
1990 if (rate == 50) tag = MKTAG('a','i','5','5');
1991 else if (rate == 60) tag = MKTAG('a','i','5','6');
1992 }
1993 }
1994 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1995 if (track->par->width == 1280 && track->par->height == 720) {
1996 if (!interlaced) {
1997 if (rate == 24) tag = MKTAG('a','i','1','p');
1998 else if (rate == 25) tag = MKTAG('a','i','1','q');
1999 else if (rate == 30) tag = MKTAG('a','i','1','p');
2000 else if (rate == 50) tag = MKTAG('a','i','1','q');
2001 else if (rate == 60) tag = MKTAG('a','i','1','p');
2002 }
2003 } else if (track->par->width == 1920 && track->par->height == 1080) {
2004 if (!interlaced) {
2005 if (rate == 24) tag = MKTAG('a','i','1','3');
2006 else if (rate == 25) tag = MKTAG('a','i','1','2');
2007 else if (rate == 30) tag = MKTAG('a','i','1','3');
2008 } else {
2009 if (rate == 25) tag = MKTAG('a','i','1','5');
2010 else if (rate == 50) tag = MKTAG('a','i','1','5');
2011 else if (rate == 60) tag = MKTAG('a','i','1','6');
2012 }
2013 } else if ( track->par->width == 4096 && track->par->height == 2160
2014 || track->par->width == 3840 && track->par->height == 2160
2015 || track->par->width == 2048 && track->par->height == 1080) {
2016 tag = MKTAG('a','i','v','x');
2017 }
2018 }
2019
2020 return tag;
2021 }
2022
2023 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
2024 {
2025 int tag = track->par->codec_tag;
2026
2027 if (!tag)
2028 tag = MKTAG('e', 'v', 'c', '1');
2029
2030 return tag;
2031 }
2032
2033 static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
2034 {
2035 int tag = track->par->codec_tag;
2036
2037 if (!tag)
2038 tag = MKTAG('a', 'p', 'v', '1');
2039
2040 return tag;
2041 }
2042
2043
2044 static const struct {
2045 enum AVPixelFormat pix_fmt;
2046 uint32_t tag;
2047 unsigned bps;
2048 } mov_pix_fmt_tags[] = {
2049 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
2050 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2051 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2052 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2053 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2054 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2055 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2056 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2057 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2058 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2059 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2060 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2061 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2062 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2063 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2064 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2065 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2066 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2067 };
2068
2069 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2070 {
2071 23 int tag = MKTAG('A','V','d','n');
2072
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2073
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2074 12 tag = MKTAG('A','V','d','h');
2075 23 return tag;
2076 }
2077
2078 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2079 {
2080 17 int tag = track->par->codec_tag;
2081 int i;
2082 enum AVPixelFormat pix_fmt;
2083
2084
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++) {
2085
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2086 17 tag = mov_pix_fmt_tags[i].tag;
2087 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2088
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2089 5 break;
2090 }
2091 }
2092
2093 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2094 17 track->par->bits_per_coded_sample);
2095
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2097 track->par->format != AV_PIX_FMT_GRAY8 &&
2098 track->par->format != AV_PIX_FMT_NONE)
2099 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2100 av_get_pix_fmt_name(track->par->format));
2101 17 return tag;
2102 }
2103
2104 170 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2105 {
2106 170 unsigned int tag = track->par->codec_tag;
2107
2108 // "rtp " is used to distinguish internally created RTP-hint tracks
2109 // (with rtp_ctx) from other tracks.
2110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (tag == MKTAG('r','t','p',' '))
2111 tag = 0;
2112
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 &&
2113
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2114
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 17 times.
133 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2115
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 track->par->codec_id == AV_CODEC_ID_H263 ||
2116
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 2 times.
116 track->par->codec_id == AV_CODEC_ID_H264 ||
2117
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 23 times.
114 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2118
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 ||
2119 90 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2120
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2121 1 tag = mov_get_dv_codec_tag(s, track);
2122
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2123 17 tag = mov_get_rawvideo_codec_tag(s, track);
2124
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2125 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2126
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2127 2 tag = mov_get_h264_codec_tag(s, track);
2128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2129 tag = mov_get_evc_codec_tag(s, track);
2130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2131 tag = mov_get_apv_codec_tag(s, track);
2132
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2133 23 tag = mov_get_dnxhd_codec_tag(s, track);
2134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2135 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2136 if (!tag) { // if no mac fcc found, try with Microsoft tags
2137 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2138 if (tag)
2139 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2140 "the file may be unplayable!\n");
2141 }
2142
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2143 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2145 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2146 if (ms_tag) {
2147 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2148 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2149 "the file may be unplayable!\n");
2150 }
2151 }
2152 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2153 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2154 }
2155
2156 170 return tag;
2157 }
2158
2159 static const AVCodecTag codec_cover_image_tags[] = {
2160 { AV_CODEC_ID_MJPEG, 0xD },
2161 { AV_CODEC_ID_PNG, 0xE },
2162 { AV_CODEC_ID_BMP, 0x1B },
2163 { AV_CODEC_ID_NONE, 0 },
2164 };
2165
2166 104 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2167 unsigned int tag, int codec_id)
2168 {
2169 int i;
2170
2171 /**
2172 * Check that tag + id is in the table
2173 */
2174
2/4
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 104 times.
✗ Branch 3 not taken.
104 for (i = 0; tags && tags[i]; i++) {
2175 104 const AVCodecTag *codec_tags = tags[i];
2176
1/2
✓ Branch 0 taken 1591 times.
✗ Branch 1 not taken.
1591 while (codec_tags->id != AV_CODEC_ID_NONE) {
2177
2/2
✓ Branch 2 taken 123 times.
✓ Branch 3 taken 1468 times.
1591 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2178
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 19 times.
123 codec_tags->id == codec_id)
2179 104 return codec_tags->tag;
2180 1487 codec_tags++;
2181 }
2182 }
2183 return 0;
2184 }
2185
2186 276 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2187 {
2188
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 274 times.
276 if (is_cover_image(track->st))
2189 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2190
2191
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 273 times.
274 if (track->mode == MODE_IPOD)
2192
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") &&
2193
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2194 1 !av_match_ext(s->url, "m4b"))
2195 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2196 "Quicktime/Ipod might not play the file\n");
2197
2198
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 104 times.
274 if (track->mode == MODE_MOV) {
2199 170 return mov_get_codec_tag(s, track);
2200 } else
2201 104 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2202 104 track->par->codec_id);
2203 }
2204
2205 /** Write uuid atom.
2206 * Needed to make file play in iPods running newest firmware
2207 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2208 */
2209 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2210 {
2211 avio_wb32(pb, 28);
2212 ffio_wfourcc(pb, "uuid");
2213 avio_wb32(pb, 0x6b6840f2);
2214 avio_wb32(pb, 0x5f244fc5);
2215 avio_wb32(pb, 0xba39a51b);
2216 avio_wb32(pb, 0xcf0323f3);
2217 avio_wb32(pb, 0x0);
2218 return 28;
2219 }
2220
2221 static const uint16_t fiel_data[] = {
2222 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2223 };
2224
2225 99 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2226 {
2227 99 unsigned mov_field_order = 0;
2228
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2229 99 mov_field_order = fiel_data[field_order];
2230 else
2231 return 0;
2232 99 avio_wb32(pb, 10);
2233 99 ffio_wfourcc(pb, "fiel");
2234 99 avio_wb16(pb, mov_field_order);
2235 99 return 10;
2236 }
2237
2238 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2239 {
2240 6 MOVMuxContext *mov = s->priv_data;
2241 6 int ret = AVERROR_BUG;
2242 6 int64_t pos = avio_tell(pb);
2243 6 avio_wb32(pb, 0); /* size */
2244 6 avio_wl32(pb, track->tag); // store it byteswapped
2245 6 avio_wb32(pb, 0); /* Reserved */
2246 6 avio_wb16(pb, 0); /* Reserved */
2247 6 avio_wb16(pb, 1); /* Data-reference index */
2248
2249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2250 mov_write_esds_tag(pb, track);
2251
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2252
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2253 2 case MOV_ISMV_TTML_TAG:
2254 // ISMV dfxp requires no extradata.
2255 4 break;
2256 2 case MOV_MP4_TTML_TAG:
2257 // As specified in 14496-30, XMLSubtitleSampleEntry
2258 // Namespace
2259 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2260 // Empty schema_location
2261 2 avio_w8(pb, 0);
2262 // Empty auxiliary_mime_types
2263 2 avio_w8(pb, 0);
2264 2 break;
2265 default:
2266 av_log(NULL, AV_LOG_ERROR,
2267 "Unknown codec tag '%s' utilized for TTML stream with "
2268 "index %d (track id %d)!\n",
2269 av_fourcc2str(track->par->codec_tag), track->st->index,
2270 track->track_id);
2271 return AVERROR(EINVAL);
2272 }
2273
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2274 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2275
2276
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 &&
2277 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2278 return ret;
2279
2280 6 return update_size(pb, pos);
2281 }
2282
2283 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2284 {
2285 int8_t stereo_mode;
2286
2287 if (stereo_3d->flags != 0) {
2288 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2289 return 0;
2290 }
2291
2292 switch (stereo_3d->type) {
2293 case AV_STEREO3D_2D:
2294 stereo_mode = 0;
2295 break;
2296 case AV_STEREO3D_TOPBOTTOM:
2297 stereo_mode = 1;
2298 break;
2299 case AV_STEREO3D_SIDEBYSIDE:
2300 stereo_mode = 2;
2301 break;
2302 default:
2303 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2304 return 0;
2305 }
2306 avio_wb32(pb, 13); /* size */
2307 ffio_wfourcc(pb, "st3d");
2308 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2309 avio_w8(pb, stereo_mode);
2310 return 13;
2311 }
2312
2313 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2314 {
2315 int64_t sv3d_pos, svhd_pos, proj_pos;
2316 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2317
2318 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2319 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2320 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2321 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2322 return 0;
2323 }
2324
2325 sv3d_pos = avio_tell(pb);
2326 avio_wb32(pb, 0); /* size */
2327 ffio_wfourcc(pb, "sv3d");
2328
2329 svhd_pos = avio_tell(pb);
2330 avio_wb32(pb, 0); /* size */
2331 ffio_wfourcc(pb, "svhd");
2332 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2333 avio_put_str(pb, metadata_source);
2334 update_size(pb, svhd_pos);
2335
2336 proj_pos = avio_tell(pb);
2337 avio_wb32(pb, 0); /* size */
2338 ffio_wfourcc(pb, "proj");
2339
2340 avio_wb32(pb, 24); /* size */
2341 ffio_wfourcc(pb, "prhd");
2342 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2343 avio_wb32(pb, spherical_mapping->yaw);
2344 avio_wb32(pb, spherical_mapping->pitch);
2345 avio_wb32(pb, spherical_mapping->roll);
2346
2347 switch (spherical_mapping->projection) {
2348 case AV_SPHERICAL_EQUIRECTANGULAR:
2349 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2350 avio_wb32(pb, 28); /* size */
2351 ffio_wfourcc(pb, "equi");
2352 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2353 avio_wb32(pb, spherical_mapping->bound_top);
2354 avio_wb32(pb, spherical_mapping->bound_bottom);
2355 avio_wb32(pb, spherical_mapping->bound_left);
2356 avio_wb32(pb, spherical_mapping->bound_right);
2357 break;
2358 case AV_SPHERICAL_CUBEMAP:
2359 avio_wb32(pb, 20); /* size */
2360 ffio_wfourcc(pb, "cbmp");
2361 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2362 avio_wb32(pb, 0); /* layout */
2363 avio_wb32(pb, spherical_mapping->padding); /* padding */
2364 break;
2365 }
2366 update_size(pb, proj_pos);
2367
2368 return update_size(pb, sv3d_pos);
2369 }
2370
2371 5 static inline int64_t rescale_rational(AVRational q, int b)
2372 {
2373 5 return av_rescale(q.num, b, q.den);
2374 }
2375
2376 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2377 const AVStereo3D *stereo3d)
2378 {
2379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2380 return;
2381
2382 1 avio_wb32(pb, 12); /* size */
2383 1 ffio_wfourcc(pb, "hfov");
2384 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2385 }
2386
2387 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2388 const AVSphericalMapping *spherical_mapping)
2389 {
2390 1 avio_wb32(pb, 24); /* size */
2391 1 ffio_wfourcc(pb, "proj");
2392 1 avio_wb32(pb, 16); /* size */
2393 1 ffio_wfourcc(pb, "prji");
2394 1 avio_wb32(pb, 0); /* version + flags */
2395
2396
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) {
2397 1 case AV_SPHERICAL_RECTILINEAR:
2398 1 ffio_wfourcc(pb, "rect");
2399 1 break;
2400 case AV_SPHERICAL_EQUIRECTANGULAR:
2401 ffio_wfourcc(pb, "equi");
2402 break;
2403 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2404 ffio_wfourcc(pb, "hequ");
2405 break;
2406 case AV_SPHERICAL_FISHEYE:
2407 ffio_wfourcc(pb, "fish");
2408 break;
2409 default:
2410 av_assert0(0);
2411 }
2412 1 }
2413
2414 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2415 const AVStereo3D *stereo3d)
2416 {
2417 1 int64_t pos = avio_tell(pb);
2418 1 int view = 0;
2419
2420 1 avio_wb32(pb, 0); /* size */
2421 1 ffio_wfourcc(pb, "eyes");
2422
2423 // stri is mandatory
2424 1 avio_wb32(pb, 13); /* size */
2425 1 ffio_wfourcc(pb, "stri");
2426 1 avio_wb32(pb, 0); /* version + flags */
2427
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2428 case AV_STEREO3D_VIEW_LEFT:
2429 view |= 1 << 0;
2430 break;
2431 case AV_STEREO3D_VIEW_RIGHT:
2432 view |= 1 << 1;
2433 break;
2434 1 case AV_STEREO3D_VIEW_PACKED:
2435 1 view |= (1 << 0) | (1 << 1);
2436 1 break;
2437 }
2438 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2439 1 avio_w8(pb, view);
2440
2441 // hero is optional
2442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2443 avio_wb32(pb, 13); /* size */
2444 ffio_wfourcc(pb, "hero");
2445 avio_wb32(pb, 0); /* version + flags */
2446 avio_w8(pb, stereo3d->primary_eye);
2447 }
2448
2449 // it's not clear if cams is mandatory or optional
2450
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2451 1 avio_wb32(pb, 24); /* size */
2452 1 ffio_wfourcc(pb, "cams");
2453 1 avio_wb32(pb, 16); /* size */
2454 1 ffio_wfourcc(pb, "blin");
2455 1 avio_wb32(pb, 0); /* version + flags */
2456 1 avio_wb32(pb, stereo3d->baseline);
2457 }
2458
2459 // it's not clear if cmfy is mandatory or optional
2460
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2461 1 avio_wb32(pb, 24); /* size */
2462 1 ffio_wfourcc(pb, "cmfy");
2463 1 avio_wb32(pb, 16); /* size */
2464 1 ffio_wfourcc(pb, "dadj");
2465 1 avio_wb32(pb, 0); /* version + flags */
2466 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2467 }
2468
2469 1 return update_size(pb, pos);
2470 }
2471
2472 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2473 const AVStereo3D *stereo3d,
2474 const AVSphericalMapping *spherical_mapping)
2475 {
2476 int64_t pos;
2477
2478
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2480 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2481 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2482 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2483 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2484 spherical_mapping->projection);
2485 spherical_mapping = NULL;
2486 }
2487
2488
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2489
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2491 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2492 !stereo3d->baseline &&
2493 !stereo3d->horizontal_disparity_adjustment.num))) {
2494 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2495 stereo3d = NULL;
2496 }
2497
2498
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2499 return 0;
2500
2501 1 pos = avio_tell(pb);
2502 1 avio_wb32(pb, 0); /* size */
2503 1 ffio_wfourcc(pb, "vexu");
2504
2505
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2506 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2507
2508
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2509 1 mov_write_eyes_tag(s, pb, stereo3d);
2510
2511 1 return update_size(pb, pos);
2512 }
2513
2514 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2515 {
2516 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2517
2518 avio_wb32(pb, 32); /* size = 8 + 24 */
2519 if (dovi->dv_profile > 10)
2520 ffio_wfourcc(pb, "dvwC");
2521 else if (dovi->dv_profile > 7)
2522 ffio_wfourcc(pb, "dvvC");
2523 else
2524 ffio_wfourcc(pb, "dvcC");
2525
2526 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2527 avio_write(pb, buf, sizeof(buf));
2528
2529 return 32; /* 8 + 24 */
2530 }
2531
2532 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2533 uint32_t top, uint32_t bottom,
2534 uint32_t left, uint32_t right)
2535 {
2536 5 uint32_t cropped_width = track->par->width - left - right;
2537 5 uint32_t cropped_height = track->height - top - bottom;
2538 AVRational horizOff =
2539 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2540 5 (AVRational) { left, 1 });
2541 AVRational vertOff =
2542 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2543 5 (AVRational) { top, 1 });
2544
2545 5 avio_wb32(pb, 40);
2546 5 ffio_wfourcc(pb, "clap");
2547 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2548 5 avio_wb32(pb, 1); /* apertureWidthD */
2549 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2550 5 avio_wb32(pb, 1); /* apertureHeightD */
2551
2552 5 avio_wb32(pb, -horizOff.num);
2553 5 avio_wb32(pb, horizOff.den);
2554 5 avio_wb32(pb, -vertOff.num);
2555 5 avio_wb32(pb, vertOff.den);
2556
2557 5 return 40;
2558 }
2559
2560 14 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2561 {
2562 AVRational sar;
2563 14 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2564 14 track->par->sample_aspect_ratio.den, INT_MAX);
2565
2566 14 avio_wb32(pb, 16);
2567 14 ffio_wfourcc(pb, "pasp");
2568 14 avio_wb32(pb, sar.num);
2569 14 avio_wb32(pb, sar.den);
2570 14 return 16;
2571 }
2572
2573 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2574 {
2575 uint32_t gama = 0;
2576 if (gamma <= 0.0)
2577 gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2578 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2579
2580 if (gamma > 1e-6) {
2581 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2582 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2583
2584 av_assert0(track->mode == MODE_MOV);
2585 avio_wb32(pb, 12);
2586 ffio_wfourcc(pb, "gama");
2587 avio_wb32(pb, gama);
2588 return 12;
2589 } else {
2590 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2591 }
2592 return 0;
2593 }
2594
2595 10 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2596 {
2597 10 int64_t pos = avio_tell(pb);
2598
2599 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2600 // Ref (MP4): ISO/IEC 14496-12:2012
2601
2602
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if (prefer_icc) {
2603 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2604 4 track->st->codecpar->nb_coded_side_data,
2605 AV_PKT_DATA_ICC_PROFILE);
2606
2607
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2608 avio_wb32(pb, 12 + sd->size);
2609 ffio_wfourcc(pb, "colr");
2610 ffio_wfourcc(pb, "prof");
2611 avio_write(pb, sd->data, sd->size);
2612 return 12 + sd->size;
2613 }
2614 else {
2615 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2616 }
2617 }
2618
2619 /* We should only ever be called for MOV, MP4 and AVIF. */
2620
3/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2621 track->mode == MODE_AVIF);
2622
2623 10 avio_wb32(pb, 0); /* size */
2624 10 ffio_wfourcc(pb, "colr");
2625
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
10 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2626 2 ffio_wfourcc(pb, "nclx");
2627 else
2628 8 ffio_wfourcc(pb, "nclc");
2629 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2630 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2631 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2632 10 avio_wb16(pb, track->par->color_primaries);
2633 10 avio_wb16(pb, track->par->color_trc);
2634 10 avio_wb16(pb, track->par->color_space);
2635
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
10 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2636 2 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2637 2 avio_w8(pb, full_range << 7);
2638 }
2639
2640 10 return update_size(pb, pos);
2641 }
2642
2643 211 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2644 {
2645 const AVPacketSideData *side_data;
2646 const AVContentLightMetadata *content_light_metadata;
2647
2648 211 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2649 211 track->st->codecpar->nb_coded_side_data,
2650 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2651
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 if (!side_data) {
2652 211 return 0;
2653 }
2654 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2655
2656 avio_wb32(pb, 12); // size
2657 ffio_wfourcc(pb, "clli");
2658 avio_wb16(pb, content_light_metadata->MaxCLL);
2659 avio_wb16(pb, content_light_metadata->MaxFALL);
2660 return 12;
2661 }
2662
2663 211 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2664 {
2665 211 const int chroma_den = 50000;
2666 211 const int luma_den = 10000;
2667 const AVPacketSideData *side_data;
2668 211 const AVMasteringDisplayMetadata *metadata = NULL;
2669
2670 211 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2671 211 track->st->codecpar->nb_coded_side_data,
2672 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (side_data)
2674 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2675
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
211 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2676 211 return 0;
2677 }
2678
2679 avio_wb32(pb, 32); // size
2680 ffio_wfourcc(pb, "mdcv");
2681 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2682 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2683 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2684 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2685 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2686 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2687 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2688 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2689 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2690 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2691 return 32;
2692 }
2693
2694 211 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2695 {
2696 211 const int illuminance_den = 10000;
2697 211 const int ambient_den = 50000;
2698 const AVPacketSideData *side_data;
2699 const AVAmbientViewingEnvironment *ambient;
2700
2701
2702 211 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2703 211 track->st->codecpar->nb_coded_side_data,
2704 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2705
2706
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 1 times.
211 if (!side_data)
2707 210 return 0;
2708
2709 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2710
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)
2711 return 0;
2712
2713 1 avio_wb32(pb, 16); // size
2714 1 ffio_wfourcc(pb, "amve");
2715 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2716 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2717 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2718 1 return 16;
2719 }
2720
2721 217 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2722 {
2723 AVDictionaryEntry *encoder;
2724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2725
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
216 || (track->par->width == 1440 && track->par->height == 1080)
2726
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 203 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
434 || (track->par->width == 1920 && track->par->height == 1080);
2727
2728
1/2
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
217 if ((track->mode == MODE_AVIF ||
2729
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 143 times.
217 track->mode == MODE_MOV ||
2730
4/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 59 times.
285 track->mode == MODE_MP4) &&
2731 211 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2732 152 av_strlcpy(compressor_name, encoder->value, 32);
2733
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
65 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2734 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2735 AVStream *st = track->st;
2736 int rate = defined_frame_rate(NULL, st);
2737 av_strlcatf(compressor_name, len, "XDCAM");
2738 if (track->par->format == AV_PIX_FMT_YUV422P) {
2739 av_strlcatf(compressor_name, len, " HD422");
2740 } else if(track->par->width == 1440) {
2741 av_strlcatf(compressor_name, len, " HD");
2742 } else
2743 av_strlcatf(compressor_name, len, " EX");
2744
2745 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2746
2747 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2748 }
2749 217 }
2750
2751 static int mov_write_ccst_tag(AVIOContext *pb)
2752 {
2753 int64_t pos = avio_tell(pb);
2754 // Write sane defaults:
2755 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2756 // intra_pred_used = 1 : intra prediction may or may not be used.
2757 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2758 // reference images can be used.
2759 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2760 (1 << 6) | /* intra_pred_used */
2761 (15 << 2); /* max_ref_per_pic */
2762 avio_wb32(pb, 0); /* size */
2763 ffio_wfourcc(pb, "ccst");
2764 avio_wb32(pb, 0); /* Version & flags */
2765 avio_w8(pb, ccstValue);
2766 avio_wb24(pb, 0); /* reserved */
2767 return update_size(pb, pos);
2768 }
2769
2770 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2771 {
2772 int64_t pos = avio_tell(pb);
2773 avio_wb32(pb, 0); /* size */
2774 ffio_wfourcc(pb, aux_type);
2775 avio_wb32(pb, 0); /* Version & flags */
2776 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2777 return update_size(pb, pos);
2778 }
2779
2780 217 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2781 {
2782 217 int ret = AVERROR_BUG;
2783 217 int64_t pos = avio_tell(pb);
2784 const AVPacketSideData *sd;
2785 217 char compressor_name[32] = { 0 };
2786 217 int avid = 0;
2787
2788
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)
2789
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
217 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2790
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
217 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2791
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
217 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2792
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
217 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2793 #if FF_API_V408_CODECID
2794
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 || track->par->codec_id == AV_CODEC_ID_V308
2795
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 || track->par->codec_id == AV_CODEC_ID_V408
2796
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 || track->par->codec_id == AV_CODEC_ID_V410
2797 #endif
2798
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 213 times.
434 || track->par->codec_id == AV_CODEC_ID_V210);
2799
2800 217 avio_wb32(pb, 0); /* size */
2801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 if (mov->encryption_scheme != MOV_ENC_NONE) {
2802 ffio_wfourcc(pb, "encv");
2803 } else {
2804 217 avio_wl32(pb, track->tag); // store it byteswapped
2805 }
2806 217 avio_wb32(pb, 0); /* Reserved */
2807 217 avio_wb16(pb, 0); /* Reserved */
2808 217 avio_wb16(pb, 1); /* Data-reference index */
2809
2810
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 213 times.
217 if (uncompressed_ycbcr) {
2811 4 avio_wb16(pb, 2); /* Codec stream version */
2812 } else {
2813 213 avio_wb16(pb, 0); /* Codec stream version */
2814 }
2815 217 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2816
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 74 times.
217 if (track->mode == MODE_MOV) {
2817 143 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2818
3/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
143 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2819 17 avio_wb32(pb, 0); /* Temporal Quality */
2820 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2821 } else {
2822 126 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2823 126 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2824 }
2825 } else {
2826 74 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2827 }
2828 217 avio_wb16(pb, track->par->width); /* Video width */
2829 217 avio_wb16(pb, track->height); /* Video height */
2830 217 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2831 217 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2832 217 avio_wb32(pb, 0); /* Data size (= 0) */
2833 217 avio_wb16(pb, 1); /* Frame count (= 1) */
2834
2835 217 find_compressor(compressor_name, 32, track);
2836 217 avio_w8(pb, strlen(compressor_name));
2837 217 avio_write(pb, compressor_name, 31);
2838
2839
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 74 times.
217 if (track->mode == MODE_MOV &&
2840
2/4
✓ Branch 0 taken 143 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 143 times.
143 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2841 avio_wb16(pb, 0x18);
2842
4/4
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 110 times.
217 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2843 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2844
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2845 else
2846 184 avio_wb16(pb, 0x18); /* Reserved */
2847
2848
4/4
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 138 times.
222 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2849 int pal_size, i;
2850 5 avio_wb16(pb, 0); /* Color table ID */
2851 5 avio_wb32(pb, 0); /* Color table seed */
2852 5 avio_wb16(pb, 0x8000); /* Color table flags */
2853
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)
2854 return AVERROR(EINVAL);
2855 5 pal_size = 1 << track->par->bits_per_coded_sample;
2856 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2857
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2858 1040 uint32_t rgb = track->palette[i];
2859 1040 uint16_t r = (rgb >> 16) & 0xff;
2860 1040 uint16_t g = (rgb >> 8) & 0xff;
2861 1040 uint16_t b = rgb & 0xff;
2862 1040 avio_wb16(pb, 0);
2863 1040 avio_wb16(pb, (r << 8) | r);
2864 1040 avio_wb16(pb, (g << 8) | g);
2865 1040 avio_wb16(pb, (b << 8) | b);
2866 }
2867 } else
2868 212 avio_wb16(pb, 0xffff); /* Reserved */
2869
2870
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 188 times.
217 if (track->tag == MKTAG('m','p','4','v'))
2871 29 mov_write_esds_tag(pb, track);
2872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
188 else if (track->par->codec_id == AV_CODEC_ID_H263)
2873 mov_write_d263_tag(pb);
2874
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 3 times.
188 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2876 3 mov_write_extradata_tag(pb, track);
2877 3 avio_wb32(pb, 0);
2878
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 162 times.
185 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2879 23 mov_write_avid_tag(pb, track);
2880 23 avid = 1;
2881
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 156 times.
162 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2882 6 mov_write_hvcc_tag(mov->fc, pb, track);
2883
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2884 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2886 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2887 }
2888
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 155 times.
156 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2889 1 mov_write_vvcc_tag(pb, track);
2890
16/30
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 55 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 55 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 55 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 55 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 55 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 55 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 55 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 55 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 55 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 55 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 55 times.
✗ Branch 29 not taken.
155 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2891 55 mov_write_avcc_tag(pb, track);
2892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (track->mode == MODE_IPOD)
2893 mov_write_uuid_tag_ipod(pb);
2894 }
2895
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2896 1 mov_write_evcc_tag(pb, track);
2897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_LCEVC) {
2898 mov_write_lvcc_tag(pb, track);
2899
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 98 times.
99 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2900 1 mov_write_apvc_tag(mov->fc, pb, track);
2901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2902 mov_write_vpcc_tag(mov->fc, pb, track);
2903
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2904 1 mov_write_av1c_tag(pb, track);
2905
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)
2906 mov_write_dvc1_tag(pb, track);
2907
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2908
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2909 /* Don't write any potential extradata here - the cropping
2910 * is signalled via the normal width/height fields. */
2911
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2912 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2913 mov_write_dpxe_tag(pb, track);
2914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2915 mov_write_av3c_tag(pb, track);
2916
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
2917 4 mov_write_glbl_tag(pb, track);
2918
2919
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 55 times.
217 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2920
2/2
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 25 times.
162 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2921
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 23 times.
137 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2922 114 int field_order = track->par->field_order;
2923
2924
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 15 times.
114 if (field_order != AV_FIELD_UNKNOWN)
2925 99 mov_write_fiel_tag(pb, track, field_order);
2926 }
2927
2928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2929 if (track->mode == MODE_MOV)
2930 mov_write_gama_tag(s, pb, track, mov->gamma);
2931 else
2932 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2933 }
2934
5/6
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
428 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2935 428 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2936
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 205 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
217 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2937
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2938
5/6
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 201 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 201 times.
412 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2939 201 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2940 AV_PKT_DATA_ICC_PROFILE)) {
2941
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 6 times.
10 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2942 10 mov_write_colr_tag(pb, track, prefer_icc);
2943 }
2944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2945 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2946 }
2947
2948
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 6 times.
217 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2949 211 mov_write_clli_tag(pb, track);
2950 211 mov_write_mdcv_tag(pb, track);
2951 211 mov_write_amve_tag(pb, track);
2952 }
2953
2954
3/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 149 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
217 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2955 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2956 track->st->codecpar->nb_coded_side_data,
2957 AV_PKT_DATA_STEREO3D);
2958 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2959 track->st->codecpar->nb_coded_side_data,
2960 AV_PKT_DATA_SPHERICAL);
2961 if (stereo_3d)
2962 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2963 if (spherical_mapping)
2964 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2965 }
2966
2967
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 6 times.
217 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2969 143 const AVStereo3D *stereo3d = NULL;
2970 143 const AVSphericalMapping *spherical_mapping = NULL;
2971
2972 143 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2973 143 track->st->codecpar->nb_coded_side_data,
2974 AV_PKT_DATA_STEREO3D);
2975
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 142 times.
143 if (sd)
2976 1 stereo3d = (AVStereo3D *)sd->data;
2977
2978 143 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2979 143 track->st->codecpar->nb_coded_side_data,
2980 AV_PKT_DATA_SPHERICAL);
2981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 142 times.
143 if (sd)
2982 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2983
2984
3/4
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 142 times.
143 if (stereo3d || spherical_mapping)
2985 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2986
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 142 times.
143 if (stereo3d)
2987 1 mov_write_hfov_tag(s, pb, stereo3d);
2988 }
2989
2990
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 149 times.
217 if (track->mode == MODE_MP4) {
2991 68 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2992 68 track->st->codecpar->nb_coded_side_data,
2993 AV_PKT_DATA_DOVI_CONF);
2994
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
68 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2995 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 } else if (dovi) {
2997 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2998 }
2999 }
3000
3001
3/4
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 203 times.
217 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
3002 14 mov_write_pasp_tag(pb, track);
3003 }
3004
3005 217 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3006 217 track->st->codecpar->nb_coded_side_data,
3007 AV_PKT_DATA_FRAME_CROPPING);
3008
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
218 if (sd && sd->size >= sizeof(uint32_t) * 4) {
3009 1 uint64_t top = AV_RL32(sd->data + 0);
3010 1 uint64_t bottom = AV_RL32(sd->data + 4);
3011 1 uint64_t left = AV_RL32(sd->data + 8);
3012 1 uint64_t right = AV_RL32(sd->data + 12);
3013
3014
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
3015
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
3016 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
3017 return AVERROR(EINVAL);
3018 }
3019
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)
3020 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
3021
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 212 times.
216 } else if (uncompressed_ycbcr)
3022 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
3023
3024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 if (mov->encryption_scheme != MOV_ENC_NONE) {
3025 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
3026 }
3027
3028
3/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 149 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
285 if (mov->write_btrt &&
3029 68 ((ret = mov_write_btrt_tag(pb, track)) < 0))
3030 return ret;
3031
3032 /* extra padding for avid stsd */
3033 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3034
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 194 times.
217 if (avid)
3035 23 avio_wb32(pb, 0);
3036
3037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 if (track->mode == MODE_AVIF) {
3038 mov_write_ccst_tag(pb);
3039 if (mov->nb_streams > 0 && track == &mov->tracks[1])
3040 mov_write_aux_tag(pb, "auxi");
3041 }
3042
3043 217 return update_size(pb, pos);
3044 }
3045
3046 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
3047 {
3048 2 int64_t pos = avio_tell(pb);
3049 2 avio_wb32(pb, 0); /* size */
3050 2 ffio_wfourcc(pb, "rtp ");
3051 2 avio_wb32(pb, 0); /* Reserved */
3052 2 avio_wb16(pb, 0); /* Reserved */
3053 2 avio_wb16(pb, 1); /* Data-reference index */
3054
3055 2 avio_wb16(pb, 1); /* Hint track version */
3056 2 avio_wb16(pb, 1); /* Highest compatible version */
3057 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3058
3059 2 avio_wb32(pb, 12); /* size */
3060 2 ffio_wfourcc(pb, "tims");
3061 2 avio_wb32(pb, track->timescale);
3062
3063 2 return update_size(pb, pos);
3064 }
3065
3066 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3067 {
3068 2 uint64_t str_size =strlen(reel_name);
3069 2 int64_t pos = avio_tell(pb);
3070
3071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3072 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3073 avio_wb16(pb, 0);
3074 return AVERROR(EINVAL);
3075 }
3076
3077 2 avio_wb32(pb, 0); /* size */
3078 2 ffio_wfourcc(pb, "name"); /* Data format */
3079 2 avio_wb16(pb, str_size); /* string size */
3080 2 avio_wb16(pb, track->language); /* langcode */
3081 2 avio_write(pb, reel_name, str_size); /* reel name */
3082 2 return update_size(pb,pos);
3083 }
3084
3085 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3086 {
3087 13 int64_t pos = avio_tell(pb);
3088 #if 1
3089 int frame_duration;
3090 int nb_frames;
3091 13 AVDictionaryEntry *t = NULL;
3092
3093
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) {
3094 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3095 return AVERROR(EINVAL);
3096 } else {
3097 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3098
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);
3099 }
3100
3101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3102 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3103 return AVERROR(EINVAL);
3104 }
3105
3106 13 avio_wb32(pb, 0); /* size */
3107 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3108 13 avio_wb32(pb, 0); /* Reserved */
3109 13 avio_wb32(pb, 1); /* Data reference index */
3110 13 avio_wb32(pb, 0); /* Flags */
3111 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3112 13 avio_wb32(pb, track->timescale); /* Timescale */
3113 13 avio_wb32(pb, frame_duration); /* Frame duration */
3114 13 avio_w8(pb, nb_frames); /* Number of frames */
3115 13 avio_w8(pb, 0); /* Reserved */
3116
3117 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3118
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)
3119 2 mov_write_source_reference_tag(pb, track, t->value);
3120 else
3121 11 avio_wb16(pb, 0); /* zero size */
3122 #else
3123
3124 avio_wb32(pb, 0); /* size */
3125 ffio_wfourcc(pb, "tmcd"); /* Data format */
3126 avio_wb32(pb, 0); /* Reserved */
3127 avio_wb32(pb, 1); /* Data reference index */
3128 if (track->par->extradata_size)
3129 avio_write(pb, track->par->extradata, track->par->extradata_size);
3130 #endif
3131 13 return update_size(pb, pos);
3132 }
3133
3134 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3135 {
3136 1 int64_t pos = avio_tell(pb);
3137 1 avio_wb32(pb, 0); /* size */
3138 1 ffio_wfourcc(pb, "gpmd");
3139 1 avio_wb32(pb, 0); /* Reserved */
3140 1 avio_wb16(pb, 0); /* Reserved */
3141 1 avio_wb16(pb, 1); /* Data-reference index */
3142 1 avio_wb32(pb, 0); /* Reserved */
3143 1 return update_size(pb, pos);
3144 }
3145
3146 350 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3147 {
3148 350 int64_t pos = avio_tell(pb);
3149 350 int ret = 0;
3150 350 avio_wb32(pb, 0); /* size */
3151 350 ffio_wfourcc(pb, "stsd");
3152 350 avio_wb32(pb, 0); /* version & flags */
3153 350 avio_wb32(pb, track->stsd_count);
3154
3155 350 int stsd_index_back = track->last_stsd_index;
3156 350 for (track->last_stsd_index = 0;
3157
2/2
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 350 times.
701 track->last_stsd_index < track->stsd_count;
3158 351 track->last_stsd_index++) {
3159
2/2
✓ Branch 0 taken 217 times.
✓ Branch 1 taken 134 times.
351 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3160 217 ret = mov_write_video_tag(s, pb, mov, track);
3161
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
134 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3162 112 ret = mov_write_audio_tag(s, pb, mov, track);
3163
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3164 6 ret = mov_write_subtitle_tag(s, pb, track);
3165
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3166 2 ret = mov_write_rtp_tag(pb, track);
3167
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3168 13 ret = mov_write_tmcd_tag(pb, track);
3169
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3170 1 ret = mov_write_gpmd_tag(pb, track);
3171
3172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 351 times.
351 if (ret < 0)
3173 return ret;
3174 }
3175
3176 350 track->last_stsd_index = stsd_index_back;
3177
3178 350 return update_size_and_version(pb, pos, track->entry_version);
3179 }
3180
3181 12 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3182 {
3183 12 MOVMuxContext *mov = s->priv_data;
3184 MOVCtts *ctts_entries;
3185 12 uint32_t entries = 0;
3186 uint32_t atom_size;
3187 int i;
3188
3189 12 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!ctts_entries)
3191 return AVERROR(ENOMEM);
3192 12 ctts_entries[0].count = 1;
3193 12 ctts_entries[0].offset = track->cluster[0].cts;
3194
2/2
✓ Branch 0 taken 758 times.
✓ Branch 1 taken 12 times.
770 for (i = 1; i < track->entry; i++) {
3195
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 627 times.
758 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3196 131 ctts_entries[entries].count++; /* compress */
3197 } else {
3198 627 entries++;
3199 627 ctts_entries[entries].offset = track->cluster[i].cts;
3200 627 ctts_entries[entries].count = 1;
3201 }
3202 }
3203 12 entries++; /* last one */
3204 12 atom_size = 16 + (entries * 8);
3205 12 avio_wb32(pb, atom_size); /* size */
3206 12 ffio_wfourcc(pb, "ctts");
3207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3208 avio_w8(pb, 1); /* version */
3209 else
3210 12 avio_w8(pb, 0); /* version */
3211 12 avio_wb24(pb, 0); /* flags */
3212 12 avio_wb32(pb, entries); /* entry count */
3213
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 12 times.
651 for (i = 0; i < entries; i++) {
3214 639 avio_wb32(pb, ctts_entries[i].count);
3215 639 avio_wb32(pb, ctts_entries[i].offset);
3216 }
3217 12 av_free(ctts_entries);
3218 12 return atom_size;
3219 }
3220
3221 /* Time to sample atom */
3222 350 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3223 {
3224 350 MOVStts *stts_entries = NULL;
3225 350 uint32_t entries = -1;
3226 uint32_t atom_size;
3227 int i;
3228
3229
4/4
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 238 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 77 times.
350 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3230 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3232 return AVERROR(ENOMEM);
3233 35 stts_entries[0].count = track->sample_count;
3234 35 stts_entries[0].duration = 1;
3235 35 entries = 1;
3236 } else {
3237
2/2
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 97 times.
315 if (track->entry) {
3238 218 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 if (!stts_entries)
3240 return AVERROR(ENOMEM);
3241 }
3242
2/2
✓ Branch 0 taken 12426 times.
✓ Branch 1 taken 315 times.
12741 for (i = 0; i < track->entry; i++) {
3243 12426 int duration = get_cluster_duration(track, i);
3244 #if CONFIG_IAMFENC
3245
3/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 12376 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
12426 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3246 duration = av_rescale(duration, 48000, track->par->sample_rate);
3247 #endif
3248
4/4
✓ Branch 0 taken 12208 times.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 11778 times.
✓ Branch 3 taken 430 times.
12426 if (i && duration == stts_entries[entries].duration) {
3249 11778 stts_entries[entries].count++; /* compress */
3250 } else {
3251 648 entries++;
3252 648 stts_entries[entries].duration = duration;
3253 648 stts_entries[entries].count = 1;
3254 }
3255 }
3256 315 entries++; /* last one */
3257 }
3258 350 atom_size = 16 + (entries * 8);
3259 350 avio_wb32(pb, atom_size); /* size */
3260 350 ffio_wfourcc(pb, "stts");
3261 350 avio_wb32(pb, 0); /* version & flags */
3262 350 avio_wb32(pb, entries); /* entry count */
3263
2/2
✓ Branch 0 taken 683 times.
✓ Branch 1 taken 350 times.
1033 for (i = 0; i < entries; i++) {
3264 683 avio_wb32(pb, stts_entries[i].count);
3265 683 avio_wb32(pb, stts_entries[i].duration);
3266 }
3267 350 av_free(stts_entries);
3268 350 return atom_size;
3269 }
3270
3271 350 static int mov_write_dref_tag(AVIOContext *pb)
3272 {
3273 350 avio_wb32(pb, 28); /* size */
3274 350 ffio_wfourcc(pb, "dref");
3275 350 avio_wb32(pb, 0); /* version & flags */
3276 350 avio_wb32(pb, 1); /* entry count */
3277
3278 350 avio_wb32(pb, 0xc); /* size */
3279 //FIXME add the alis and rsrc atom
3280 350 ffio_wfourcc(pb, "url ");
3281 350 avio_wb32(pb, 1); /* version & flags */
3282
3283 350 return 28;
3284 }
3285
3286 55 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3287 {
3288 struct sgpd_entry {
3289 int count;
3290 int16_t roll_distance;
3291 int group_description_index;
3292 };
3293
3294 55 struct sgpd_entry *sgpd_entries = NULL;
3295 55 int entries = -1;
3296 55 int group = 0;
3297 int i, j;
3298
3299 55 const int OPUS_SEEK_PREROLL_MS = 80;
3300 55 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3301 55 (AVRational){1, 1000},
3302 55 (AVRational){1, 48000});
3303
3304
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 12 times.
55 if (!track->entry)
3305 43 return 0;
3306
3307 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3309 return AVERROR(ENOMEM);
3310
3311
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3312
3313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3314 for (i = 0; i < track->entry; i++) {
3315 int roll_samples_remaining = roll_samples;
3316 int distance = 0;
3317 for (j = i - 1; j >= 0; j--) {
3318 roll_samples_remaining -= get_cluster_duration(track, j);
3319 distance++;
3320 if (roll_samples_remaining <= 0)
3321 break;
3322 }
3323 /* We don't have enough preceding samples to compute a valid
3324 roll_distance here, so this sample can't be independently
3325 decoded. */
3326 if (roll_samples_remaining > 0)
3327 distance = 0;
3328 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3329 if (distance > 32)
3330 return AVERROR_INVALIDDATA;
3331 if (i && distance == sgpd_entries[entries].roll_distance) {
3332 sgpd_entries[entries].count++;
3333 } else {
3334 entries++;
3335 sgpd_entries[entries].count = 1;
3336 sgpd_entries[entries].roll_distance = distance;
3337 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3338 }
3339 }
3340 } else {
3341 12 entries++;
3342 12 sgpd_entries[entries].count = track->sample_count;
3343 12 sgpd_entries[entries].roll_distance = 1;
3344 12 sgpd_entries[entries].group_description_index = ++group;
3345 }
3346 12 entries++;
3347
3348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3349 av_free(sgpd_entries);
3350 return 0;
3351 }
3352
3353 /* Write sgpd tag */
3354 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3355 12 ffio_wfourcc(pb, "sgpd");
3356 12 avio_wb32(pb, 1 << 24); /* fullbox */
3357 12 ffio_wfourcc(pb, "roll");
3358 12 avio_wb32(pb, 2); /* default_length */
3359 12 avio_wb32(pb, group); /* entry_count */
3360
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3361
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3362 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3363 }
3364 }
3365
3366 /* Write sbgp tag */
3367 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3368 12 ffio_wfourcc(pb, "sbgp");
3369 12 avio_wb32(pb, 0); /* fullbox */
3370 12 ffio_wfourcc(pb, "roll");
3371 12 avio_wb32(pb, entries); /* entry_count */
3372
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3373 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3374 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3375 }
3376
3377 12 av_free(sgpd_entries);
3378 12 return 0;
3379 }
3380
3381 350 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3382 {
3383 350 int64_t pos = avio_tell(pb);
3384 350 int ret = 0;
3385
3386 350 avio_wb32(pb, 0); /* size */
3387 350 ffio_wfourcc(pb, "stbl");
3388
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 350 times.
350 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3389 return ret;
3390 350 mov_write_stts_tag(pb, track);
3391
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 216 times.
350 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3392
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3393
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3394
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
134 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3395
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 132 times.
134 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3396
4/4
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 104 times.
218 track->has_keyframes && track->has_keyframes < track->entry)
3397 62 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3398
5/6
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 213 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
350 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3399 3 mov_write_sdtp_tag(pb, track);
3400
3/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
350 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3401 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3402
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 134 times.
350 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3403
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 22 times.
216 track->flags & MOV_TRACK_CTTS && track->entry) {
3404
3405
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3406 return ret;
3407 }
3408 350 mov_write_stsc_tag(pb, track);
3409 350 mov_write_stsz_tag(pb, track);
3410 350 mov_write_stco_tag(pb, track);
3411
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
350 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3412 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3413 }
3414
3/4
✓ Branch 0 taken 350 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 295 times.
350 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3415 55 mov_preroll_write_stbl_atoms(pb, track);
3416 }
3417 350 return update_size(pb, pos);
3418 }
3419
3420 350 static int mov_write_dinf_tag(AVIOContext *pb)
3421 {
3422 350 int64_t pos = avio_tell(pb);
3423 350 avio_wb32(pb, 0); /* size */
3424 350 ffio_wfourcc(pb, "dinf");
3425 350 mov_write_dref_tag(pb);
3426 350 return update_size(pb, pos);
3427 }
3428
3429 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3430 {
3431 7 avio_wb32(pb, 12);
3432 7 ffio_wfourcc(pb, "nmhd");
3433 7 avio_wb32(pb, 0);
3434 7 return 12;
3435 }
3436
3437 2 static int mov_write_sthd_tag(AVIOContext *pb)
3438 {
3439 2 avio_wb32(pb, 12);
3440 2 ffio_wfourcc(pb, "sthd");
3441 2 avio_wb32(pb, 0);
3442 2 return 12;
3443 }
3444
3445 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3446 {
3447 9 int64_t pos = avio_tell(pb);
3448 9 const char *font = "Lucida Grande";
3449 9 avio_wb32(pb, 0); /* size */
3450 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3451 9 avio_wb32(pb, 0); /* version & flags */
3452 9 avio_wb16(pb, 0); /* text font */
3453 9 avio_wb16(pb, 0); /* text face */
3454 9 avio_wb16(pb, 12); /* text size */
3455 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3456 9 avio_wb16(pb, 0x0000); /* text color (red) */
3457 9 avio_wb16(pb, 0x0000); /* text color (green) */
3458 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3459 9 avio_wb16(pb, 0xffff); /* background color (red) */
3460 9 avio_wb16(pb, 0xffff); /* background color (green) */
3461 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3462 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3463 9 avio_write(pb, font, strlen(font)); /* font name */
3464 9 return update_size(pb, pos);
3465 }
3466
3467 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3468 {
3469 11 int64_t pos = avio_tell(pb);
3470 11 avio_wb32(pb, 0); /* size */
3471 11 ffio_wfourcc(pb, "gmhd");
3472 11 avio_wb32(pb, 0x18); /* gmin size */
3473 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3474 11 avio_wb32(pb, 0); /* version & flags */
3475 11 avio_wb16(pb, 0x40); /* graphics mode = */
3476 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3477 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3478 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3479 11 avio_wb16(pb, 0); /* balance */
3480 11 avio_wb16(pb, 0); /* reserved */
3481
3482 /*
3483 * This special text atom is required for
3484 * Apple Quicktime chapters. The contents
3485 * don't appear to be documented, so the
3486 * bytes are copied verbatim.
3487 */
3488
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3489 11 avio_wb32(pb, 0x2C); /* size */
3490 11 ffio_wfourcc(pb, "text");
3491 11 avio_wb16(pb, 0x01);
3492 11 avio_wb32(pb, 0x00);
3493 11 avio_wb32(pb, 0x00);
3494 11 avio_wb32(pb, 0x00);
3495 11 avio_wb32(pb, 0x01);
3496 11 avio_wb32(pb, 0x00);
3497 11 avio_wb32(pb, 0x00);
3498 11 avio_wb32(pb, 0x00);
3499 11 avio_wb32(pb, 0x00004000);
3500 11 avio_wb16(pb, 0x0000);
3501 }
3502
3503
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3504 9 int64_t tmcd_pos = avio_tell(pb);
3505 9 avio_wb32(pb, 0); /* size */
3506 9 ffio_wfourcc(pb, "tmcd");
3507 9 mov_write_tcmi_tag(pb, track);
3508 9 update_size(pb, tmcd_pos);
3509
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3510 1 int64_t gpmd_pos = avio_tell(pb);
3511 1 avio_wb32(pb, 0); /* size */
3512 1 ffio_wfourcc(pb, "gpmd");
3513 1 avio_wb32(pb, 0); /* version */
3514 1 update_size(pb, gpmd_pos);
3515 }
3516 11 return update_size(pb, pos);
3517 }
3518
3519 112 static int mov_write_smhd_tag(AVIOContext *pb)
3520 {
3521 112 avio_wb32(pb, 16); /* size */
3522 112 ffio_wfourcc(pb, "smhd");
3523 112 avio_wb32(pb, 0); /* version & flags */
3524 112 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3525 112 avio_wb16(pb, 0); /* reserved */
3526 112 return 16;
3527 }
3528
3529 216 static int mov_write_vmhd_tag(AVIOContext *pb)
3530 {
3531 216 avio_wb32(pb, 0x14); /* size (always 0x14) */
3532 216 ffio_wfourcc(pb, "vmhd");
3533 216 avio_wb32(pb, 0x01); /* version & flags */
3534 216 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3535 216 return 0x14;
3536 }
3537
3538 229 static int is_clcp_track(MOVTrack *track)
3539 {
3540
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
458 return track->tag == MKTAG('c','7','0','8') ||
3541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 track->tag == MKTAG('c','6','0','8');
3542 }
3543
3544 542 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3545 {
3546 542 MOVMuxContext *mov = s->priv_data;
3547 542 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3548 542 int64_t pos = avio_tell(pb);
3549 size_t descr_len;
3550
3551 542 hdlr = "dhlr";
3552 542 hdlr_type = "url ";
3553 542 descr = "DataHandler";
3554
3555
2/2
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 192 times.
542 if (track) {
3556
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 158 times.
350 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3557
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 134 times.
350 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (track->mode == MODE_AVIF) {
3559 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3560 descr = "PictureHandler";
3561 } else {
3562 216 hdlr_type = "vide";
3563 216 descr = "VideoHandler";
3564 }
3565
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
134 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3566 112 hdlr_type = "soun";
3567 112 descr = "SoundHandler";
3568
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3569
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3570 hdlr_type = "clcp";
3571 descr = "ClosedCaptionHandler";
3572 } else {
3573
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3574 1 hdlr_type = "sbtl";
3575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3576 hdlr_type = "subp";
3577
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3578 2 hdlr_type = "subt";
3579 } else {
3580 3 hdlr_type = "text";
3581 }
3582 6 descr = "SubtitleHandler";
3583 }
3584
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3585 2 hdlr_type = "hint";
3586 2 descr = "HintHandler";
3587
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3588 13 hdlr_type = "tmcd";
3589 13 descr = "TimeCodeHandler";
3590
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3591 1 hdlr_type = "meta";
3592 1 descr = "GoPro MET"; // GoPro Metadata
3593 } else {
3594 av_log(s, AV_LOG_WARNING,
3595 "Unknown hdlr_type for %s, writing dummy values\n",
3596 av_fourcc2str(track->par->codec_tag));
3597 }
3598
2/2
✓ Branch 0 taken 347 times.
✓ Branch 1 taken 3 times.
350 if (track->st) {
3599 // hdlr.name is used by some players to identify the content title
3600 // of the track. So if an alternate handler description is
3601 // specified, use it.
3602 AVDictionaryEntry *t;
3603 347 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3604
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 321 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
347 if (t && utf8len(t->value))
3605 26 descr = t->value;
3606 }
3607 }
3608
3609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 542 times.
542 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3610 descr = "";
3611
3612 542 avio_wb32(pb, 0); /* size */
3613 542 ffio_wfourcc(pb, "hdlr");
3614 542 avio_wb32(pb, 0); /* Version & flags */
3615 542 avio_write(pb, hdlr, 4); /* handler */
3616 542 ffio_wfourcc(pb, hdlr_type); /* handler type */
3617 542 avio_wb32(pb, 0); /* reserved */
3618 542 avio_wb32(pb, 0); /* reserved */
3619 542 avio_wb32(pb, 0); /* reserved */
3620 542 descr_len = strlen(descr);
3621
4/4
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 158 times.
542 if (!track || track->mode == MODE_MOV)
3622 384 avio_w8(pb, descr_len); /* pascal string */
3623 542 avio_write(pb, descr, descr_len); /* handler description */
3624
4/4
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 158 times.
✓ Branch 3 taken 192 times.
542 if (track && track->mode != MODE_MOV)
3625 158 avio_w8(pb, 0); /* c string */
3626 542 return update_size(pb, pos);
3627 }
3628
3629 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3630 {
3631 int64_t pos = avio_tell(pb);
3632 avio_wb32(pb, 0); /* size */
3633 ffio_wfourcc(pb, "pitm");
3634 avio_wb32(pb, 0); /* Version & flags */
3635 avio_wb16(pb, item_id); /* item_id */
3636 return update_size(pb, pos);
3637 }
3638
3639 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3640 {
3641 int64_t pos = avio_tell(pb);
3642 avio_wb32(pb, 0); /* size */
3643 ffio_wfourcc(pb, "iloc");
3644 avio_wb32(pb, 0); /* Version & flags */
3645 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3646 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3647 avio_wb16(pb, mov->nb_streams); /* item_count */
3648
3649 for (int i = 0; i < mov->nb_streams; i++) {
3650 avio_wb16(pb, i + 1); /* item_id */
3651 avio_wb16(pb, 0); /* data_reference_index */
3652 avio_wb16(pb, 1); /* extent_count */
3653 mov->avif_extent_pos[i] = avio_tell(pb);
3654 avio_wb32(pb, 0); /* extent_offset (written later) */
3655 // For animated AVIF, we simply write the first packet's size.
3656 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3657 }
3658
3659 return update_size(pb, pos);
3660 }
3661
3662 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3663 {
3664 int64_t iinf_pos = avio_tell(pb);
3665 avio_wb32(pb, 0); /* size */
3666 ffio_wfourcc(pb, "iinf");
3667 avio_wb32(pb, 0); /* Version & flags */
3668 avio_wb16(pb, mov->nb_streams); /* entry_count */
3669
3670 for (int i = 0; i < mov->nb_streams; i++) {
3671 int64_t infe_pos = avio_tell(pb);
3672 avio_wb32(pb, 0); /* size */
3673 ffio_wfourcc(pb, "infe");
3674 avio_w8(pb, 0x2); /* Version */
3675 avio_wb24(pb, 0); /* flags */
3676 avio_wb16(pb, i + 1); /* item_id */
3677 avio_wb16(pb, 0); /* item_protection_index */
3678 avio_write(pb, "av01", 4); /* item_type */
3679 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3680 update_size(pb, infe_pos);
3681 }
3682
3683 return update_size(pb, iinf_pos);
3684 }
3685
3686
3687 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3688 {
3689 int64_t auxl_pos;
3690 int64_t iref_pos = avio_tell(pb);
3691 avio_wb32(pb, 0); /* size */
3692 ffio_wfourcc(pb, "iref");
3693 avio_wb32(pb, 0); /* Version & flags */
3694
3695 auxl_pos = avio_tell(pb);
3696 avio_wb32(pb, 0); /* size */
3697 ffio_wfourcc(pb, "auxl");
3698 avio_wb16(pb, 2); /* from_item_ID */
3699 avio_wb16(pb, 1); /* reference_count */
3700 avio_wb16(pb, 1); /* to_item_ID */
3701 update_size(pb, auxl_pos);
3702
3703 return update_size(pb, iref_pos);
3704 }
3705
3706 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3707 int stream_index)
3708 {
3709 int64_t pos = avio_tell(pb);
3710 avio_wb32(pb, 0); /* size */
3711 ffio_wfourcc(pb, "ispe");
3712 avio_wb32(pb, 0); /* Version & flags */
3713 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3714 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3715 return update_size(pb, pos);
3716 }
3717
3718 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3719 int stream_index)
3720 {
3721 int64_t pos = avio_tell(pb);
3722 const AVPixFmtDescriptor *pixdesc =
3723 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3724 avio_wb32(pb, 0); /* size */
3725 ffio_wfourcc(pb, "pixi");
3726 avio_wb32(pb, 0); /* Version & flags */
3727 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3728 for (int i = 0; i < pixdesc->nb_components; ++i) {
3729 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3730 }
3731 return update_size(pb, pos);
3732 }
3733
3734 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3735 {
3736 int64_t pos = avio_tell(pb);
3737 avio_wb32(pb, 0); /* size */
3738 ffio_wfourcc(pb, "ipco");
3739 for (int i = 0; i < mov->nb_streams; i++) {
3740 mov_write_ispe_tag(pb, mov, s, i);
3741 mov_write_pixi_tag(pb, mov, s, i);
3742 mov_write_av1c_tag(pb, &mov->tracks[i]);
3743 if (!i)
3744 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3745 else
3746 mov_write_aux_tag(pb, "auxC");
3747 }
3748 return update_size(pb, pos);
3749 }
3750
3751 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3752 {
3753 int64_t pos = avio_tell(pb);
3754 avio_wb32(pb, 0); /* size */
3755 ffio_wfourcc(pb, "ipma");
3756 avio_wb32(pb, 0); /* Version & flags */
3757 avio_wb32(pb, mov->nb_streams); /* entry_count */
3758
3759 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3760 avio_wb16(pb, i + 1); /* item_ID */
3761 avio_w8(pb, 4); /* association_count */
3762
3763 // ispe association.
3764 avio_w8(pb, index++); /* essential and property_index */
3765 // pixi association.
3766 avio_w8(pb, index++); /* essential and property_index */
3767 // av1C association.
3768 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3769 // colr/auxC association.
3770 avio_w8(pb, index++); /* essential and property_index */
3771 }
3772 return update_size(pb, pos);
3773 }
3774
3775 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3776 {
3777 int64_t pos = avio_tell(pb);
3778 avio_wb32(pb, 0); /* size */
3779 ffio_wfourcc(pb, "iprp");
3780 mov_write_ipco_tag(pb, mov, s);
3781 mov_write_ipma_tag(pb, mov, s);
3782 return update_size(pb, pos);
3783 }
3784
3785 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3786 {
3787 /* This atom must be present, but leaving the values at zero
3788 * seems harmless. */
3789 2 avio_wb32(pb, 28); /* size */
3790 2 ffio_wfourcc(pb, "hmhd");
3791 2 avio_wb32(pb, 0); /* version, flags */
3792 2 avio_wb16(pb, 0); /* maxPDUsize */
3793 2 avio_wb16(pb, 0); /* avgPDUsize */
3794 2 avio_wb32(pb, 0); /* maxbitrate */
3795 2 avio_wb32(pb, 0); /* avgbitrate */
3796 2 avio_wb32(pb, 0); /* reserved */
3797 2 return 28;
3798 }
3799
3800 350 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3801 {
3802 350 int64_t pos = avio_tell(pb);
3803 int ret;
3804
3805 350 avio_wb32(pb, 0); /* size */
3806 350 ffio_wfourcc(pb, "minf");
3807
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 134 times.
350 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3808 216 mov_write_vmhd_tag(pb);
3809
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
134 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3810 112 mov_write_smhd_tag(pb);
3811
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3812
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)) {
3813 1 mov_write_gmhd_tag(pb, track);
3814
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3815 2 mov_write_sthd_tag(pb);
3816 } else {
3817 3 mov_write_nmhd_tag(pb);
3818 }
3819
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3820 2 mov_write_hmhd_tag(pb);
3821
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3822
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3823 4 mov_write_nmhd_tag(pb);
3824 else
3825 9 mov_write_gmhd_tag(pb, track);
3826
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3827 1 mov_write_gmhd_tag(pb, track);
3828 }
3829
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 158 times.
350 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3830 192 mov_write_hdlr_tag(s, pb, NULL);
3831 350 mov_write_dinf_tag(pb);
3832
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 350 times.
350 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3833 return ret;
3834 350 return update_size(pb, pos);
3835 }
3836
3837 1348 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3838 int64_t *start, int64_t *end, int elst)
3839 {
3840
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1298 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1348 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3841 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3842 // another track's duration, while the end_pts may be left at zero.
3843 // Calculate the pts duration for that track instead.
3844 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end, elst);
3845 38 *start = av_rescale(*start, track->timescale,
3846 38 mov->tracks[track->src_track].timescale);
3847 38 *end = av_rescale(*end, track->timescale,
3848 38 mov->tracks[track->src_track].timescale);
3849 38 return;
3850 }
3851
2/2
✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 70 times.
1310 if (track->end_pts != AV_NOPTS_VALUE &&
3852
1/2
✓ Branch 0 taken 1240 times.
✗ Branch 1 not taken.
1240 track->start_dts != AV_NOPTS_VALUE &&
3853
1/2
✓ Branch 0 taken 1240 times.
✗ Branch 1 not taken.
1240 track->start_cts != AV_NOPTS_VALUE) {
3854 1240 *start = track->start_dts + track->start_cts;
3855
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 948 times.
1240 *end = elst ? track->elst_end_pts : track->end_pts;
3856 1240 return;
3857 }
3858 70 *start = 0;
3859 70 *end = track->track_duration;
3860 }
3861
3862 350 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3863 {
3864 int64_t start, end;
3865 350 get_pts_range(mov, track, &start, &end, 0);
3866 350 return end - start;
3867 }
3868
3869 // Calculate the actual duration of the track, after edits.
3870 // If it starts with a pts < 0, that is removed by the edit list.
3871 // If it starts with a pts > 0, the edit list adds a delay before that.
3872 // Thus, with edit lists enabled, the post-edit output of the file is
3873 // starting with pts=0.
3874 668 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3875 {
3876 int64_t start, end;
3877 668 get_pts_range(mov, track, &start, &end, 0);
3878
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 78 times.
668 if (mov->use_editlist != 0)
3879 590 start = 0;
3880 668 return end - start;
3881 }
3882
3883 292 static int64_t calc_elst_duration(MOVMuxContext *mov, MOVTrack *track)
3884 {
3885 int64_t start, end;
3886 292 get_pts_range(mov, track, &start, &end, 1);
3887 292 return end - start;
3888 }
3889
3890 949 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3891 {
3892
4/4
✓ Branch 0 taken 700 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 682 times.
949 if (track && track->mode == MODE_ISM)
3893 18 return 1;
3894
2/2
✓ Branch 0 taken 927 times.
✓ Branch 1 taken 4 times.
931 if (duration < INT32_MAX)
3895 927 return 0;
3896 4 return 1;
3897 }
3898
3899 350 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3900 MOVTrack *track)
3901 {
3902 350 int64_t duration = calc_samples_pts_duration(mov, track);
3903 350 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3904
3905
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 337 times.
350 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3906 350 ffio_wfourcc(pb, "mdhd");
3907 350 avio_w8(pb, version);
3908 350 avio_wb24(pb, 0); /* flags */
3909
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 337 times.
350 if (version == 1) {
3910 13 avio_wb64(pb, track->time);
3911 13 avio_wb64(pb, track->time);
3912 } else {
3913 337 avio_wb32(pb, track->time); /* creation time */
3914 337 avio_wb32(pb, track->time); /* modification time */
3915 }
3916 350 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3917
4/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 89 times.
350 if (!track->entry && mov->mode == MODE_ISM)
3918
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3919
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 252 times.
341 else if (!track->entry)
3920
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 85 times.
89 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3921 else
3922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3923 350 avio_wb16(pb, track->language); /* language */
3924 350 avio_wb16(pb, 0); /* reserved (quality) */
3925
3926
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
350 if (version != 0 && track->mode == MODE_MOV) {
3927 av_log(NULL, AV_LOG_ERROR,
3928 "FATAL error, file duration too long for timebase, this file will not be\n"
3929 "playable with QuickTime. Choose a different timebase with "
3930 "-video_track_timescale or a different container format\n");
3931 }
3932
3933 350 return 32;
3934 }
3935
3936 350 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3937 MOVMuxContext *mov, MOVTrack *track)
3938 {
3939 350 int64_t pos = avio_tell(pb);
3940 int ret;
3941
3942 350 avio_wb32(pb, 0); /* size */
3943 350 ffio_wfourcc(pb, "mdia");
3944 350 mov_write_mdhd_tag(pb, mov, track);
3945 350 mov_write_hdlr_tag(s, pb, track);
3946
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 350 times.
350 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3947 return ret;
3948 350 return update_size(pb, pos);
3949 }
3950
3951 /* transformation matrix
3952 |a b u|
3953 |c d v|
3954 |tx ty w| */
3955 598 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3956 int16_t d, int16_t tx, int16_t ty)
3957 {
3958 598 avio_wb32(pb, a << 16); /* 16.16 format */
3959 598 avio_wb32(pb, b << 16); /* 16.16 format */
3960 598 avio_wb32(pb, 0); /* u in 2.30 format */
3961 598 avio_wb32(pb, c << 16); /* 16.16 format */
3962 598 avio_wb32(pb, d << 16); /* 16.16 format */
3963 598 avio_wb32(pb, 0); /* v in 2.30 format */
3964 598 avio_wb32(pb, tx << 16); /* 16.16 format */
3965 598 avio_wb32(pb, ty << 16); /* 16.16 format */
3966 598 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3967 598 }
3968
3969 350 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3970 MOVTrack *track, AVStream *st)
3971 {
3972 700 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3973 350 mov->movie_timescale, track->timescale,
3974 AV_ROUND_UP);
3975 int version;
3976 350 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3977 350 int group = 0;
3978
3979 350 uint32_t *display_matrix = NULL;
3980 int i;
3981
3982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (mov->mode == MODE_AVIF)
3983 if (!mov->avif_loop_count)
3984 duration = INT64_MAX;
3985 else
3986 duration *= mov->avif_loop_count;
3987
3988
2/2
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 13 times.
350 if (st) {
3989 const AVPacketSideData *sd;
3990
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 335 times.
337 if (mov->per_stream_grouping)
3991 2 group = st->index;
3992 else
3993 335 group = st->codecpar->codec_type;
3994
3995 337 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3996 337 st->codecpar->nb_coded_side_data,
3997 AV_PKT_DATA_DISPLAYMATRIX);
3998
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 336 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
337 if (sd && sd->size == 9 * sizeof(*display_matrix))
3999 1 display_matrix = (uint32_t *)sd->data;
4000 }
4001
4002
2/2
✓ Branch 0 taken 325 times.
✓ Branch 1 taken 25 times.
350 if (track->flags & MOV_TRACK_ENABLED)
4003 325 flags |= MOV_TKHD_FLAG_ENABLED;
4004
4005 350 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4006
4007
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 341 times.
350 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
4008 350 ffio_wfourcc(pb, "tkhd");
4009 350 avio_w8(pb, version);
4010 350 avio_wb24(pb, flags);
4011
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 341 times.
350 if (version == 1) {
4012 9 avio_wb64(pb, track->time);
4013 9 avio_wb64(pb, track->time);
4014 } else {
4015 341 avio_wb32(pb, track->time); /* creation time */
4016 341 avio_wb32(pb, track->time); /* modification time */
4017 }
4018 350 avio_wb32(pb, track->track_id); /* track-id */
4019 350 avio_wb32(pb, 0); /* reserved */
4020
4/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 89 times.
350 if (!track->entry && mov->mode == MODE_ISM)
4021
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4022
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 252 times.
341 else if (!track->entry)
4023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4024 else
4025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
4026
4027 350 avio_wb32(pb, 0); /* reserved */
4028 350 avio_wb32(pb, 0); /* reserved */
4029 350 avio_wb16(pb, 0); /* layer */
4030 350 avio_wb16(pb, group); /* alternate group) */
4031 /* Volume, only for audio */
4032
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 238 times.
350 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
4033 112 avio_wb16(pb, 0x0100);
4034 else
4035 238 avio_wb16(pb, 0);
4036 350 avio_wb16(pb, 0); /* reserved */
4037
4038 /* Matrix structure */
4039
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 349 times.
350 if (display_matrix) {
4040
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
4041 9 avio_wb32(pb, display_matrix[i]);
4042 } else {
4043 349 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4044 }
4045 /* Track width and height, for visual only */
4046
4/4
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 216 times.
350 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
4047
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 116 times.
342 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
4048 int64_t track_width_1616;
4049
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
221 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
4050 143 track_width_1616 = track->par->width * 0x10000ULL;
4051 } else {
4052 78 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
4053 78 track->par->width * 0x10000LL,
4054 78 st->sample_aspect_ratio.den);
4055
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 69 times.
78 if (!track_width_1616 ||
4056
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 track->height != track->par->height ||
4057 track_width_1616 > UINT32_MAX)
4058 69 track_width_1616 = track->par->width * 0x10000ULL;
4059 }
4060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221 times.
221 if (track_width_1616 > UINT32_MAX) {
4061 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4062 track_width_1616 = 0;
4063 }
4064 221 avio_wb32(pb, track_width_1616);
4065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221 times.
221 if (track->height > 0xFFFF) {
4066 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4067 avio_wb32(pb, 0);
4068 } else
4069 221 avio_wb32(pb, track->height * 0x10000U);
4070 } else {
4071 129 avio_wb32(pb, 0);
4072 129 avio_wb32(pb, 0);
4073 }
4074 350 return 0x5c;
4075 }
4076
4077 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4078 {
4079 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4080 1 track->par->sample_aspect_ratio.den);
4081
4082 1 int64_t pos = avio_tell(pb);
4083
4084 1 avio_wb32(pb, 0); /* size */
4085 1 ffio_wfourcc(pb, "tapt");
4086
4087 1 avio_wb32(pb, 20);
4088 1 ffio_wfourcc(pb, "clef");
4089 1 avio_wb32(pb, 0);
4090 1 avio_wb32(pb, width << 16);
4091 1 avio_wb32(pb, track->par->height << 16);
4092
4093 1 avio_wb32(pb, 20);
4094 1 ffio_wfourcc(pb, "prof");
4095 1 avio_wb32(pb, 0);
4096 1 avio_wb32(pb, width << 16);
4097 1 avio_wb32(pb, track->par->height << 16);
4098
4099 1 avio_wb32(pb, 20);
4100 1 ffio_wfourcc(pb, "enof");
4101 1 avio_wb32(pb, 0);
4102 1 avio_wb32(pb, track->par->width << 16);
4103 1 avio_wb32(pb, track->par->height << 16);
4104
4105 1 return update_size(pb, pos);
4106 }
4107
4108 // This box is written in the following cases:
4109 // * Seems important for the psp playback. Without it the movie seems to hang.
4110 // * Used for specifying the looping behavior of animated AVIF (as specified
4111 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4112 292 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4113 MOVTrack *track)
4114 {
4115 584 int64_t duration = av_rescale_rnd(calc_elst_duration(mov, track),
4116 292 mov->movie_timescale, track->timescale,
4117 AV_ROUND_UP);
4118 292 int version = duration < INT32_MAX ? 0 : 1;
4119 int entry_size, entry_count, size;
4120 292 int64_t delay, start_ct = track->start_cts;
4121 292 int64_t start_dts = track->start_dts;
4122 292 int flags = 0;
4123
4124
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 56 times.
292 if (track->entry) {
4125
4/6
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 233 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
236 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4126
4127 av_log(mov->fc, AV_LOG_DEBUG,
4128 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4129 track->cluster[0].dts, track->cluster[0].cts,
4130 start_dts, start_ct, track->track_id);
4131 start_dts = track->cluster[0].dts;
4132 start_ct = track->cluster[0].cts;
4133 }
4134 }
4135
4136 292 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4137 292 track->timescale, AV_ROUND_DOWN);
4138
4139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 if (mov->mode == MODE_AVIF) {
4140 delay = 0;
4141 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4142 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4143 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4144 // edit list is repeated.
4145 flags = mov->avif_loop_count != 1;
4146 start_ct = 0;
4147 }
4148
4149 292 version |= delay < INT32_MAX ? 0 : 1;
4150
4151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 entry_size = (version == 1) ? 20 : 12;
4152
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 290 times.
292 entry_count = 1 + (delay > 0);
4153 292 size = 24 + entry_count * entry_size;
4154
4155 /* write the atom data */
4156 292 avio_wb32(pb, size);
4157 292 ffio_wfourcc(pb, "edts");
4158 292 avio_wb32(pb, size - 8);
4159 292 ffio_wfourcc(pb, "elst");
4160 292 avio_w8(pb, version);
4161 292 avio_wb24(pb, flags); /* flags */
4162
4163 292 avio_wb32(pb, entry_count);
4164
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 290 times.
292 if (delay > 0) { /* add an empty edit to delay presentation */
4165 /* In the positive delay case, the delay includes the cts
4166 * offset, and the second edit list entry below trims out
4167 * the same amount from the actual content. This makes sure
4168 * that the offset last sample is included in the edit
4169 * list duration as well. */
4170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
4171 avio_wb64(pb, delay);
4172 avio_wb64(pb, -1);
4173 } else {
4174 2 avio_wb32(pb, delay);
4175 2 avio_wb32(pb, -1);
4176 }
4177 2 avio_wb32(pb, 0x00010000);
4178
1/2
✓ Branch 0 taken 290 times.
✗ Branch 1 not taken.
290 } else if (mov->mode != MODE_AVIF) {
4179 /* Avoid accidentally ending up with start_ct = -1 which has got a
4180 * special meaning. Normally start_ct should end up positive or zero
4181 * here, but use FFMIN in case dts is a small positive integer
4182 * rounded to 0 when represented in movie timescale units. */
4183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 290 times.
290 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4184 290 start_ct = -FFMIN(start_dts, 0);
4185
4186 #if CONFIG_IAMFENC
4187
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 285 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
290 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4188 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4189 #endif
4190 /* Note, this delay is calculated from the pts of the first sample,
4191 * ensuring that we don't reduce the duration for cases with
4192 * dts<0 pts=0. */
4193 290 duration += delay;
4194 }
4195
4196 /* For fragmented files, we don't know the full length yet. Setting
4197 * duration to 0 allows us to only specify the offset, including
4198 * the rest of the content (from all future fragments) without specifying
4199 * an explicit duration.
4200 *
4201 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4202 * don't reset duration to zero.
4203 */
4204
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 232 times.
292 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4205
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4206 60 duration = 0;
4207
4208 /* duration */
4209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 if (version == 1) {
4210 avio_wb64(pb, duration);
4211 avio_wb64(pb, start_ct);
4212 } else {
4213 292 avio_wb32(pb, duration);
4214 292 avio_wb32(pb, start_ct);
4215 }
4216 292 avio_wb32(pb, 0x00010000);
4217 292 return size;
4218 }
4219
4220 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4221 {
4222 14 avio_wb32(pb, 20); // size
4223 14 ffio_wfourcc(pb, "tref");
4224 14 avio_wb32(pb, 12); // size (subatom)
4225 14 avio_wl32(pb, track->tref_tag);
4226 14 avio_wb32(pb, track->tref_id);
4227 14 return 20;
4228 }
4229
4230 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4231 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4232 {
4233 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4234 2 ffio_wfourcc(pb, "uuid");
4235 2 ffio_wfourcc(pb, "USMT");
4236 2 avio_wb32(pb, 0x21d24fce);
4237 2 avio_wb32(pb, 0xbb88695c);
4238 2 avio_wb32(pb, 0xfac9c740);
4239 2 avio_wb32(pb, 0x1c); // another size here!
4240 2 ffio_wfourcc(pb, "MTDT");
4241 2 avio_wb32(pb, 0x00010012);
4242 2 avio_wb32(pb, 0x0a);
4243 2 avio_wb32(pb, 0x55c40000);
4244 2 avio_wb32(pb, 0x1);
4245 2 avio_wb32(pb, 0x0);
4246 2 return 0x34;
4247 }
4248
4249 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4250 {
4251 2 AVFormatContext *ctx = track->rtp_ctx;
4252 2 char buf[1000] = "";
4253 int len;
4254
4255 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4256 NULL, NULL, 0, 0, ctx);
4257 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4258 2 len = strlen(buf);
4259
4260 2 avio_wb32(pb, len + 24);
4261 2 ffio_wfourcc(pb, "udta");
4262 2 avio_wb32(pb, len + 16);
4263 2 ffio_wfourcc(pb, "hnti");
4264 2 avio_wb32(pb, len + 8);
4265 2 ffio_wfourcc(pb, "sdp ");
4266 2 avio_write(pb, buf, len);
4267 2 return len + 24;
4268 }
4269
4270 327 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4271 const char *tag, const char *str)
4272 {
4273 327 int64_t pos = avio_tell(pb);
4274 327 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4275
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 326 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
327 if (!t || !utf8len(t->value))
4276 326 return 0;
4277
4278 1 avio_wb32(pb, 0); /* size */
4279 1 ffio_wfourcc(pb, tag); /* type */
4280 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4281 1 return update_size(pb, pos);
4282 }
4283
4284 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4285 const char *value)
4286 {
4287 2 int64_t pos = avio_tell(pb);
4288
4289 /* Box|FullBox basics */
4290 2 avio_wb32(pb, 0); /* size placeholder */
4291 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4292 2 avio_w8(pb, 0); /* version = 0 */
4293 2 avio_wb24(pb, 0); /* flags = 0 */
4294
4295 /* Required null-terminated scheme URI */
4296 2 avio_write(pb, (const unsigned char *)scheme_uri,
4297 2 strlen(scheme_uri));
4298 2 avio_w8(pb, 0);
4299
4300 /* Optional value string */
4301
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])
4302 2 avio_write(pb, (const unsigned char *)value,
4303 2 strlen(value));
4304
4305 2 avio_w8(pb, 0);
4306
4307 2 return update_size(pb, pos);
4308 }
4309
4310 141 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4311 {
4312 141 int ret = AVERROR_BUG;
4313
4314
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 141 times.
282 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4315 141 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4316
4317
2/2
✓ Branch 0 taken 705 times.
✓ Branch 1 taken 141 times.
846 for (int j = 0; map.value_maps[j].disposition; j++) {
4318 705 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4319
2/2
✓ Branch 0 taken 703 times.
✓ Branch 1 taken 2 times.
705 if (!(st->disposition & value_map.disposition))
4320 703 continue;
4321
4322
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)
4323 return ret;
4324 }
4325 }
4326
4327 141 return 0;
4328 }
4329
4330 350 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4331 AVStream *st)
4332 {
4333 AVIOContext *pb_buf;
4334 int ret, size;
4335 uint8_t *buf;
4336
4337
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 337 times.
350 if (!st)
4338 13 return 0;
4339
4340 337 ret = avio_open_dyn_buf(&pb_buf);
4341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 337 times.
337 if (ret < 0)
4342 return ret;
4343
4344
2/2
✓ Branch 0 taken 327 times.
✓ Branch 1 taken 10 times.
337 if (mov->mode & (MODE_MP4|MODE_MOV))
4345 327 mov_write_track_metadata(pb_buf, st, "name", "title");
4346
4347
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 196 times.
337 if (mov->mode & MODE_MP4) {
4348
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 141 times.
141 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4349 return ret;
4350 }
4351
4352
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 334 times.
337 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4353 3 avio_wb32(pb, size + 8);
4354 3 ffio_wfourcc(pb, "udta");
4355 3 avio_write(pb, buf, size);
4356 }
4357 337 ffio_free_dyn_buf(&pb_buf);
4358
4359 337 return 0;
4360 }
4361
4362 350 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4363 MOVTrack *track, AVStream *st)
4364 {
4365 350 int64_t pos = avio_tell(pb);
4366 350 int entry_backup = track->entry;
4367 350 int chunk_backup = track->chunkCount;
4368 int ret;
4369
4370 /* If we want to have an empty moov, but some samples already have been
4371 * buffered (delay_moov), pretend that no samples have been written yet. */
4372
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 252 times.
350 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4373 98 track->chunkCount = track->entry = 0;
4374
4375 350 avio_wb32(pb, 0); /* size */
4376 350 ffio_wfourcc(pb, "trak");
4377 350 mov_write_tkhd_tag(pb, mov, track, st);
4378
4379 av_assert2(mov->use_editlist >= 0);
4380
4381
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 32 times.
350 if (track->start_dts != AV_NOPTS_VALUE) {
4382
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 26 times.
318 if (mov->use_editlist)
4383 292 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4384
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))
4385 av_log(mov->fc, AV_LOG_WARNING,
4386 "Not writing any edit list even though one would have been required\n");
4387 }
4388
4389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (mov->is_animated_avif)
4390 mov_write_edts_tag(pb, mov, track);
4391
4392
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 336 times.
350 if (track->tref_tag)
4393 14 mov_write_tref_tag(pb, track);
4394
4395
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 350 times.
350 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4396 return ret;
4397
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 348 times.
350 if (track->mode == MODE_PSP)
4398 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4399
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 348 times.
350 if (track->tag == MKTAG('r','t','p',' '))
4400 2 mov_write_udta_sdp(pb, track);
4401
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 158 times.
350 if (track->mode == MODE_MOV) {
4402
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 49 times.
192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4403 143 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4404
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
143 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4405 1 mov_write_tapt_tag(pb, track);
4406 }
4407 }
4408
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) {
4409 mov_write_tapt_tag(pb, track);
4410 }
4411 }
4412 350 mov_write_track_udta_tag(pb, mov, st);
4413 350 track->entry = entry_backup;
4414 350 track->chunkCount = chunk_backup;
4415 350 return update_size(pb, pos);
4416 }
4417
4418 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4419 {
4420 int i, has_audio = 0, has_video = 0;
4421 int64_t pos = avio_tell(pb);
4422 int audio_profile = mov->iods_audio_profile;
4423 int video_profile = mov->iods_video_profile;
4424 for (i = 0; i < mov->nb_tracks; i++) {
4425 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4426 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4427 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4428 }
4429 }
4430 if (audio_profile < 0)
4431 audio_profile = 0xFF - has_audio;
4432 if (video_profile < 0)
4433 video_profile = 0xFF - has_video;
4434 avio_wb32(pb, 0x0); /* size */
4435 ffio_wfourcc(pb, "iods");
4436 avio_wb32(pb, 0); /* version & flags */
4437 put_descr(pb, 0x10, 7);
4438 avio_wb16(pb, 0x004f);
4439 avio_w8(pb, 0xff);
4440 avio_w8(pb, 0xff);
4441 avio_w8(pb, audio_profile);
4442 avio_w8(pb, video_profile);
4443 avio_w8(pb, 0xff);
4444 return update_size(pb, pos);
4445 }
4446
4447 114 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4448 {
4449 114 avio_wb32(pb, 0x20); /* size */
4450 114 ffio_wfourcc(pb, "trex");
4451 114 avio_wb32(pb, 0); /* version & flags */
4452 114 avio_wb32(pb, track->track_id); /* track ID */
4453 114 avio_wb32(pb, 1); /* default sample description index */
4454 114 avio_wb32(pb, 0); /* default sample duration */
4455 114 avio_wb32(pb, 0); /* default sample size */
4456 114 avio_wb32(pb, 0); /* default sample flags */
4457 114 return 0;
4458 }
4459
4460 60 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4461 {
4462 60 int64_t pos = avio_tell(pb);
4463 int i;
4464 60 avio_wb32(pb, 0x0); /* size */
4465 60 ffio_wfourcc(pb, "mvex");
4466
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 60 times.
174 for (i = 0; i < mov->nb_tracks; i++)
4467 114 mov_write_trex_tag(pb, &mov->tracks[i]);
4468 60 return update_size(pb, pos);
4469 }
4470
4471 249 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4472 {
4473 249 int max_track_id = 1, i;
4474 249 int64_t max_track_len = 0;
4475 int version;
4476 int timescale;
4477
4478
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 249 times.
601 for (i = 0; i < mov->nb_tracks; i++) {
4479
3/4
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 318 times.
✗ Branch 3 not taken.
352 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4480 636 int64_t max_track_len_temp = av_rescale_rnd(
4481 318 calc_pts_duration(mov, &mov->tracks[i]),
4482 318 mov->movie_timescale,
4483 318 mov->tracks[i].timescale,
4484 AV_ROUND_UP);
4485
2/2
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 70 times.
318 if (max_track_len < max_track_len_temp)
4486 248 max_track_len = max_track_len_temp;
4487
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 233 times.
318 if (max_track_id < mov->tracks[i].track_id)
4488 85 max_track_id = mov->tracks[i].track_id;
4489 }
4490 }
4491 /* If using delay_moov, make sure the output is the same as if no
4492 * samples had been written yet. */
4493
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 197 times.
249 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4494 52 max_track_len = 0;
4495 52 max_track_id = 1;
4496 }
4497
4498 249 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4500
4501 249 ffio_wfourcc(pb, "mvhd");
4502 249 avio_w8(pb, version);
4503 249 avio_wb24(pb, 0); /* flags */
4504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (version == 1) {
4505 avio_wb64(pb, mov->time);
4506 avio_wb64(pb, mov->time);
4507 } else {
4508 249 avio_wb32(pb, mov->time); /* creation time */
4509 249 avio_wb32(pb, mov->time); /* modification time */
4510 }
4511
4512 249 timescale = mov->movie_timescale;
4513
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
249 if (mov->mode == MODE_AVIF && !timescale)
4514 timescale = mov->tracks[0].timescale;
4515
4516 249 avio_wb32(pb, timescale);
4517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4518
4519 249 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4520 249 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4521 249 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4522
4523 /* Matrix structure */
4524 249 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4525
4526 249 avio_wb32(pb, 0); /* reserved (preview time) */
4527 249 avio_wb32(pb, 0); /* reserved (preview duration) */
4528 249 avio_wb32(pb, 0); /* reserved (poster time) */
4529 249 avio_wb32(pb, 0); /* reserved (selection time) */
4530 249 avio_wb32(pb, 0); /* reserved (selection duration) */
4531 249 avio_wb32(pb, 0); /* reserved (current time) */
4532 249 avio_wb32(pb, max_track_id + 1); /* Next track id */
4533 249 return 0x6c;
4534 }
4535
4536 90 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4537 AVFormatContext *s)
4538 {
4539 90 avio_wb32(pb, 33); /* size */
4540 90 ffio_wfourcc(pb, "hdlr");
4541 90 avio_wb32(pb, 0);
4542 90 avio_wb32(pb, 0);
4543 90 ffio_wfourcc(pb, "mdir");
4544 90 ffio_wfourcc(pb, "appl");
4545 90 avio_wb32(pb, 0);
4546 90 avio_wb32(pb, 0);
4547 90 avio_w8(pb, 0);
4548 90 return 33;
4549 }
4550
4551 /* helper function to write a data tag with the specified string as data */
4552 57 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4553 {
4554 57 size_t data_len = strlen(data);
4555
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 34 times.
57 if (long_style) {
4556 23 int size = 16 + data_len;
4557 23 avio_wb32(pb, size); /* size */
4558 23 ffio_wfourcc(pb, "data");
4559 23 avio_wb32(pb, 1);
4560 23 avio_wb32(pb, 0);
4561 23 avio_write(pb, data, data_len);
4562 23 return size;
4563 } else {
4564 34 avio_wb16(pb, data_len); /* string length */
4565
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4566 26 lang = ff_mov_iso639_to_lang("und", 1);
4567 34 avio_wb16(pb, lang);
4568 34 avio_write(pb, data, data_len);
4569 34 return data_len + 4;
4570 }
4571 }
4572
4573 57 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4574 const char *value, int lang, int long_style)
4575 {
4576 57 int size = 0;
4577
2/4
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
57 if (value && value[0]) {
4578 57 int64_t pos = avio_tell(pb);
4579 57 avio_wb32(pb, 0); /* size */
4580 57 ffio_wfourcc(pb, name);
4581 57 mov_write_string_data_tag(pb, value, lang, long_style);
4582 57 size = update_size(pb, pos);
4583 }
4584 57 return size;
4585 }
4586
4587 3922 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4588 const char *tag, int *lang)
4589 {
4590 int l, len, len2;
4591 3922 AVDictionaryEntry *t, *t2 = NULL;
4592 char tag2[16];
4593
4594 3922 *lang = 0;
4595
4596
2/2
✓ Branch 1 taken 3869 times.
✓ Branch 2 taken 53 times.
3922 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4597 3869 return NULL;
4598
4599 53 len = strlen(t->key);
4600 53 snprintf(tag2, sizeof(tag2), "%s-", tag);
4601
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 45 times.
53 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4602 8 len2 = strlen(t2->key);
4603
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)
4604
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4605 8 *lang = l;
4606 8 return t;
4607 }
4608 }
4609 45 return t;
4610 }
4611
4612 3832 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4613 const char *name, const char *tag,
4614 int long_style)
4615 {
4616 int lang;
4617 3832 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4618
2/2
✓ Branch 0 taken 3779 times.
✓ Branch 1 taken 53 times.
3832 if (!t)
4619 3779 return 0;
4620 53 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4621 }
4622
4623 /* iTunes bpm number */
4624 90 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4625 {
4626 90 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 int size = 0, tmpo = t ? atoi(t->value) : 0;
4628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (tmpo) {
4629 size = 26;
4630 avio_wb32(pb, size);
4631 ffio_wfourcc(pb, "tmpo");
4632 avio_wb32(pb, size-8); /* size */
4633 ffio_wfourcc(pb, "data");
4634 avio_wb32(pb, 0x15); //type specifier
4635 avio_wb32(pb, 0);
4636 avio_wb16(pb, tmpo); // data
4637 }
4638 90 return size;
4639 }
4640
4641 /* 3GPP TS 26.244 */
4642 90 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4643 {
4644 int lang;
4645 90 int64_t pos = avio_tell(pb);
4646 double latitude, longitude, altitude;
4647 int32_t latitude_fix, longitude_fix, altitude_fix;
4648 90 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4649 90 const char *ptr, *place = "";
4650 char *end;
4651 static const char *astronomical_body = "earth";
4652
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 if (!t)
4653 90 return 0;
4654
4655 ptr = t->value;
4656 latitude = strtod(ptr, &end);
4657 if (end == ptr) {
4658 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4659 return 0;
4660 }
4661 ptr = end;
4662 longitude = strtod(ptr, &end);
4663 if (end == ptr) {
4664 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4665 return 0;
4666 }
4667 ptr = end;
4668 altitude = strtod(ptr, &end);
4669 /* If no altitude was present, the default 0 should be fine */
4670 if (*end == '/')
4671 place = end + 1;
4672
4673 latitude_fix = (int32_t) ((1 << 16) * latitude);
4674 longitude_fix = (int32_t) ((1 << 16) * longitude);
4675 altitude_fix = (int32_t) ((1 << 16) * altitude);
4676
4677 avio_wb32(pb, 0); /* size */
4678 ffio_wfourcc(pb, "loci"); /* type */
4679 avio_wb32(pb, 0); /* version + flags */
4680 avio_wb16(pb, lang);
4681 avio_write(pb, place, strlen(place) + 1);
4682 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4683 avio_wb32(pb, longitude_fix);
4684 avio_wb32(pb, latitude_fix);
4685 avio_wb32(pb, altitude_fix);
4686 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4687 avio_w8(pb, 0); /* additional notes, null terminated string */
4688
4689 return update_size(pb, pos);
4690 }
4691
4692 /* iTunes track or disc number */
4693 180 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4694 AVFormatContext *s, int disc)
4695 {
4696
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 90 times.
180 AVDictionaryEntry *t = av_dict_get(s->metadata,
4697 disc ? "disc" : "track",
4698 NULL, 0);
4699
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 int size = 0, track = t ? atoi(t->value) : 0;
4700
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (track) {
4701 2 int tracks = 0;
4702 2 char *slash = strchr(t->value, '/');
4703
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4704 2 tracks = atoi(slash + 1);
4705 2 avio_wb32(pb, 32); /* size */
4706
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4707 2 avio_wb32(pb, 24); /* size */
4708 2 ffio_wfourcc(pb, "data");
4709 2 avio_wb32(pb, 0); // 8 bytes empty
4710 2 avio_wb32(pb, 0);
4711 2 avio_wb16(pb, 0); // empty
4712 2 avio_wb16(pb, track); // track / disc number
4713 2 avio_wb16(pb, tracks); // total track / disc number
4714 2 avio_wb16(pb, 0); // empty
4715 2 size = 32;
4716 }
4717 180 return size;
4718 }
4719
4720 540 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4721 const char *name, const char *tag,
4722 int len)
4723 {
4724 540 AVDictionaryEntry *t = NULL;
4725 uint8_t num;
4726 540 int size = 24 + len;
4727
4728
3/4
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 180 times.
540 if (len != 1 && len != 4)
4729 return -1;
4730
4731
2/2
✓ Branch 1 taken 538 times.
✓ Branch 2 taken 2 times.
540 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4732 538 return 0;
4733 2 num = atoi(t->value);
4734
4735 2 avio_wb32(pb, size);
4736 2 ffio_wfourcc(pb, name);
4737 2 avio_wb32(pb, size - 8);
4738 2 ffio_wfourcc(pb, "data");
4739 2 avio_wb32(pb, 0x15);
4740 2 avio_wb32(pb, 0);
4741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4742 2 else avio_w8 (pb, num);
4743
4744 2 return size;
4745 }
4746
4747 90 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4748 {
4749 90 MOVMuxContext *mov = s->priv_data;
4750 90 int64_t pos = 0;
4751
4752
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 90 times.
241 for (int i = 0; i < mov->nb_streams; i++) {
4753 151 MOVTrack *trk = &mov->tracks[i];
4754
4755
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 149 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
151 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4756 149 continue;
4757
4758
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4759 1 pos = avio_tell(pb);
4760 1 avio_wb32(pb, 0);
4761 1 ffio_wfourcc(pb, "covr");
4762 }
4763 2 avio_wb32(pb, 16 + trk->cover_image->size);
4764 2 ffio_wfourcc(pb, "data");
4765 2 avio_wb32(pb, trk->tag);
4766 2 avio_wb32(pb , 0);
4767 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4768 }
4769
4770
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 89 times.
90 return pos ? update_size(pb, pos) : 0;
4771 }
4772
4773 /* iTunes meta data list */
4774 90 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4775 AVFormatContext *s)
4776 {
4777 90 int64_t pos = avio_tell(pb);
4778 90 avio_wb32(pb, 0); /* size */
4779 90 ffio_wfourcc(pb, "ilst");
4780 90 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4781 90 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4782 90 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4783 90 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4784 90 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4785 90 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4786
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4787
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 86 times.
90 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4788 4 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4789 }
4790 90 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4791 90 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4792 90 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4793 90 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4794 90 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4795 90 mov_write_string_metadata(s, pb, "desc", "description",1);
4796 90 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4797 90 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4798 90 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4799 90 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4800 90 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4801 90 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4802 90 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4803 90 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4804 90 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4805 90 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4806 90 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4807 90 mov_write_covr(pb, s);
4808 90 mov_write_trkn_tag(pb, mov, s, 0); // track number
4809 90 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4810 90 mov_write_tmpo_tag(pb, s);
4811 90 return update_size(pb, pos);
4812 }
4813
4814 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4815 AVFormatContext *s)
4816 {
4817 avio_wb32(pb, 33); /* size */
4818 ffio_wfourcc(pb, "hdlr");
4819 avio_wb32(pb, 0);
4820 avio_wb32(pb, 0);
4821 ffio_wfourcc(pb, "mdta");
4822 avio_wb32(pb, 0);
4823 avio_wb32(pb, 0);
4824 avio_wb32(pb, 0);
4825 avio_w8(pb, 0);
4826 return 33;
4827 }
4828
4829 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4830 AVFormatContext *s)
4831 {
4832 const AVDictionaryEntry *t = NULL;
4833 int64_t pos = avio_tell(pb);
4834 int64_t curpos, entry_pos;
4835 int count = 0;
4836
4837 avio_wb32(pb, 0); /* size */
4838 ffio_wfourcc(pb, "keys");
4839 avio_wb32(pb, 0);
4840 entry_pos = avio_tell(pb);
4841 avio_wb32(pb, 0); /* entry count */
4842
4843 while (t = av_dict_iterate(s->metadata, t)) {
4844 size_t key_len = strlen(t->key);
4845 avio_wb32(pb, key_len + 8);
4846 ffio_wfourcc(pb, "mdta");
4847 avio_write(pb, t->key, key_len);
4848 count += 1;
4849 }
4850 curpos = avio_tell(pb);
4851 avio_seek(pb, entry_pos, SEEK_SET);
4852 avio_wb32(pb, count); // rewrite entry count
4853 avio_seek(pb, curpos, SEEK_SET);
4854
4855 return update_size(pb, pos);
4856 }
4857
4858 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4859 AVFormatContext *s)
4860 {
4861 const AVDictionaryEntry *t = NULL;
4862 int64_t pos = avio_tell(pb);
4863 int count = 1; /* keys are 1-index based */
4864
4865 avio_wb32(pb, 0); /* size */
4866 ffio_wfourcc(pb, "ilst");
4867
4868 while (t = av_dict_iterate(s->metadata, t)) {
4869 int64_t entry_pos = avio_tell(pb);
4870 avio_wb32(pb, 0); /* size */
4871 avio_wb32(pb, count); /* key */
4872 mov_write_string_data_tag(pb, t->value, 0, 1);
4873 update_size(pb, entry_pos);
4874 count += 1;
4875 }
4876 return update_size(pb, pos);
4877 }
4878
4879 /* meta data tags */
4880 90 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4881 AVFormatContext *s)
4882 {
4883 90 int size = 0;
4884 90 int64_t pos = avio_tell(pb);
4885 90 avio_wb32(pb, 0); /* size */
4886 90 ffio_wfourcc(pb, "meta");
4887 90 avio_wb32(pb, 0);
4888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4889 mov_write_mdta_hdlr_tag(pb, mov, s);
4890 mov_write_mdta_keys_tag(pb, mov, s);
4891 mov_write_mdta_ilst_tag(pb, mov, s);
4892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 } else if (mov->mode == MODE_AVIF) {
4893 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4894 // We always write the primary item id as 1 since only one track is
4895 // supported for AVIF.
4896 mov_write_pitm_tag(pb, 1);
4897 mov_write_iloc_tag(pb, mov, s);
4898 mov_write_iinf_tag(pb, mov, s);
4899 if (mov->nb_streams > 1)
4900 mov_write_iref_tag(pb, mov, s);
4901 mov_write_iprp_tag(pb, mov, s);
4902 } else {
4903 /* iTunes metadata tag */
4904 90 mov_write_itunes_hdlr_tag(pb, mov, s);
4905 90 mov_write_ilst_tag(pb, mov, s);
4906 }
4907 90 size = update_size(pb, pos);
4908 90 return size;
4909 }
4910
4911 158 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4912 const char *name, const char *key)
4913 {
4914 int len;
4915 AVDictionaryEntry *t;
4916
4917
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4918 158 return 0;
4919
4920 len = strlen(t->value);
4921 if (len > 0) {
4922 int size = len + 8;
4923 avio_wb32(pb, size);
4924 ffio_wfourcc(pb, name);
4925 avio_write(pb, t->value, len);
4926 return size;
4927 }
4928 return 0;
4929 }
4930
4931 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4932 {
4933 int val;
4934 while (*b) {
4935 GET_UTF8(val, *b++, return -1;)
4936 avio_wb16(pb, val);
4937 }
4938 avio_wb16(pb, 0x00);
4939 return 0;
4940 }
4941
4942 static uint16_t language_code(const char *str)
4943 {
4944 return (((str[0] - 0x60) & 0x1F) << 10) +
4945 (((str[1] - 0x60) & 0x1F) << 5) +
4946 (( str[2] - 0x60) & 0x1F);
4947 }
4948
4949 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4950 const char *tag, const char *str)
4951 {
4952 int64_t pos = avio_tell(pb);
4953 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4954 if (!t || !utf8len(t->value))
4955 return 0;
4956 avio_wb32(pb, 0); /* size */
4957 ffio_wfourcc(pb, tag); /* type */
4958 avio_wb32(pb, 0); /* version + flags */
4959 if (!strcmp(tag, "yrrc"))
4960 avio_wb16(pb, atoi(t->value));
4961 else {
4962 avio_wb16(pb, language_code("eng")); /* language */
4963 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4964 if (!strcmp(tag, "albm") &&
4965 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4966 avio_w8(pb, atoi(t->value));
4967 }
4968 return update_size(pb, pos);
4969 }
4970
4971 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4972 {
4973 1 int64_t pos = avio_tell(pb);
4974 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4975
4976 1 avio_wb32(pb, 0); // size
4977 1 ffio_wfourcc(pb, "chpl");
4978 1 avio_wb32(pb, 0x01000000); // version + flags
4979 1 avio_wb32(pb, 0); // unknown
4980 1 avio_w8(pb, nb_chapters);
4981
4982
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4983 4 AVChapter *c = s->chapters[i];
4984 AVDictionaryEntry *t;
4985 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4986
4987
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4988
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4989 4 avio_w8(pb, len);
4990 4 avio_write(pb, t->value, len);
4991 } else
4992 avio_w8(pb, 0);
4993 }
4994 1 return update_size(pb, pos);
4995 }
4996
4997 248 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4998 AVFormatContext *s)
4999 {
5000 AVIOContext *pb_buf;
5001 int ret, size;
5002 uint8_t *buf;
5003
5004 248 ret = avio_open_dyn_buf(&pb_buf);
5005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (ret < 0)
5006 return ret;
5007
5008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (mov->mode & MODE_3GP) {
5009 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
5010 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
5011 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
5012 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
5013 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
5014 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
5015 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
5016 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
5017 mov_write_loci_tag(s, pb_buf);
5018
3/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 158 times.
✗ Branch 3 not taken.
248 } 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
5019 158 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
5020 158 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
5021 158 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
5022 158 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
5023 158 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
5024 158 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
5025 // currently ignored by mov.c
5026 158 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
5027 // add support for libquicktime, this atom is also actually read by mov.c
5028 158 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
5029 158 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
5030 158 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
5031 158 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
5032 158 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
5033 158 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
5034 158 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
5035 158 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
5036 } else {
5037 /* iTunes meta data */
5038 90 mov_write_meta_tag(pb_buf, mov, s);
5039 90 mov_write_loci_tag(s, pb_buf);
5040 }
5041
5042
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
248 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
5043 1 mov_write_chpl_tag(pb_buf, s);
5044
5045
2/2
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 130 times.
248 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
5046 118 avio_wb32(pb, size + 8);
5047 118 ffio_wfourcc(pb, "udta");
5048 118 avio_write(pb, buf, size);
5049 }
5050 248 ffio_free_dyn_buf(&pb_buf);
5051
5052 248 return 0;
5053 }
5054
5055 static void mov_write_psp_udta_tag(AVIOContext *pb,
5056 const char *str, const char *lang, int type)
5057 {
5058 int len = utf8len(str) + 1;
5059 if (len <= 0)
5060 return;
5061 avio_wb16(pb, len * 2 + 10); /* size */
5062 avio_wb32(pb, type); /* type */
5063 avio_wb16(pb, language_code(lang)); /* language */
5064 avio_wb16(pb, 0x01); /* ? */
5065 ascii_to_wc(pb, str);
5066 }
5067
5068 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5069 {
5070 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5071 int64_t pos, pos2;
5072
5073
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5074 pos = avio_tell(pb);
5075 avio_wb32(pb, 0); /* size placeholder*/
5076 ffio_wfourcc(pb, "uuid");
5077 ffio_wfourcc(pb, "USMT");
5078 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5079 avio_wb32(pb, 0xbb88695c);
5080 avio_wb32(pb, 0xfac9c740);
5081
5082 pos2 = avio_tell(pb);
5083 avio_wb32(pb, 0); /* size placeholder*/
5084 ffio_wfourcc(pb, "MTDT");
5085 avio_wb16(pb, 4);
5086
5087 // ?
5088 avio_wb16(pb, 0x0C); /* size */
5089 avio_wb32(pb, 0x0B); /* type */
5090 avio_wb16(pb, language_code("und")); /* language */
5091 avio_wb16(pb, 0x0); /* ? */
5092 avio_wb16(pb, 0x021C); /* data */
5093
5094 if (!(s->flags & AVFMT_FLAG_BITEXACT))
5095 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5096 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5097 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5098
5099 update_size(pb, pos2);
5100 return update_size(pb, pos);
5101 }
5102
5103 1 return 0;
5104 }
5105
5106 339 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5107 {
5108 AVEncryptionInitInfo *info;
5109 339 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5110 339 st->codecpar->nb_coded_side_data,
5111 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5112
1/2
✓ Branch 0 taken 339 times.
✗ Branch 1 not taken.
339 if (!sd)
5113 339 return 0;
5114
5115 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5116 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5117 int64_t pos;
5118
5119 if (!copy->data_size && !copy->num_key_ids)
5120 continue;
5121
5122 pos = avio_tell(pb);
5123 avio_wb32(pb, 0); /* size placeholder */
5124 ffio_wfourcc(pb, "pssh");
5125 avio_w8(pb, 1); /* version */
5126 avio_wb24(pb, 0);
5127 for (int i = 0; i < copy->system_id_size; i++)
5128 avio_w8(pb, copy->system_id[i]);
5129 avio_wb32(pb, copy->num_key_ids);
5130 for (int i = 0; i < copy->num_key_ids; i++)
5131 for (int j = 0; j < copy->key_id_size; j++)
5132 avio_w8(pb, copy->key_ids[i][j]);
5133 avio_wb32(pb, copy->data_size);
5134 avio_write(pb, copy->data, copy->data_size);
5135 update_size(pb, pos);
5136 }
5137
5138 av_encryption_init_info_free(info);
5139
5140 return 0;
5141 }
5142
5143 318 static void build_chunks(MOVTrack *trk)
5144 {
5145 int i;
5146 318 MOVIentry *chunk = &trk->cluster[0];
5147 318 uint64_t chunkSize = chunk->size;
5148 318 chunk->chunkNum = 1;
5149
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 262 times.
318 if (trk->chunkCount)
5150 56 return;
5151 262 trk->chunkCount = 1;
5152
2/2
✓ Branch 0 taken 15124 times.
✓ Branch 1 taken 262 times.
15386 for (i = 1; i<trk->entry; i++){
5153
2/2
✓ Branch 0 taken 13191 times.
✓ Branch 1 taken 1933 times.
15124 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5154
2/2
✓ Branch 0 taken 13190 times.
✓ Branch 1 taken 1 times.
13191 chunk->stsd_index == trk->cluster[i].stsd_index &&
5155
2/2
✓ Branch 0 taken 12545 times.
✓ Branch 1 taken 645 times.
13190 chunkSize + trk->cluster[i].size < (1<<20)){
5156 12545 chunkSize += trk->cluster[i].size;
5157 12545 chunk->samples_in_chunk += trk->cluster[i].entries;
5158 } else {
5159 2579 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5160 2579 chunk=&trk->cluster[i];
5161 2579 chunkSize = chunk->size;
5162 2579 trk->chunkCount++;
5163 }
5164 }
5165 }
5166
5167 /**
5168 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5169 * the stream ids are used as track ids.
5170 *
5171 * This assumes mov->tracks and s->streams are in the same order and
5172 * there are no gaps in either of them (so mov->tracks[n] refers to
5173 * s->streams[n]).
5174 *
5175 * As an exception, there can be more entries in
5176 * s->streams than in mov->tracks, in which case new track ids are
5177 * generated (starting after the largest found stream id).
5178 */
5179 249 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5180 {
5181 int i;
5182
5183
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 219 times.
249 if (mov->track_ids_ok)
5184 30 return 0;
5185
5186
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->use_stream_ids_as_track_ids) {
5187 1 int next_generated_track_id = 0;
5188
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5189 2 AVStream *st = mov->tracks[i].st;
5190
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5191 2 next_generated_track_id = st->id;
5192 }
5193
5194
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5195
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))
5196 continue;
5197
5198
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;
5199 }
5200 } else {
5201 218 int last_track_id = 0;
5202
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 218 times.
506 for (i = 0; i < mov->nb_tracks; i++) {
5203
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 30 times.
288 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5204 2 continue;
5205
5206 286 last_track_id =
5207 286 mov->tracks[i].track_id = (mov->tracks[i].st
5208 283 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5209
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 3 times.
286 : FFMAX(i, last_track_id)) + 1;
5210 }
5211 }
5212
5213 219 mov->track_ids_ok = 1;
5214
5215 219 return 0;
5216 }
5217
5218 249 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5219 AVFormatContext *s)
5220 {
5221 int i;
5222 249 int64_t pos = avio_tell(pb);
5223 249 avio_wb32(pb, 0); /* size placeholder*/
5224 249 ffio_wfourcc(pb, "moov");
5225
5226 249 mov_setup_track_ids(mov, s);
5227
5228
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 249 times.
601 for (i = 0; i < mov->nb_tracks; i++) {
5229
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 318 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 32 times.
352 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5230 2 continue;
5231
5232 350 mov->tracks[i].time = mov->time;
5233
5234
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 32 times.
350 if (mov->tracks[i].entry)
5235 318 build_chunks(&mov->tracks[i]);
5236 }
5237
5238
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 248 times.
249 if (mov->chapter_track)
5239
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5240 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5241 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5242 }
5243
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 249 times.
601 for (i = 0; i < mov->nb_tracks; i++) {
5244 352 MOVTrack *track = &mov->tracks[i];
5245
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 350 times.
352 if (track->tag == MKTAG('r','t','p',' ')) {
5246 2 track->tref_tag = MKTAG('h','i','n','t');
5247 2 track->tref_id = mov->tracks[track->src_track].track_id;
5248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 } else if (track->tag == MKTAG('l','v','c','1')) {
5249 track->tref_tag = MKTAG('s','b','a','s');
5250 track->tref_id = mov->tracks[track->src_track].track_id;
5251
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 238 times.
350 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5252 112 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5253 112 track->st->codecpar->nb_coded_side_data,
5254 AV_PKT_DATA_FALLBACK_TRACK );
5255
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
112 if (sd && sd->size == sizeof(int)) {
5256 int *fallback = (int *)sd->data;
5257 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5258 track->tref_tag = MKTAG('f','a','l','l');
5259 track->tref_id = mov->tracks[*fallback].track_id;
5260 }
5261 }
5262 }
5263 }
5264
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 249 times.
601 for (i = 0; i < mov->nb_tracks; i++) {
5265
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 339 times.
352 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5266 13 int src_trk = mov->tracks[i].src_track;
5267 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5268 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5269 //src_trk may have a different timescale than the tmcd track
5270 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5271 13 mov->tracks[i].timescale,
5272 13 mov->tracks[src_trk].timescale);
5273 }
5274 }
5275
5276 249 mov_write_mvhd_tag(pb, mov);
5277
4/6
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 91 times.
249 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5278 mov_write_iods_tag(pb, mov);
5279
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 249 times.
601 for (i = 0; i < mov->nb_tracks; i++) {
5280
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 318 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 32 times.
352 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5282
2/2
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 13 times.
350 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (ret < 0)
5284 return ret;
5285 }
5286 }
5287 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5288 * (mov->moov_written != 0)
5289 */
5290
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 187 times.
249 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5291
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
62 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
5292 60 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5293
5294
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 248 times.
249 if (mov->mode == MODE_PSP)
5295 1 mov_write_uuidusmt_tag(pb, s);
5296
1/2
✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
248 else if (mov->mode != MODE_AVIF)
5297 248 mov_write_udta_tag(pb, mov, s);
5298
2/2
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 249 times.
588 for (i = 0; i < mov->nb_streams; i++)
5299 339 mov_write_pssh_tag(pb, mov->tracks[i].st);
5300
5301 249 return update_size(pb, pos);
5302 }
5303
5304 static void param_write_int(AVIOContext *pb, const char *name, int value)
5305 {
5306 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5307 }
5308
5309 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5310 {
5311 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5312 }
5313
5314 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5315 {
5316 char buf[150];
5317 len = FFMIN(sizeof(buf) / 2 - 1, len);
5318 ff_data_to_hex(buf, value, len, 0);
5319 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5320 }
5321
5322 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5323 {
5324 int64_t pos = avio_tell(pb);
5325 int i;
5326
5327 static const AVUUID uuid = {
5328 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5329 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5330 };
5331
5332 avio_wb32(pb, 0);
5333 ffio_wfourcc(pb, "uuid");
5334 avio_write(pb, uuid, AV_UUID_LEN);
5335 avio_wb32(pb, 0);
5336
5337 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5338 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5339 avio_printf(pb, "<head>\n");
5340 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5341 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5342 LIBAVFORMAT_IDENT);
5343 avio_printf(pb, "</head>\n");
5344 avio_printf(pb, "<body>\n");
5345 avio_printf(pb, "<switch>\n");
5346
5347 mov_setup_track_ids(mov, s);
5348
5349 for (i = 0; i < mov->nb_tracks; i++) {
5350 MOVTrack *track = &mov->tracks[i];
5351 struct mpeg4_bit_rate_values bit_rates =
5352 calculate_mpeg4_bit_rates(track);
5353 const char *type;
5354 int track_id = track->track_id;
5355 char track_name_buf[32] = { 0 };
5356
5357 AVStream *st = track->st;
5358 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5359
5360 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5361 type = "video";
5362 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5363 type = "audio";
5364 } else {
5365 continue;
5366 }
5367
5368 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5369 bit_rates.avg_bit_rate);
5370 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5371 param_write_int(pb, "trackID", track_id);
5372 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5373
5374 /* Build track name piece by piece: */
5375 /* 1. track type */
5376 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5377 /* 2. track language, if available */
5378 if (lang)
5379 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5380 "_%s", lang->value);
5381 /* 3. special type suffix */
5382 /* "_cc" = closed captions, "_ad" = audio_description */
5383 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5384 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5385 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5386 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5387
5388 param_write_string(pb, "trackName", track_name_buf);
5389
5390 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5391 if (track->par->codec_id == AV_CODEC_ID_H264) {
5392 uint8_t *ptr;
5393 int size = track->extradata_size[track->last_stsd_index];
5394 if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5395 &size)) {
5396 param_write_hex(pb, "CodecPrivateData",
5397 ptr ? ptr : track->extradata[track->last_stsd_index],
5398 size);
5399 av_free(ptr);
5400 }
5401 param_write_string(pb, "FourCC", "H264");
5402 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5403 param_write_string(pb, "FourCC", "WVC1");
5404 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5405 track->extradata_size[track->last_stsd_index]);
5406 }
5407 param_write_int(pb, "MaxWidth", track->par->width);
5408 param_write_int(pb, "MaxHeight", track->par->height);
5409 param_write_int(pb, "DisplayWidth", track->par->width);
5410 param_write_int(pb, "DisplayHeight", track->par->height);
5411 } else {
5412 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5413 switch (track->par->profile) {
5414 case AV_PROFILE_AAC_HE_V2:
5415 param_write_string(pb, "FourCC", "AACP");
5416 break;
5417 case AV_PROFILE_AAC_HE:
5418 param_write_string(pb, "FourCC", "AACH");
5419 break;
5420 default:
5421 param_write_string(pb, "FourCC", "AACL");
5422 }
5423 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5424 param_write_string(pb, "FourCC", "WMAP");
5425 }
5426 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5427 track->extradata_size[track->last_stsd_index]);
5428 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5429 track->par->codec_id));
5430 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5431 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5432 0 : track->par->sample_rate);
5433 param_write_int(pb, "BitsPerSample", 16);
5434 param_write_int(pb, "PacketSize", track->par->block_align ?
5435 track->par->block_align : 4);
5436 }
5437 avio_printf(pb, "</%s>\n", type);
5438 }
5439 avio_printf(pb, "</switch>\n");
5440 avio_printf(pb, "</body>\n");
5441 avio_printf(pb, "</smil>\n");
5442
5443 return update_size(pb, pos);
5444 }
5445
5446 226 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5447 {
5448 226 avio_wb32(pb, 16);
5449 226 ffio_wfourcc(pb, "mfhd");
5450 226 avio_wb32(pb, 0);
5451 226 avio_wb32(pb, mov->fragments);
5452 226 return 0;
5453 }
5454
5455 13522 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5456 {
5457
2/2
✓ Branch 0 taken 7628 times.
✓ Branch 1 taken 5894 times.
13522 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5458 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5459 }
5460
5461 346 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5462 MOVTrack *track, int64_t moof_offset)
5463 {
5464 346 int64_t pos = avio_tell(pb);
5465 346 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5466 MOV_TFHD_BASE_DATA_OFFSET;
5467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (!track->entry) {
5468 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5469 } else {
5470 346 flags |= MOV_TFHD_DEFAULT_FLAGS;
5471 }
5472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5473 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5474
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 214 times.
346 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5475 132 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5476 132 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5477 }
5478 /* CMAF requires all values to be explicit in tfhd atoms */
5479
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 286 times.
346 if (mov->flags & FF_MOV_FLAG_CMAF)
5480 60 flags |= MOV_TFHD_STSD_ID;
5481
5482 /* Don't set a default sample size, the silverlight player refuses
5483 * to play files with that set. Don't set a default sample duration,
5484 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5485 * file format says it MUST NOT be set. */
5486
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 264 times.
346 if (track->mode == MODE_ISM)
5487 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5488 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5489
5490 346 avio_wb32(pb, 0); /* size placeholder */
5491 346 ffio_wfourcc(pb, "tfhd");
5492 346 avio_w8(pb, 0); /* version */
5493 346 avio_wb24(pb, flags);
5494
5495 346 avio_wb32(pb, track->track_id); /* track-id */
5496
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 214 times.
346 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5497 132 avio_wb64(pb, moof_offset);
5498
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 286 times.
346 if (flags & MOV_TFHD_STSD_ID) {
5499 60 avio_wb32(pb, 1);
5500 }
5501
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 82 times.
346 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5502 264 track->default_duration = get_cluster_duration(track, 0);
5503 264 avio_wb32(pb, track->default_duration);
5504 }
5505
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 82 times.
346 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5506
1/2
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
264 track->default_size = track->entry ? track->cluster[0].size : 1;
5507 264 avio_wb32(pb, track->default_size);
5508 } else
5509 82 track->default_size = -1;
5510
5511
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
346 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5512 /* Set the default flags based on the second sample, if available.
5513 * If the first sample is different, that can be signaled via a separate field. */
5514
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 64 times.
346 if (track->entry > 1)
5515 282 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5516 else
5517 64 track->default_sample_flags =
5518 64 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5519
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 56 times.
64 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5520 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5521 346 avio_wb32(pb, track->default_sample_flags);
5522 }
5523
5524 346 return update_size(pb, pos);
5525 }
5526
5527 348 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5528 MOVTrack *track, int moof_size,
5529 int first, int end)
5530 {
5531 348 int64_t pos = avio_tell(pb);
5532 348 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5533 int i;
5534
5535
2/2
✓ Branch 0 taken 12712 times.
✓ Branch 1 taken 348 times.
13060 for (i = first; i < end; i++) {
5536
2/2
✓ Branch 1 taken 1822 times.
✓ Branch 2 taken 10890 times.
12712 if (get_cluster_duration(track, i) != track->default_duration)
5537 1822 flags |= MOV_TRUN_SAMPLE_DURATION;
5538
2/2
✓ Branch 0 taken 2940 times.
✓ Branch 1 taken 9772 times.
12712 if (track->cluster[i].size != track->default_size)
5539 2940 flags |= MOV_TRUN_SAMPLE_SIZE;
5540
4/4
✓ Branch 0 taken 12364 times.
✓ Branch 1 taken 348 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 12354 times.
12712 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5541 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5542 }
5543
3/4
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
348 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5544
2/2
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 176 times.
340 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5545 164 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5546
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 254 times.
348 if (track->flags & MOV_TRACK_CTTS)
5547 94 flags |= MOV_TRUN_SAMPLE_CTS;
5548
5549 348 avio_wb32(pb, 0); /* size placeholder */
5550 348 ffio_wfourcc(pb, "trun");
5551
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 190 times.
348 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5552 158 avio_w8(pb, 1); /* version */
5553 else
5554 190 avio_w8(pb, 0); /* version */
5555 348 avio_wb24(pb, flags);
5556
5557 348 avio_wb32(pb, end - first); /* sample count */
5558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 348 times.
348 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5559 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5560 !mov->first_trun)
5561 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5562 else
5563 348 avio_wb32(pb, moof_size + 8 + track->data_offset +
5564 348 track->cluster[first].pos); /* data offset */
5565
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 184 times.
348 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5566 164 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5567
5568
2/2
✓ Branch 0 taken 12712 times.
✓ Branch 1 taken 348 times.
13060 for (i = first; i < end; i++) {
5569
2/2
✓ Branch 0 taken 2010 times.
✓ Branch 1 taken 10702 times.
12712 if (flags & MOV_TRUN_SAMPLE_DURATION)
5570 2010 avio_wb32(pb, get_cluster_duration(track, i));
5571
2/2
✓ Branch 0 taken 3616 times.
✓ Branch 1 taken 9096 times.
12712 if (flags & MOV_TRUN_SAMPLE_SIZE)
5572 3616 avio_wb32(pb, track->cluster[i].size);
5573
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 12340 times.
12712 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5574 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5575
2/2
✓ Branch 0 taken 3156 times.
✓ Branch 1 taken 9556 times.
12712 if (flags & MOV_TRUN_SAMPLE_CTS)
5576 3156 avio_wb32(pb, track->cluster[i].cts);
5577 }
5578
5579 348 mov->first_trun = 0;
5580 348 return update_size(pb, pos);
5581 }
5582
5583 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5584 {
5585 82 int64_t pos = avio_tell(pb);
5586 static const uint8_t uuid[] = {
5587 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5588 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5589 };
5590
5591 82 avio_wb32(pb, 0); /* size placeholder */
5592 82 ffio_wfourcc(pb, "uuid");
5593 82 avio_write(pb, uuid, AV_UUID_LEN);
5594 82 avio_w8(pb, 1);
5595 82 avio_wb24(pb, 0);
5596 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5597 82 avio_wb64(pb, track->end_pts -
5598 82 (track->cluster[0].dts + track->cluster[0].cts));
5599
5600 82 return update_size(pb, pos);
5601 }
5602
5603 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5604 MOVTrack *track, int entry)
5605 {
5606 int n = track->nb_frag_info - 1 - entry, i;
5607 int size = 8 + 16 + 4 + 1 + 16*n;
5608 static const uint8_t uuid[] = {
5609 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5610 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5611 };
5612
5613 if (entry < 0)
5614 return 0;
5615
5616 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5617 avio_wb32(pb, size);
5618 ffio_wfourcc(pb, "uuid");
5619 avio_write(pb, uuid, AV_UUID_LEN);
5620 avio_w8(pb, 1);
5621 avio_wb24(pb, 0);
5622 avio_w8(pb, n);
5623 for (i = 0; i < n; i++) {
5624 int index = entry + 1 + i;
5625 avio_wb64(pb, track->frag_info[index].time);
5626 avio_wb64(pb, track->frag_info[index].duration);
5627 }
5628 if (n < mov->ism_lookahead) {
5629 int free_size = 16 * (mov->ism_lookahead - n);
5630 avio_wb32(pb, free_size);
5631 ffio_wfourcc(pb, "free");
5632 ffio_fill(pb, 0, free_size - 8);
5633 }
5634
5635 return 0;
5636 }
5637
5638 173 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5639 MOVTrack *track)
5640 {
5641 173 int64_t pos = avio_tell(pb);
5642 int i;
5643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 for (i = 0; i < mov->ism_lookahead; i++) {
5644 /* Update the tfrf tag for the last ism_lookahead fragments,
5645 * nb_frag_info - 1 is the next fragment to be written. */
5646 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5647 }
5648 173 avio_seek(pb, pos, SEEK_SET);
5649 173 return 0;
5650 }
5651
5652 113 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5653 int size)
5654 {
5655 int i;
5656
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 113 times.
329 for (i = 0; i < mov->nb_tracks; i++) {
5657 216 MOVTrack *track = &mov->tracks[i];
5658 MOVFragmentInfo *info;
5659
6/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 137 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 173 times.
216 if ((tracks >= 0 && i != tracks) || !track->entry)
5660 43 continue;
5661 173 track->nb_frag_info++;
5662
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 103 times.
173 if (track->nb_frag_info >= track->frag_info_capacity) {
5663 70 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5664
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
70 if (av_reallocp_array(&track->frag_info,
5665 new_capacity,
5666 sizeof(*track->frag_info)))
5667 return AVERROR(ENOMEM);
5668 70 track->frag_info_capacity = new_capacity;
5669 }
5670 173 info = &track->frag_info[track->nb_frag_info - 1];
5671 173 info->offset = avio_tell(pb);
5672 173 info->size = size;
5673 // Try to recreate the original pts for the first packet
5674 // from the fields we have stored
5675 173 info->time = track->cluster[0].dts + track->cluster[0].cts;
5676 173 info->duration = track->end_pts -
5677 173 (track->cluster[0].dts + track->cluster[0].cts);
5678 // If the pts is less than zero, we will have trimmed
5679 // away parts of the media track using an edit list,
5680 // and the corresponding start presentation time is zero.
5681
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 165 times.
173 if (info->time < 0) {
5682 8 info->duration += info->time;
5683 8 info->time = 0;
5684 }
5685 173 info->tfrf_offset = 0;
5686 173 mov_write_tfrf_tags(pb, mov, track);
5687 }
5688 113 return 0;
5689 }
5690
5691 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5692 {
5693 int i;
5694 for (i = 0; i < mov->nb_tracks; i++) {
5695 MOVTrack *track = &mov->tracks[i];
5696 if ((tracks >= 0 && i != tracks) || !track->entry)
5697 continue;
5698 if (track->nb_frag_info > max) {
5699 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5700 track->nb_frag_info = max;
5701 }
5702 }
5703 }
5704
5705 264 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5706 {
5707 264 int64_t pos = avio_tell(pb);
5708
5709 264 avio_wb32(pb, 0); /* size */
5710 264 ffio_wfourcc(pb, "tfdt");
5711 264 avio_w8(pb, 1); /* version */
5712 264 avio_wb24(pb, 0);
5713 264 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5714 264 return update_size(pb, pos);
5715 }
5716
5717 346 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5718 MOVTrack *track, int64_t moof_offset,
5719 int moof_size)
5720 {
5721 346 int64_t pos = avio_tell(pb);
5722 346 int i, start = 0;
5723 346 avio_wb32(pb, 0); /* size placeholder */
5724 346 ffio_wfourcc(pb, "traf");
5725
5726 346 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5727
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 82 times.
346 if (mov->mode != MODE_ISM)
5728 264 mov_write_tfdt_tag(pb, track);
5729
2/2
✓ Branch 0 taken 12366 times.
✓ Branch 1 taken 346 times.
12712 for (i = 1; i < track->entry; i++) {
5730
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12364 times.
12366 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5731 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5732 2 start = i;
5733 }
5734 }
5735 346 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5736
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 264 times.
346 if (mov->mode == MODE_ISM) {
5737 82 mov_write_tfxd_tag(pb, track);
5738
5739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5740 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5741
5742 if (track->nb_frag_info > 0) {
5743 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5744 if (!info->tfrf_offset)
5745 info->tfrf_offset = avio_tell(pb);
5746 }
5747 avio_wb32(pb, 8 + size);
5748 ffio_wfourcc(pb, "free");
5749 ffio_fill(pb, 0, size);
5750 }
5751 }
5752
5753
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
346 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5754 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5755
5756 346 return update_size(pb, pos);
5757 }
5758
5759 226 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5760 int tracks, int moof_size)
5761 {
5762 226 int64_t pos = avio_tell(pb);
5763 int i;
5764
5765 226 avio_wb32(pb, 0); /* size placeholder */
5766 226 ffio_wfourcc(pb, "moof");
5767 226 mov->first_trun = 1;
5768
5769 226 mov_write_mfhd_tag(pb, mov);
5770
2/2
✓ Branch 0 taken 432 times.
✓ Branch 1 taken 226 times.
658 for (i = 0; i < mov->nb_tracks; i++) {
5771 432 MOVTrack *track = &mov->tracks[i];
5772
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 274 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 82 times.
432 if (tracks >= 0 && i != tracks)
5773 76 continue;
5774
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 346 times.
356 if (!track->entry)
5775 10 continue;
5776
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
346 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5777 mov_write_pssh_tag(pb, track->st);
5778 346 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5779 }
5780
5781 226 return update_size(pb, pos);
5782 }
5783
5784 72 static int mov_write_sidx_tag(AVIOContext *pb,
5785 MOVTrack *track, int ref_size, int total_sidx_size)
5786 {
5787 72 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5788 int64_t presentation_time, duration, offset;
5789 unsigned starts_with_SAP;
5790 int i, entries;
5791
5792
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 if (track->entry) {
5793 72 entries = 1;
5794 72 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
5795 72 duration = track->end_pts -
5796 72 (track->cluster[0].dts + track->cluster[0].cts);
5797 72 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5798
5799 // pts<0 should be cut away using edts
5800
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 66 times.
72 if (presentation_time < 0) {
5801 6 duration += presentation_time;
5802 6 presentation_time = 0;
5803 }
5804 } else {
5805 entries = track->nb_frag_info;
5806 if (entries <= 0)
5807 return 0;
5808 presentation_time = track->frag_info[0].time;
5809 }
5810
5811 72 avio_wb32(pb, 0); /* size */
5812 72 ffio_wfourcc(pb, "sidx");
5813 72 avio_w8(pb, 1); /* version */
5814 72 avio_wb24(pb, 0);
5815 72 avio_wb32(pb, track->track_id); /* reference_ID */
5816 72 avio_wb32(pb, track->timescale); /* timescale */
5817 72 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5818 72 offset_pos = avio_tell(pb);
5819 72 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5820 72 avio_wb16(pb, 0); /* reserved */
5821
5822 72 avio_wb16(pb, entries); /* reference_count */
5823
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 for (i = 0; i < entries; i++) {
5824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (!track->entry) {
5825 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5826 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5827 }
5828 duration = track->frag_info[i].duration;
5829 ref_size = track->frag_info[i].size;
5830 starts_with_SAP = 1;
5831 }
5832 72 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5833 72 avio_wb32(pb, duration); /* subsegment_duration */
5834 72 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5835 }
5836
5837 72 end_pos = avio_tell(pb);
5838 72 offset = pos + total_sidx_size - end_pos;
5839 72 avio_seek(pb, offset_pos, SEEK_SET);
5840 72 avio_wb64(pb, offset);
5841 72 avio_seek(pb, end_pos, SEEK_SET);
5842 72 return update_size(pb, pos);
5843 }
5844
5845 21 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5846 int tracks, int ref_size)
5847 {
5848 int i, round, ret;
5849 AVIOContext *avio_buf;
5850 21 int total_size = 0;
5851
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 21 times.
63 for (round = 0; round < 2; round++) {
5852 // First run one round to calculate the total size of all
5853 // sidx atoms.
5854 // This would be much simpler if we'd only write one sidx
5855 // atom, for the first track in the moof.
5856
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
42 if (round == 0) {
5857
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5858 return ret;
5859 } else {
5860 21 avio_buf = pb;
5861 }
5862
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 42 times.
114 for (i = 0; i < mov->nb_tracks; i++) {
5863 72 MOVTrack *track = &mov->tracks[i];
5864
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
72 if (tracks >= 0 && i != tracks)
5865 continue;
5866 // When writing a sidx for the full file, entry is 0, but
5867 // we want to include all tracks. ref_size is 0 in this case,
5868 // since we read it from frag_info instead.
5869
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
72 if (!track->entry && ref_size > 0)
5870 continue;
5871 72 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5872 total_size);
5873 }
5874
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
42 if (round == 0) {
5875 21 total_size = ffio_close_null_buf(avio_buf);
5876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (total_size < 0)
5877 return total_size;
5878 }
5879 }
5880 21 return 0;
5881 }
5882
5883 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5884 {
5885 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5886 MOVTrack *first_track;
5887 int flags = 24;
5888
5889 /* PRFT should be associated with at most one track. So, choosing only the
5890 * first track. */
5891 if (tracks > 0)
5892 return 0;
5893 first_track = &(mov->tracks[0]);
5894
5895 if (!first_track->entry) {
5896 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5897 return 0;
5898 }
5899
5900 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5901 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5902 return 0;
5903 }
5904
5905 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5906 if (first_track->cluster[0].prft.wallclock) {
5907 /* Round the NTP time to whole milliseconds. */
5908 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5909 NTP_OFFSET_US);
5910 flags = first_track->cluster[0].prft.flags;
5911 } else
5912 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5913 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5914 pts_us = av_rescale_q(first_track->cluster[0].pts,
5915 first_track->st->time_base, AV_TIME_BASE_Q);
5916 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5917 } else {
5918 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5919 mov->write_prft);
5920 return 0;
5921 }
5922
5923 avio_wb32(pb, 0); // Size place holder
5924 ffio_wfourcc(pb, "prft"); // Type
5925 avio_w8(pb, 1); // Version
5926 avio_wb24(pb, flags); // Flags
5927 avio_wb32(pb, first_track->track_id); // reference track ID
5928 avio_wb64(pb, ntp_ts); // NTP time stamp
5929 avio_wb64(pb, first_track->cluster[0].pts); //media time
5930 return update_size(pb, pos);
5931 }
5932
5933 113 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5934 int64_t mdat_size)
5935 {
5936 AVIOContext *avio_buf;
5937 int ret, moof_size;
5938
5939
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
113 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5940 return ret;
5941 113 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5942 113 moof_size = ffio_close_null_buf(avio_buf);
5943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 if (moof_size < 0)
5944 return moof_size;
5945
5946
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 92 times.
113 if (mov->flags & FF_MOV_FLAG_DASH &&
5947
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5948 21 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5949
5950
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
113 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
5951 mov_write_prft_tag(pb, mov, tracks);
5952
5953
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5955 mov->ism_lookahead) {
5956
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
113 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
5957 return ret;
5958
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5960 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5961 }
5962 }
5963
5964 113 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5965 }
5966
5967 66 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5968 {
5969 66 int64_t pos = avio_tell(pb);
5970 int i;
5971
5972 66 avio_wb32(pb, 0); /* size placeholder */
5973 66 ffio_wfourcc(pb, "tfra");
5974 66 avio_w8(pb, 1); /* version */
5975 66 avio_wb24(pb, 0);
5976
5977 66 avio_wb32(pb, track->track_id);
5978 66 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5979 66 avio_wb32(pb, track->nb_frag_info);
5980
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 66 times.
233 for (i = 0; i < track->nb_frag_info; i++) {
5981 167 avio_wb64(pb, track->frag_info[i].time);
5982 167 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5983 167 avio_w8(pb, 1); /* traf number */
5984 167 avio_w8(pb, 1); /* trun number */
5985 167 avio_w8(pb, 1); /* sample number */
5986 }
5987
5988 66 return update_size(pb, pos);
5989 }
5990
5991 36 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5992 {
5993 AVIOContext *mfra_pb;
5994 int i, ret, sz;
5995 uint8_t *buf;
5996
5997 36 ret = avio_open_dyn_buf(&mfra_pb);
5998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (ret < 0)
5999 return ret;
6000
6001 36 avio_wb32(mfra_pb, 0); /* size placeholder */
6002 36 ffio_wfourcc(mfra_pb, "mfra");
6003 /* An empty mfra atom is enough to indicate to the publishing point that
6004 * the stream has ended. */
6005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (mov->flags & FF_MOV_FLAG_ISML)
6006 goto done_mfra;
6007
6008
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 36 times.
104 for (i = 0; i < mov->nb_tracks; i++) {
6009 68 MOVTrack *track = &mov->tracks[i];
6010
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 2 times.
68 if (track->nb_frag_info)
6011 66 mov_write_tfra_tag(mfra_pb, track);
6012 }
6013
6014 36 avio_wb32(mfra_pb, 16);
6015 36 ffio_wfourcc(mfra_pb, "mfro");
6016 36 avio_wb32(mfra_pb, 0); /* version + flags */
6017 36 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
6018
6019 36 done_mfra:
6020
6021 36 sz = update_size(mfra_pb, 0);
6022 36 ret = avio_get_dyn_buf(mfra_pb, &buf);
6023 36 avio_write(pb, buf, ret);
6024 36 ffio_free_dyn_buf(&mfra_pb);
6025
6026 36 return sz;
6027 }
6028
6029 181 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
6030 {
6031 181 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
6032
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 32 times.
181 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
6033
6034 181 mov->mdat_pos = avio_tell(pb);
6035 181 avio_wb32(pb, 0); /* size placeholder*/
6036 181 ffio_wfourcc(pb, "mdat");
6037 181 return 0;
6038 }
6039
6040 442 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
6041 int has_h264, int has_video, int write_minor)
6042 {
6043 442 MOVMuxContext *mov = s->priv_data;
6044 442 int minor = 0x200;
6045
6046
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
442 if (mov->major_brand && strlen(mov->major_brand) >= 4)
6047 ffio_wfourcc(pb, mov->major_brand);
6048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 else if (mov->mode == MODE_3GP) {
6049 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
6050 minor = has_h264 ? 0x100 : 0x200;
6051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 } else if (mov->mode == MODE_AVIF) {
6052 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
6053 minor = 0;
6054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 } else if (mov->mode & MODE_3G2) {
6055 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
6056 minor = has_h264 ? 0x20000 : 0x10000;
6057
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 440 times.
442 } else if (mov->mode == MODE_PSP)
6058 2 ffio_wfourcc(pb, "MSNV");
6059
4/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 314 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 60 times.
440 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
6060
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 58 times.
66 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6061 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
6062
4/4
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 314 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 94 times.
432 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6063 24 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
6064
3/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 94 times.
408 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6065 ffio_wfourcc(pb, "iso4");
6066
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 314 times.
408 else if (mov->mode == MODE_MP4)
6067 94 ffio_wfourcc(pb, "isom");
6068
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 312 times.
314 else if (mov->mode == MODE_IPOD)
6069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6070
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 302 times.
312 else if (mov->mode == MODE_ISM)
6071 10 ffio_wfourcc(pb, "isml");
6072
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 302 times.
302 else if (mov->mode == MODE_F4V)
6073 ffio_wfourcc(pb, "f4v ");
6074 else
6075 302 ffio_wfourcc(pb, "qt ");
6076
6077
2/2
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 221 times.
442 if (write_minor)
6078 221 avio_wb32(pb, minor);
6079 442 }
6080
6081 221 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6082 {
6083 221 MOVMuxContext *mov = s->priv_data;
6084 221 int64_t pos = avio_tell(pb);
6085 221 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6086 221 int has_iamf = 0;
6087
6088 #if CONFIG_IAMFENC
6089
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 216 times.
221 for (int i = 0; i < s->nb_stream_groups; i++) {
6090 5 const AVStreamGroup *stg = s->stream_groups[i];
6091
6092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6093 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6094 5 has_iamf = 1;
6095 5 break;
6096 }
6097 }
6098 #endif
6099
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 221 times.
506 for (int i = 0; i < mov->nb_streams; i++) {
6100 285 AVStream *st = mov->tracks[i].st;
6101
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 283 times.
285 if (is_cover_image(st))
6102 2 continue;
6103
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 93 times.
283 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6104 190 has_video = 1;
6105
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 248 times.
283 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6106 35 has_h264 = 1;
6107
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 282 times.
283 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6108 1 has_av1 = 1;
6109
2/2
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 4 times.
283 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6110
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 1 times.
279 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6111
2/4
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 278 times.
556 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6112 278 av_packet_side_data_get(st->codecpar->coded_side_data,
6113 278 st->codecpar->nb_coded_side_data,
6114 AV_PKT_DATA_DOVI_CONF))
6115 5 has_dolby = 1;
6116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6117 has_id3 = 1;
6118 }
6119
6120 221 avio_wb32(pb, 0); /* size */
6121 221 ffio_wfourcc(pb, "ftyp");
6122
6123 // Write major brand
6124 221 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6125 // Write the major brand as the first compatible brand as well
6126 221 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6127
6128 // Write compatible brands, ensuring that we don't write the major brand as a
6129 // compatible brand a second time.
6130
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 216 times.
221 if (mov->mode == MODE_ISM) {
6131 5 ffio_wfourcc(pb, "piff");
6132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 } else if (mov->mode == MODE_AVIF) {
6133 const AVPixFmtDescriptor *pix_fmt_desc =
6134 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6135 const int depth = pix_fmt_desc->comp[0].depth;
6136 if (mov->is_animated_avif) {
6137 // For animated AVIF, major brand is "avis". Add "avif" as a
6138 // compatible brand.
6139 ffio_wfourcc(pb, "avif");
6140 ffio_wfourcc(pb, "msf1");
6141 ffio_wfourcc(pb, "iso8");
6142 }
6143 ffio_wfourcc(pb, "mif1");
6144 ffio_wfourcc(pb, "miaf");
6145 if (depth == 8 || depth == 10) {
6146 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6147 // computing that is based on chroma subsampling type. 420 chroma
6148 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6149 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6150 // 444 chroma subsampling.
6151 ffio_wfourcc(pb, "MA1A");
6152 } else {
6153 // 420 chroma subsampling.
6154 ffio_wfourcc(pb, "MA1B");
6155 }
6156 }
6157
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 151 times.
216 } else if (mov->mode != MODE_MOV) {
6158 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6159 // brand, if not already the major brand. This is compatible with users that
6160 // don't understand tfdt.
6161
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 2 times.
65 if (mov->mode == MODE_MP4) {
6162
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 61 times.
63 if (mov->flags & FF_MOV_FLAG_CMAF)
6163 2 ffio_wfourcc(pb, "cmfc");
6164
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 4 times.
63 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6165 29 ffio_wfourcc(pb, "iso6");
6166
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 if (has_av1)
6167 1 ffio_wfourcc(pb, "av01");
6168
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 60 times.
63 if (has_dolby)
6169 3 ffio_wfourcc(pb, "dby1");
6170
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 58 times.
63 if (has_iamf)
6171 5 ffio_wfourcc(pb, "iamf");
6172 } else {
6173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6174 ffio_wfourcc(pb, "iso6");
6175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6176 ffio_wfourcc(pb, "iso5");
6177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6178 ffio_wfourcc(pb, "iso4");
6179 }
6180 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6181
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 14 times.
65 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6182 // write isom for mp4 only if it it's not the major brand already.
6183
4/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 47 times.
51 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6184 4 ffio_wfourcc(pb, "isom");
6185 51 ffio_wfourcc(pb, "iso2");
6186
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 30 times.
51 if (has_h264)
6187 21 ffio_wfourcc(pb, "avc1");
6188 }
6189 }
6190
6191
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 158 times.
221 if (mov->mode == MODE_MP4)
6192 63 ffio_wfourcc(pb, "mp41");
6193
6194
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
221 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6195 ffio_wfourcc(pb, "dash");
6196
6197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221 times.
221 if (has_id3)
6198 ffio_wfourcc(pb, "aid3");
6199
6200 221 return update_size(pb, pos);
6201 }
6202
6203 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6204 {
6205 1 AVStream *video_st = s->streams[0];
6206 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6207 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6208 1 int audio_rate = audio_par->sample_rate;
6209 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6210
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 :
6211 0;
6212 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6213 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6214
6215
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) {
6216 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6217 return AVERROR(EINVAL);
6218 }
6219
6220 1 avio_wb32(pb, 0x94); /* size */
6221 1 ffio_wfourcc(pb, "uuid");
6222 1 ffio_wfourcc(pb, "PROF");
6223
6224 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6225 1 avio_wb32(pb, 0xbb88695c);
6226 1 avio_wb32(pb, 0xfac9c740);
6227
6228 1 avio_wb32(pb, 0x0); /* ? */
6229 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6230
6231 1 avio_wb32(pb, 0x14); /* size */
6232 1 ffio_wfourcc(pb, "FPRF");
6233 1 avio_wb32(pb, 0x0); /* ? */
6234 1 avio_wb32(pb, 0x0); /* ? */
6235 1 avio_wb32(pb, 0x0); /* ? */
6236
6237 1 avio_wb32(pb, 0x2c); /* size */
6238 1 ffio_wfourcc(pb, "APRF"); /* audio */
6239 1 avio_wb32(pb, 0x0);
6240 1 avio_wb32(pb, 0x2); /* TrackID */
6241 1 ffio_wfourcc(pb, "mp4a");
6242 1 avio_wb32(pb, 0x20f);
6243 1 avio_wb32(pb, 0x0);
6244 1 avio_wb32(pb, audio_kbitrate);
6245 1 avio_wb32(pb, audio_kbitrate);
6246 1 avio_wb32(pb, audio_rate);
6247 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6248
6249 1 avio_wb32(pb, 0x34); /* size */
6250 1 ffio_wfourcc(pb, "VPRF"); /* video */
6251 1 avio_wb32(pb, 0x0);
6252 1 avio_wb32(pb, 0x1); /* TrackID */
6253
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6254 1 ffio_wfourcc(pb, "avc1");
6255 1 avio_wb16(pb, 0x014D);
6256 1 avio_wb16(pb, 0x0015);
6257 } else {
6258 ffio_wfourcc(pb, "mp4v");
6259 avio_wb16(pb, 0x0000);
6260 avio_wb16(pb, 0x0103);
6261 }
6262 1 avio_wb32(pb, 0x0);
6263 1 avio_wb32(pb, video_kbitrate);
6264 1 avio_wb32(pb, video_kbitrate);
6265 1 avio_wb32(pb, frame_rate);
6266 1 avio_wb32(pb, frame_rate);
6267 1 avio_wb16(pb, video_par->width);
6268 1 avio_wb16(pb, video_par->height);
6269 1 avio_wb32(pb, 0x010001); /* ? */
6270
6271 1 return 0;
6272 }
6273
6274 221 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6275 {
6276 221 MOVMuxContext *mov = s->priv_data;
6277 int i;
6278
6279 221 mov_write_ftyp_tag(pb,s);
6280
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 220 times.
221 if (mov->mode == MODE_PSP) {
6281 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6282
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6283 2 AVStream *st = mov->tracks[i].st;
6284
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6285 continue;
6286
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6287 1 video_streams_nb++;
6288
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6289 1 audio_streams_nb++;
6290 else
6291 other_streams_nb++;
6292 }
6293
6294
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) {
6295 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6296 return AVERROR(EINVAL);
6297 }
6298 1 return mov_write_uuidprof_tag(pb, s);
6299 }
6300 220 return 0;
6301 }
6302
6303 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6304 {
6305 8 uint32_t c = -1;
6306 8 int i, closed_gop = 0;
6307
6308
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6309 368 c = (c << 8) + pkt->data[i];
6310
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6311 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6312
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6313 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6314
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
6315 8 *flags = MOV_SYNC_SAMPLE;
6316 else
6317 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6318 8 break;
6319 }
6320 }
6321 8 return 0;
6322 }
6323
6324 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6325 {
6326 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6327 int seq = 0, entry = 0;
6328 int key = pkt->flags & AV_PKT_FLAG_KEY;
6329 start = find_next_marker(pkt->data, end);
6330 for (next = start; next < end; start = next) {
6331 next = find_next_marker(start + 4, end);
6332 switch (AV_RB32(start)) {
6333 case VC1_CODE_SEQHDR:
6334 seq = 1;
6335 break;
6336 case VC1_CODE_ENTRYPOINT:
6337 entry = 1;
6338 break;
6339 case VC1_CODE_SLICE:
6340 trk->vc1_info.slices = 1;
6341 break;
6342 }
6343 }
6344 if (!trk->entry && trk->vc1_info.first_packet_seen)
6345 trk->vc1_info.first_frag_written = 1;
6346 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6347 /* First packet in first fragment */
6348 trk->vc1_info.first_packet_seq = seq;
6349 trk->vc1_info.first_packet_entry = entry;
6350 trk->vc1_info.first_packet_seen = 1;
6351 } else if ((seq && !trk->vc1_info.packet_seq) ||
6352 (entry && !trk->vc1_info.packet_entry)) {
6353 int i;
6354 for (i = 0; i < trk->entry; i++)
6355 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6356 trk->has_keyframes = 0;
6357 if (seq)
6358 trk->vc1_info.packet_seq = 1;
6359 if (entry)
6360 trk->vc1_info.packet_entry = 1;
6361 if (!trk->vc1_info.first_frag_written) {
6362 /* First fragment */
6363 if ((!seq || trk->vc1_info.first_packet_seq) &&
6364 (!entry || trk->vc1_info.first_packet_entry)) {
6365 /* First packet had the same headers as this one, readd the
6366 * sync sample flag. */
6367 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6368 trk->has_keyframes = 1;
6369 }
6370 }
6371 }
6372 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6373 key = seq && entry;
6374 else if (trk->vc1_info.packet_seq)
6375 key = seq;
6376 else if (trk->vc1_info.packet_entry)
6377 key = entry;
6378 if (key) {
6379 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6380 trk->has_keyframes++;
6381 }
6382 }
6383
6384 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6385 {
6386 int length;
6387
6388 if (pkt->size < 8)
6389 return;
6390
6391 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6392 if (length < 8 || length > pkt->size)
6393 return;
6394
6395 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6396 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6397 trk->has_keyframes++;
6398 }
6399
6400 return;
6401 }
6402
6403 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6404 {
6405 89 MOVMuxContext *mov = s->priv_data;
6406 int ret, buf_size;
6407 uint8_t *buf;
6408 int i, offset;
6409
6410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if (!track->mdat_buf)
6411 return 0;
6412
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!mov->mdat_buf) {
6413
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6414 return ret;
6415 }
6416 89 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6417
6418 89 offset = avio_tell(mov->mdat_buf);
6419 89 avio_write(mov->mdat_buf, buf, buf_size);
6420 89 ffio_reset_dyn_buf(track->mdat_buf);
6421
6422
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 89 times.
177 for (i = track->entries_flushed; i < track->entry; i++)
6423 88 track->cluster[i].pos += offset;
6424 89 track->entries_flushed = track->entry;
6425 89 return 0;
6426 }
6427
6428 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6429 {
6430 28 MOVMuxContext *mov = s->priv_data;
6431 28 AVPacket *squashed_packet = mov->pkt;
6432 28 int ret = AVERROR_BUG;
6433
6434
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6435 28 case AV_CODEC_ID_TTML: {
6436 28 int had_packets = !!track->squashed_packet_queue.head;
6437
6438
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) {
6439 goto finish_squash;
6440 }
6441
6442 // We have generated a padding packet (no actual input packets in
6443 // queue) and its duration is zero. Skipping writing it.
6444
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) {
6445 goto finish_squash;
6446 }
6447
6448 28 track->end_reliable = 1;
6449 28 break;
6450 }
6451 default:
6452 ret = AVERROR(EINVAL);
6453 goto finish_squash;
6454 }
6455
6456 28 squashed_packet->stream_index = track->st->index;
6457
6458 28 ret = mov_write_single_packet(s, squashed_packet);
6459
6460 28 finish_squash:
6461 28 av_packet_unref(squashed_packet);
6462
6463 28 return ret;
6464 }
6465
6466 356 static int mov_write_squashed_packets(AVFormatContext *s)
6467 {
6468 356 MOVMuxContext *mov = s->priv_data;
6469
6470
2/2
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 356 times.
888 for (int i = 0; i < mov->nb_streams; i++) {
6471 532 MOVTrack *track = &mov->tracks[i];
6472 532 int ret = AVERROR_BUG;
6473
6474
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 502 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
532 if (track->squash_fragment_samples_to_one && !track->entry) {
6475
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6476 av_log(s, AV_LOG_ERROR,
6477 "Failed to write squashed packet for %s stream with "
6478 "index %d and track id %d. Error: %s\n",
6479 avcodec_get_name(track->st->codecpar->codec_id),
6480 track->st->index, track->track_id,
6481 av_err2str(ret));
6482 return ret;
6483 }
6484 }
6485 }
6486
6487 356 return 0;
6488 }
6489
6490 181 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6491 int64_t ref_pos)
6492 {
6493 int i;
6494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 if (!track->entry)
6495 return 0;
6496
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 173 times.
181 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6497
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6498 124 track->cluster[i].pos += ref_pos + track->data_offset;
6499
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6500 // First flush. Chunking for this fragment may already have been
6501 // done, either if we didn't use empty_moov, or if we did use
6502 // delay_moov. In either case, reset chunking here.
6503
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6504 63 track->cluster[i].chunkNum = 0;
6505 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6506 }
6507 }
6508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6509 8 track->entry_written + track->entry,
6510 sizeof(*track->cluster)))
6511 return AVERROR(ENOMEM);
6512 8 memcpy(&track->cluster_written[track->entry_written],
6513 8 track->cluster, track->entry * sizeof(*track->cluster));
6514 8 track->entry_written += track->entry;
6515 }
6516 181 track->entry = 0;
6517 181 track->entries_flushed = 0;
6518 181 track->end_reliable = 0;
6519 181 return 0;
6520 }
6521
6522 137 static int mov_flush_fragment(AVFormatContext *s, int force)
6523 {
6524 137 MOVMuxContext *mov = s->priv_data;
6525 137 int i, first_track = -1;
6526 137 int64_t mdat_size = 0, mdat_start = 0;
6527 int ret;
6528 137 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6529
6530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
137 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6531 return 0;
6532
6533 // Check if we have any tracks that require squashing.
6534 // In that case, we'll have to write the packet here.
6535
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
137 if ((ret = mov_write_squashed_packets(s)) < 0)
6536 return ret;
6537
6538 // Try to fill in the duration of the last packet in each stream
6539 // from queued packets in the interleave queues. If the flushing
6540 // of fragments was triggered automatically by an AVPacket, we
6541 // already have reliable info for the end of that track, but other
6542 // tracks may need to be filled in.
6543
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 137 times.
388 for (i = 0; i < mov->nb_streams; i++) {
6544 251 MOVTrack *track = &mov->tracks[i];
6545
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 89 times.
251 if (!track->end_reliable) {
6546 162 const AVPacket *pkt = ff_interleaved_peek(s, i);
6547
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 156 times.
162 if (pkt) {
6548 int64_t offset, dts, pts;
6549 6 ff_get_muxer_ts_offset(s, i, &offset);
6550 6 pts = pkt->pts + offset;
6551 6 dts = pkt->dts + offset;
6552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6553 dts += track->dts_shift;
6554 6 track->track_duration = dts - track->start_dts;
6555
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6556 6 track->end_pts = pts;
6557 else
6558 track->end_pts = dts;
6559
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
6560 6 track->elst_end_pts = track->end_pts;
6561 }
6562 }
6563 }
6564
6565
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 137 times.
394 for (i = 0; i < mov->nb_tracks; i++) {
6566 257 MOVTrack *track = &mov->tracks[i];
6567
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 183 times.
257 if (track->entry <= 1)
6568 74 continue;
6569 // Sample durations are calculated as the diff of dts values,
6570 // but for the last sample in a fragment, we don't know the dts
6571 // of the first sample in the next fragment, so we have to rely
6572 // on what was set as duration in the AVPacket. Not all callers
6573 // set this though, so we might want to replace it with an
6574 // estimate if it currently is zero.
6575
2/2
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 2 times.
183 if (get_cluster_duration(track, track->entry - 1) != 0)
6576 181 continue;
6577 // Use the duration (i.e. dts diff) of the second last sample for
6578 // the last one. This is a wild guess (and fatal if it turns out
6579 // to be too long), but probably the best we can do - having a zero
6580 // duration is bad as well.
6581 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6582 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6583
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6584 2 av_log(s, AV_LOG_WARNING,
6585 "Estimating the duration of the last packet in a "
6586 "fragment, consider setting the duration field in "
6587 "AVPacket instead.\n");
6588 2 mov->missing_duration_warned = 1;
6589 }
6590 }
6591
6592
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 113 times.
137 if (!mov->moov_written) {
6593 24 int64_t pos = avio_tell(s->pb);
6594 uint8_t *buf;
6595 int buf_size, moov_size;
6596
6597
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 20 times.
66 for (i = 0; i < mov->nb_tracks; i++)
6598
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 42 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
46 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6599 4 break;
6600 /* Don't write the initial moov unless all tracks have data */
6601
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
24 if (i < mov->nb_tracks && !force)
6602 2 return 0;
6603
6604 22 moov_size = get_moov_size(s);
6605
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 22 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6606 42 mov->tracks[i].data_offset = pos + moov_size + 8;
6607
6608 22 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6609
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6610
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6611 18 mov_write_identification(s->pb, s);
6612
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6613 return ret;
6614
6615
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6617 mov->reserved_header_pos = avio_tell(s->pb);
6618 18 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6619 18 mov->moov_written = 1;
6620 18 return 0;
6621 }
6622
6623 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6624 4 avio_wb32(s->pb, buf_size + 8);
6625 4 ffio_wfourcc(s->pb, "mdat");
6626 4 avio_write(s->pb, buf, buf_size);
6627 4 ffio_reset_dyn_buf(mov->mdat_buf);
6628
6629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6630 mov->reserved_header_pos = avio_tell(s->pb);
6631
6632 4 mov->moov_written = 1;
6633 4 mov->mdat_size = 0;
6634
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6635 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6636 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6637 4 return 0;
6638 }
6639
6640
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111 times.
113 if (mov->frag_interleave) {
6641
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6642 4 MOVTrack *track = &mov->tracks[i];
6643 int ret;
6644
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6645 return ret;
6646 }
6647
6648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6649 return 0;
6650 2 mdat_size = avio_tell(mov->mdat_buf);
6651 }
6652
6653
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 113 times.
324 for (i = 0; i < mov->nb_tracks; i++) {
6654 211 MOVTrack *track = &mov->tracks[i];
6655
4/4
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 162 times.
211 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6656 49 track->data_offset = 0;
6657 else
6658 162 track->data_offset = mdat_size;
6659
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 110 times.
211 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6660 101 has_video = 1;
6661
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (first_video_track) {
6662
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 13 times.
101 if (track->entry)
6663 88 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6664 101 first_video_track = 0;
6665 }
6666 }
6667
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 173 times.
211 if (!track->entry)
6668 38 continue;
6669
1/2
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
173 if (track->mdat_buf)
6670 173 mdat_size += avio_tell(track->mdat_buf);
6671
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 77 times.
173 if (first_track < 0)
6672 96 first_track = i;
6673 }
6674
6675
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 96 times.
113 if (!mdat_size)
6676 17 return 0;
6677
6678
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4 times.
96 avio_write_marker(s->pb,
6679 96 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6680
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 7 times.
96 (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);
6681
6682
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 96 times.
277 for (i = first_track; i < mov->nb_tracks; i++) {
6683 181 MOVTrack *track = &mov->tracks[i];
6684 181 int buf_size, write_moof = 1, moof_tracks = -1;
6685 uint8_t *buf;
6686
6687
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 173 times.
181 if (!track->entry)
6688 8 continue;
6689
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 132 times.
173 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6690 41 mdat_size = avio_tell(track->mdat_buf);
6691 41 moof_tracks = i;
6692 } else {
6693 132 write_moof = i == first_track;
6694 }
6695
6696
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 60 times.
173 if (write_moof) {
6697 113 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6698
6699 113 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6700 113 mov->fragments++;
6701
6702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 if (track->cenc.aes_ctr)
6703 ff_mov_cenc_flush(&track->cenc);
6704
6705 113 avio_wb32(s->pb, mdat_size + 8);
6706 113 ffio_wfourcc(s->pb, "mdat");
6707 113 mdat_start = avio_tell(s->pb);
6708 }
6709
6710 173 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6711
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 if (!mov->frag_interleave) {
6712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (!track->mdat_buf)
6713 continue;
6714 170 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6715 170 avio_write(s->pb, buf, buf_size);
6716 170 ffio_reset_dyn_buf(track->mdat_buf);
6717 } else {
6718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!mov->mdat_buf)
6719 continue;
6720 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6721 3 avio_write(s->pb, buf, buf_size);
6722 3 ffio_reset_dyn_buf(mov->mdat_buf);
6723 }
6724 }
6725
6726 96 mov->mdat_size = 0;
6727
6728 96 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6729 96 return 0;
6730 }
6731
6732 91 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6733 {
6734 91 MOVMuxContext *mov = s->priv_data;
6735 91 int had_moov = mov->moov_written;
6736 91 int ret = mov_flush_fragment(s, force);
6737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 if (ret < 0)
6738 return ret;
6739 // If using delay_moov, the first flush only wrote the moov,
6740 // not the actual moof+mdat pair, thus flush once again.
6741
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4 times.
91 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6742 9 ret = mov_flush_fragment(s, force);
6743 91 return ret;
6744 }
6745
6746 39329 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6747 {
6748 int64_t ref;
6749 uint64_t duration;
6750
6751
2/2
✓ Branch 0 taken 38590 times.
✓ Branch 1 taken 739 times.
39329 if (trk->entry) {
6752 38590 ref = trk->cluster[trk->entry - 1].dts;
6753
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 552 times.
739 } else if ( trk->start_dts != AV_NOPTS_VALUE
6754
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 8 times.
187 && !trk->frag_discont) {
6755 179 ref = trk->start_dts + trk->track_duration;
6756 } else
6757 560 ref = pkt->dts; // Skip tests for the first packet
6758
6759
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 35274 times.
39329 if (trk->dts_shift != AV_NOPTS_VALUE) {
6760 /* With negative CTS offsets we have set an offset to the DTS,
6761 * reverse this for the check. */
6762 4055 ref -= trk->dts_shift;
6763 }
6764
6765 39329 duration = pkt->dts - ref;
6766
2/4
✓ Branch 0 taken 39329 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39329 times.
39329 if (pkt->dts < ref || duration >= INT_MAX) {
6767 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6768 duration, pkt->dts, pkt->stream_index);
6769
6770 pkt->dts = ref + 1;
6771 pkt->pts = AV_NOPTS_VALUE;
6772 }
6773
6774
2/4
✓ Branch 0 taken 39329 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39329 times.
39329 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6775 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6776 return AVERROR(EINVAL);
6777 }
6778 39329 return 0;
6779 }
6780
6781 19683 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6782 {
6783 19683 MOVMuxContext *mov = s->priv_data;
6784 19683 AVIOContext *pb = s->pb;
6785 MOVTrack *trk;
6786 AVCodecParameters *par;
6787 AVProducerReferenceTime *prft;
6788 19683 unsigned int samples_in_chunk = 0;
6789 19683 int size = pkt->size, ret = 0, offset = 0;
6790 size_t prft_size;
6791 19683 uint8_t *reformatted_data = NULL;
6792
6793
2/2
✓ Branch 0 taken 19637 times.
✓ Branch 1 taken 46 times.
19683 if (pkt->stream_index < s->nb_streams)
6794 19637 trk = s->streams[pkt->stream_index]->priv_data;
6795 else // Timecode or chapter
6796 46 trk = &mov->tracks[pkt->stream_index];
6797 19683 par = trk->par;
6798
6799 19683 ret = check_pkt(s, trk, pkt);
6800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19683 times.
19683 if (ret < 0)
6801 return ret;
6802
6803
2/2
✓ Branch 0 taken 19079 times.
✓ Branch 1 taken 604 times.
19683 if (pkt->pts != AV_NOPTS_VALUE &&
6804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19079 times.
19079 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
6805 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6806 return AVERROR_PATCHWELCOME;
6807 }
6808
6809
3/4
✓ Branch 0 taken 13089 times.
✓ Branch 1 taken 6594 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13089 times.
19683 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6810 int ret;
6811
4/4
✓ Branch 0 taken 2174 times.
✓ Branch 1 taken 4420 times.
✓ Branch 2 taken 1936 times.
✓ Branch 3 taken 238 times.
6594 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
6812
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 6268 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
6356 if (mov->frag_interleave && mov->fragments > 0) {
6813
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6814
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6815 return ret;
6816 }
6817 }
6818
6819
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 6286 times.
6356 if (!trk->mdat_buf) {
6820
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
70 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6821 return ret;
6822 }
6823 6356 pb = trk->mdat_buf;
6824 } else {
6825
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6826
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6827 return ret;
6828 }
6829 238 pb = mov->mdat_buf;
6830 }
6831 }
6832
6833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19683 times.
19683 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6834 /* We must find out how many AMR blocks there are in one packet */
6835 static const uint16_t packed_size[16] =
6836 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6837 int len = 0;
6838
6839 while (len < size && samples_in_chunk < 100) {
6840 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6841 samples_in_chunk++;
6842 }
6843 if (samples_in_chunk > 1) {
6844 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6845 return -1;
6846 }
6847
1/2
✓ Branch 0 taken 19683 times.
✗ Branch 1 not taken.
19683 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19683 times.
19683 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6849 samples_in_chunk = trk->par->frame_size;
6850
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 18269 times.
19683 } else if (trk->sample_size)
6851 1414 samples_in_chunk = size / trk->sample_size;
6852 else
6853 18269 samples_in_chunk = 1;
6854
6855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19683 times.
19683 if (samples_in_chunk < 1) {
6856 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6857 return AVERROR_PATCHWELCOME;
6858 }
6859
6860 /* copy extradata if it exists */
6861
3/4
✓ Branch 0 taken 6672 times.
✓ Branch 1 taken 13011 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6672 times.
19683 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
6862 !TAG_IS_AVCI(trk->tag) &&
6863 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6864 trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
6865 if (!trk->extradata[0]) {
6866 ret = AVERROR(ENOMEM);
6867 goto err;
6868 }
6869 trk->extradata_size[0] = par->extradata_size;
6870 }
6871
6872
2/2
✓ Branch 0 taken 19568 times.
✓ Branch 1 taken 115 times.
19683 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6873
2/2
✓ Branch 0 taken 16976 times.
✓ Branch 1 taken 2592 times.
19568 par->codec_id == AV_CODEC_ID_H264 ||
6874
2/2
✓ Branch 0 taken 16611 times.
✓ Branch 1 taken 365 times.
16976 par->codec_id == AV_CODEC_ID_HEVC ||
6875
2/2
✓ Branch 0 taken 16601 times.
✓ Branch 1 taken 10 times.
16611 par->codec_id == AV_CODEC_ID_VVC ||
6876
1/2
✓ Branch 0 taken 16601 times.
✗ Branch 1 not taken.
16601 par->codec_id == AV_CODEC_ID_VP9 ||
6877
2/2
✓ Branch 0 taken 16301 times.
✓ Branch 1 taken 300 times.
16601 par->codec_id == AV_CODEC_ID_EVC ||
6878
1/2
✓ Branch 0 taken 16301 times.
✗ Branch 1 not taken.
16301 par->codec_id == AV_CODEC_ID_LCEVC ||
6879
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16301 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3358 times.
19683 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
6880
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)) {
6881 /* copy frame to create needed atoms */
6882 24 trk->extradata_size[0] = size;
6883 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
6885 ret = AVERROR(ENOMEM);
6886 goto err;
6887 }
6888 24 memcpy(trk->extradata[0], pkt->data, size);
6889 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6890 }
6891
6892 19683 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
6893
4/6
✓ Branch 0 taken 19683 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 19681 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
19683 if (pkt->size && sd && sd->size > 0) {
6894 int i;
6895
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < trk->stsd_count; i++) {
6896
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
6897 1 break;
6898 }
6899
6900
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (i < trk->stsd_count)
6901 1 trk->last_stsd_index = i;
6902
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (trk->stsd_count <= INT_MAX - 1) {
6903 1 int new_count = trk->stsd_count + 1;
6904 1 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
6905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!extradata)
6906 return AVERROR(ENOMEM);
6907 1 trk->extradata = extradata;
6908
6909 1 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
6910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!extradata_size)
6911 return AVERROR(ENOMEM);
6912 1 trk->extradata_size = extradata_size;
6913
6914 1 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
6915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!trk->extradata[trk->stsd_count])
6916 return AVERROR(ENOMEM);
6917
6918 1 trk->extradata_size[trk->stsd_count] = sd->size;
6919 1 trk->last_stsd_index = trk->stsd_count;
6920 1 trk->stsd_count = new_count;
6921 } else
6922 return AVERROR(ENOMEM);
6923 }
6924
6925
3/4
✓ Branch 0 taken 5584 times.
✓ Branch 1 taken 14099 times.
✓ Branch 2 taken 5584 times.
✗ Branch 3 not taken.
19683 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5584 times.
5584 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6927 if (!trk->st->nb_frames) {
6928 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6929 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6930 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6931 return -1;
6932 }
6933 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6934 }
6935
3/4
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 17091 times.
✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
19683 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
6936
16/30
✓ Branch 0 taken 498 times.
✓ Branch 1 taken 2094 times.
✓ Branch 2 taken 498 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 498 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 498 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 498 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 498 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 498 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 498 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 498 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 498 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 498 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 498 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 498 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 498 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 498 times.
✗ Branch 29 not taken.
2592 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
6937 /* from x264 or from bytestream H.264 */
6938 /* NAL reformatting needed */
6939
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6940 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6941 &size);
6942 if (ret < 0)
6943 return ret;
6944 avio_write(pb, reformatted_data, size);
6945 } else {
6946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6947 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6948 if (size < 0) {
6949 ret = size;
6950 goto err;
6951 }
6952 } else {
6953 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6954 }
6955 }
6956
3/4
✓ Branch 0 taken 365 times.
✓ Branch 1 taken 18820 times.
✓ Branch 2 taken 365 times.
✗ Branch 3 not taken.
19185 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
6957
3/4
✓ Branch 0 taken 365 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 354 times.
✓ Branch 3 taken 11 times.
719 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
6958 /* extradata is Annex B, assume the bitstream is too and convert it */
6959 354 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6960
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 354 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
354 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6961 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6962 &size, filter_ps, NULL);
6963 if (ret < 0)
6964 return ret;
6965 avio_write(pb, reformatted_data, size);
6966 } else {
6967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 354 times.
354 if (trk->cenc.aes_ctr) {
6968 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6969 if (size < 0) {
6970 ret = size;
6971 goto err;
6972 }
6973 } else {
6974 354 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6975 }
6976 }
6977
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 18821 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
18831 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
6978
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)) {
6979 /* extradata is Annex B, assume the bitstream is too and convert it */
6980
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) {
6981 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6982 &size, 0, NULL);
6983 if (ret < 0)
6984 return ret;
6985 avio_write(pb, reformatted_data, size);
6986 } else {
6987 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6988 }
6989
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18821 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18821 } else if (par->codec_id == AV_CODEC_ID_LCEVC && trk->extradata_size[trk->last_stsd_index] > 0 &&
6990 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1) {
6991 /* extradata is Annex B, assume the bitstream is too and convert it */
6992 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6993 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size);
6994 if (ret < 0)
6995 return ret;
6996 avio_write(pb, reformatted_data, size);
6997 } else {
6998 if (trk->cenc.aes_ctr) {
6999 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7000 if (size < 0) {
7001 ret = size;
7002 goto err;
7003 }
7004 } else {
7005 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7006 }
7007 }
7008
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18817 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
18821 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
7009
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) {
7010 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
7011 &size, &offset);
7012 if (ret < 0)
7013 return ret;
7014 avio_write(pb, reformatted_data, size);
7015 } else {
7016 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
7017
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]) {
7018 mov->avif_extent_length[pkt->stream_index] = size;
7019 }
7020 }
7021
7022
2/2
✓ Branch 0 taken 18430 times.
✓ Branch 1 taken 387 times.
18817 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
7023
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 17778 times.
18430 par->codec_id == AV_CODEC_ID_EAC3) {
7024 1039 size = handle_eac3(mov, pkt, trk);
7025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
7026 return size;
7027
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
7028 1 goto end;
7029 1038 avio_write(pb, pkt->data, size);
7030
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17778 times.
17778 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
7031 size = 8;
7032
7033 for (int i = 0; i < pkt->size; i += 3) {
7034 if (pkt->data[i] == 0xFC) {
7035 size += 2;
7036 }
7037 }
7038 avio_wb32(pb, size);
7039 ffio_wfourcc(pb, "cdat");
7040 for (int i = 0; i < pkt->size; i += 3) {
7041 if (pkt->data[i] == 0xFC) {
7042 avio_w8(pb, pkt->data[i + 1]);
7043 avio_w8(pb, pkt->data[i + 2]);
7044 }
7045 }
7046
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 17775 times.
17778 } else if (par->codec_id == AV_CODEC_ID_APV) {
7047 3 ff_isom_parse_apvc(trk->apv, pkt, s);
7048 3 avio_wb32(s->pb, pkt->size);
7049 3 size += 4;
7050
7051 3 avio_write(s->pb, pkt->data, pkt->size);
7052 } else {
7053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17775 times.
17775 if (trk->cenc.aes_ctr) {
7054 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
7055 int extradata_size = trk->extradata_size[trk->last_stsd_index];
7056 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
7057 int nal_size_length = (extradata[4] & 0x3) + 1;
7058 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7059 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
7060 int nal_size_length = (extradata[21] & 0x3) + 1;
7061 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7062 } else if(par->codec_id == AV_CODEC_ID_VVC) {
7063 ret = AVERROR_PATCHWELCOME;
7064 } else if(par->codec_id == AV_CODEC_ID_AV1) {
7065 av_assert0(size == pkt->size);
7066 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
7067 if (ret > 0) {
7068 size = ret;
7069 ret = 0;
7070 }
7071 } else {
7072 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
7073 }
7074
7075 if (ret) {
7076 goto err;
7077 }
7078 } else {
7079 17775 avio_write(pb, pkt->data, size);
7080 }
7081 }
7082
7083
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 19395 times.
19682 if (trk->entry >= trk->cluster_capacity) {
7084 287 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
7085 287 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
7086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (!cluster) {
7087 ret = AVERROR(ENOMEM);
7088 goto err;
7089 }
7090 287 trk->cluster = cluster;
7091 287 trk->cluster_capacity = new_capacity;
7092 }
7093
7094 19682 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7095 19682 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7096 19682 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7097 19682 trk->cluster[trk->entry].chunkNum = 0;
7098 19682 trk->cluster[trk->entry].size = size;
7099 19682 trk->cluster[trk->entry].entries = samples_in_chunk;
7100 19682 trk->cluster[trk->entry].dts = pkt->dts;
7101 19682 trk->cluster[trk->entry].pts = pkt->pts;
7102
2/2
✓ Branch 0 taken 19654 times.
✓ Branch 1 taken 28 times.
19682 if (!trk->squash_fragment_samples_to_one &&
7103
4/4
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 19285 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 269 times.
19654 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7104
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 4 times.
100 if (!trk->frag_discont) {
7105 /* First packet of a new fragment. We already wrote the duration
7106 * of the last packet of the previous fragment based on track_duration,
7107 * which might not exactly match our dts. Therefore adjust the dts
7108 * of this packet to be what the previous packets duration implies. */
7109 96 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7110 /* We also may have written the pts and the corresponding duration
7111 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7112 * the next fragment. This means the cts of the first sample must
7113 * be the same in all fragments, unless end_pts was updated by
7114 * the packet causing the fragment to be written. */
7115
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 82 times.
96 if ((mov->flags & FF_MOV_FLAG_DASH &&
7116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7117
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 60 times.
82 mov->mode == MODE_ISM)
7118 36 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7119 } else {
7120 /* New fragment, but discontinuous from previous fragments.
7121 * Pretend the duration sum of the earlier fragments is
7122 * pkt->dts - trk->start_dts. */
7123 4 trk->end_pts = trk->elst_end_pts = AV_NOPTS_VALUE;
7124 4 trk->frag_discont = 0;
7125 }
7126 }
7127
7128
6/6
✓ Branch 0 taken 397 times.
✓ Branch 1 taken 19285 times.
✓ Branch 2 taken 273 times.
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 237 times.
19682 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7129
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 15 times.
36 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7130 /* Not using edit lists and shifting the first track to start from zero.
7131 * If the other streams start from a later timestamp, we won't be able
7132 * to signal the difference in starting time without an edit list.
7133 * Thus move the timestamp for this first sample to 0, increasing
7134 * its duration instead. */
7135 21 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7136 }
7137
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 19430 times.
19682 if (trk->start_dts == AV_NOPTS_VALUE) {
7138 252 trk->start_dts = pkt->dts;
7139
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 246 times.
252 if (trk->frag_discont) {
7140
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7141 /* Pretend the whole stream started at pts=0, with earlier fragments
7142 * already written. If the stream started at pts=0, the duration sum
7143 * of earlier fragments would have been pkt->pts. */
7144 4 trk->start_dts = pkt->dts - pkt->pts;
7145 } else {
7146 /* Pretend the whole stream started at dts=0, with earlier fragments
7147 * already written, with a duration summing up to pkt->dts. */
7148 2 trk->start_dts = 0;
7149 }
7150 6 trk->frag_discont = 0;
7151
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 34 times.
246 } else if (pkt->dts && mov->moov_written)
7152 2 av_log(s, AV_LOG_WARNING,
7153 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7154 "already has been written. Set the delay_moov flag to handle "
7155 "this case.\n",
7156 pkt->stream_index, pkt->dts);
7157 }
7158 19682 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7159 19682 trk->last_sample_is_subtitle_end = 0;
7160
7161
2/2
✓ Branch 0 taken 604 times.
✓ Branch 1 taken 19078 times.
19682 if (pkt->pts == AV_NOPTS_VALUE) {
7162 604 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7163 604 pkt->pts = pkt->dts;
7164 }
7165
2/2
✓ Branch 0 taken 1394 times.
✓ Branch 1 taken 18288 times.
19682 if (pkt->dts != pkt->pts)
7166 1394 trk->flags |= MOV_TRACK_CTTS;
7167 19682 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7168 19682 trk->cluster[trk->entry].flags = 0;
7169
6/6
✓ Branch 0 taken 19409 times.
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 19351 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 53 times.
19682 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7170 278 trk->start_cts = pkt->pts - pkt->dts;
7171
2/2
✓ Branch 0 taken 277 times.
✓ Branch 1 taken 19405 times.
19682 if (trk->end_pts == AV_NOPTS_VALUE)
7172 277 trk->end_pts = trk->cluster[trk->entry].dts +
7173 277 trk->cluster[trk->entry].cts + pkt->duration;
7174 else
7175 19405 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7176 trk->cluster[trk->entry].cts +
7177 pkt->duration);
7178
2/2
✓ Branch 0 taken 19681 times.
✓ Branch 1 taken 1 times.
19682 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7179 19681 trk->elst_end_pts = trk->end_pts;
7180
7181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19682 times.
19682 if (par->codec_id == AV_CODEC_ID_VC1) {
7182 mov_parse_vc1_frame(pkt, trk);
7183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19682 times.
19682 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7184 mov_parse_truehd_frame(pkt, trk);
7185
2/2
✓ Branch 0 taken 13689 times.
✓ Branch 1 taken 5993 times.
19682 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7186
4/4
✓ Branch 0 taken 6367 times.
✓ Branch 1 taken 7322 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6358 times.
13689 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7187
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7188 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7190 trk->flags |= MOV_TRACK_STPS;
7191 } else {
7192 13681 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7193 }
7194
1/2
✓ Branch 0 taken 13689 times.
✗ Branch 1 not taken.
13689 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7195 13689 trk->has_keyframes++;
7196 }
7197
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 19675 times.
19682 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7198 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7199 7 trk->has_disposable++;
7200 }
7201
7202 19682 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7203
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19682 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
19682 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7204 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7205 else
7206 19682 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7207
7208 19682 trk->entry++;
7209 19682 trk->sample_count += samples_in_chunk;
7210 19682 mov->mdat_size += size;
7211
7212
3/4
✓ Branch 0 taken 19600 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
19682 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7213 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7215 : NULL, size);
7216
7217 19683 end:
7218 19683 err:
7219
7220
1/2
✓ Branch 0 taken 19683 times.
✗ Branch 1 not taken.
19683 if (pkt->data != reformatted_data)
7221 19683 av_free(reformatted_data);
7222 19683 return ret;
7223 }
7224
7225 19646 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7226 {
7227 19646 MOVMuxContext *mov = s->priv_data;
7228 19646 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7229 19646 AVCodecParameters *par = trk->par;
7230 19646 int64_t frag_duration = 0;
7231 19646 int size = pkt->size;
7232
7233 19646 int ret = check_pkt(s, trk, pkt);
7234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19646 times.
19646 if (ret < 0)
7235 return ret;
7236
7237
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 19641 times.
19646 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7238
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7239 10 mov->tracks[i].frag_discont = 1;
7240 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7241 }
7242
7243
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 17634 times.
19646 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7244
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7245 15 trk->dts_shift = pkt->pts - pkt->dts;
7246 2012 pkt->dts += trk->dts_shift;
7247 }
7248
7249
1/2
✓ Branch 0 taken 19646 times.
✗ Branch 1 not taken.
19646 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7250
2/2
✓ Branch 0 taken 14060 times.
✓ Branch 1 taken 5586 times.
19646 trk->par->codec_id == AV_CODEC_ID_AAC ||
7251
2/2
✓ Branch 0 taken 14056 times.
✓ Branch 1 taken 4 times.
14060 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7252
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 14001 times.
14056 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7253 size_t side_size;
7254 5645 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7255 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7256
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5639 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
5645 if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
7257 6 void *newextra = av_malloc(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7259 return AVERROR(ENOMEM);
7260 6 memset((uint8_t*)newextra + side_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7261 6 memcpy(newextra, side, side_size);
7262 6 av_free(trk->extradata[trk->last_stsd_index]);
7263 6 trk->extradata[trk->last_stsd_index] = newextra;
7264 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7265 }
7266 }
7267
7268
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 19637 times.
19646 if (!pkt->size) {
7269
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) {
7270 4 trk->start_dts = pkt->dts;
7271
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7272 4 trk->start_cts = pkt->pts - pkt->dts;
7273 else
7274 trk->start_cts = 0;
7275 }
7276
7277 9 return 0; /* Discard 0 sized packets */
7278 }
7279
7280
4/4
✓ Branch 0 taken 19300 times.
✓ Branch 1 taken 337 times.
✓ Branch 2 taken 19276 times.
✓ Branch 3 taken 24 times.
19637 if (trk->entry && pkt->stream_index < mov->nb_streams)
7281 19276 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7282 19276 s->streams[pkt->stream_index]->time_base,
7283 19276 AV_TIME_BASE_Q);
7284
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 19376 times.
19637 if ((mov->max_fragment_duration &&
7285
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7286
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19633 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
19633 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7287
2/2
✓ Branch 0 taken 4875 times.
✓ Branch 1 taken 14758 times.
19633 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7288
2/2
✓ Branch 0 taken 2301 times.
✓ Branch 1 taken 2574 times.
4875 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7289
4/4
✓ Branch 0 taken 2275 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 2226 times.
✓ Branch 3 taken 49 times.
2301 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19584 times.
19584 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7291
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (frag_duration >= mov->min_fragment_duration) {
7292
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (trk->entry) {
7293 // Set the duration of this track to line up with the next
7294 // sample in this track. This avoids relying on AVPacket
7295 // duration, but only helps for this particular track, not
7296 // for the other ones that are flushed at the same time.
7297 //
7298 // If we have trk->entry == 0, no fragment will be written
7299 // for this track, and we can't adjust the track end here.
7300 53 trk->track_duration = pkt->dts - trk->start_dts;
7301
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (pkt->pts != AV_NOPTS_VALUE)
7302 53 trk->end_pts = pkt->pts;
7303 else
7304 trk->end_pts = pkt->dts;
7305
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7306 53 trk->elst_end_pts = trk->end_pts;
7307 53 trk->end_reliable = 1;
7308 }
7309 53 mov_auto_flush_fragment(s, 0);
7310 }
7311 }
7312
7313 19637 return ff_mov_write_packet(s, pkt);
7314 }
7315
7316 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7317 int stream_index,
7318 int64_t dts) {
7319 3 MOVMuxContext *mov = s->priv_data;
7320 3 AVPacket *end = mov->pkt;
7321 3 uint8_t data[2] = {0};
7322 int ret;
7323
7324 3 end->size = sizeof(data);
7325 3 end->data = data;
7326 3 end->pts = dts;
7327 3 end->dts = dts;
7328 3 end->duration = 0;
7329 3 end->stream_index = stream_index;
7330
7331 3 ret = mov_write_single_packet(s, end);
7332 3 av_packet_unref(end);
7333
7334 3 return ret;
7335 }
7336
7337 #if CONFIG_IAMFENC
7338 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7339 {
7340 uint8_t *data;
7341 int ret;
7342
7343
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7344 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7346 return ret;
7347 }
7348
7349 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7350 275 s->streams[pkt->stream_index]->id, pkt);
7351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7352 return ret;
7353
7354
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7355 220 return AVERROR(EAGAIN);
7356
7357 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7358 55 trk->iamf_buf = NULL;
7359
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7361 // Either all or none of the packets for a single
7362 // IA Sample may be empty.
7363 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7364 "stream #%d\n", pkt->stream_index);
7365 ret = AVERROR_INVALIDDATA;
7366 }
7367 5 av_free(data);
7368 5 return ret;
7369 }
7370
7371 50 av_buffer_unref(&pkt->buf);
7372 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7374 av_free(data);
7375 return AVERROR(ENOMEM);
7376 }
7377 50 pkt->data = data;
7378 50 pkt->size = ret;
7379 50 pkt->stream_index = trk->first_iamf_idx;
7380
7381 50 return avio_open_dyn_buf(&trk->iamf_buf);
7382 }
7383 #endif
7384
7385 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7386 {
7387 2 int64_t pos = avio_tell(pb);
7388 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7389 2 const char *value = "";
7390
7391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7392
7393 2 avio_write_marker(pb,
7394 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7395 AVIO_DATA_MARKER_BOUNDARY_POINT);
7396
7397 2 avio_wb32(pb, 0); /* size */
7398 2 ffio_wfourcc(pb, "emsg");
7399 2 avio_w8(pb, 1); /* version */
7400 2 avio_wb24(pb, 0);
7401 2 avio_wb32(pb, st->time_base.den); /* timescale */
7402 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7403 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7404 2 avio_wb32(pb, 0); /* id */
7405 /* null terminated UTF8 strings */
7406 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7407 2 avio_write(pb, value, strlen(value) + 1);
7408 2 avio_write(pb, pkt->data, pkt->size);
7409
7410 2 return update_size(pb, pos);
7411 }
7412
7413 20024 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7414 {
7415 20024 MOVMuxContext *mov = s->priv_data;
7416 MOVTrack *trk;
7417
7418
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 19987 times.
20024 if (!pkt) {
7419 37 mov_flush_fragment(s, 1);
7420 37 return 1;
7421 }
7422
7423
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19985 times.
19987 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7424 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7425 2 return 0;
7426 }
7427
7428 19985 trk = s->streams[pkt->stream_index]->priv_data;
7429
7430 #if CONFIG_IAMFENC
7431
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 19710 times.
19985 if (trk->iamf) {
7432 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7433
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7434
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7435 220 return 0;
7436 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7437 "for stream #%d\n", trk->st->index);
7438 return ret;
7439 }
7440 }
7441 #endif
7442
7443
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 19763 times.
19765 if (is_cover_image(trk->st)) {
7444 int ret;
7445
7446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7447 if (trk->st->nb_frames == 1)
7448 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7449 " ignoring.\n", pkt->stream_index);
7450 return 0;
7451 }
7452
7453
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7454 return ret;
7455
7456 2 return 0;
7457 } else {
7458 int i;
7459
7460
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 19754 times.
19763 if (!pkt->size)
7461 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7462
7463 /*
7464 * Subtitles require special handling.
7465 *
7466 * 1) For full compliance, every track must have a sample at
7467 * dts == 0, which is rarely true for subtitles. So, as soon
7468 * as we see any packet with dts > 0, write an empty subtitle
7469 * at dts == 0 for any subtitle track with no samples in it.
7470 *
7471 * 2) For each subtitle track, check if the current packet's
7472 * dts is past the duration of the last subtitle sample. If
7473 * so, we now need to write an end sample for that subtitle.
7474 *
7475 * This must be done conditionally to allow for subtitles that
7476 * immediately replace each other, in which case an end sample
7477 * is not needed, and is, in fact, actively harmful.
7478 *
7479 * 3) See mov_write_trailer for how the final end sample is
7480 * handled.
7481 */
7482
2/2
✓ Branch 0 taken 35952 times.
✓ Branch 1 taken 19754 times.
55706 for (i = 0; i < mov->nb_tracks; i++) {
7483 35952 MOVTrack *trk = &mov->tracks[i];
7484 int ret;
7485
7486
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 35949 times.
35952 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7487
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7488
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)) {
7489 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7491 2 trk->last_sample_is_subtitle_end = 1;
7492 }
7493 }
7494
7495
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 19606 times.
19754 if (trk->squash_fragment_samples_to_one) {
7496 /*
7497 * If the track has to have its samples squashed into one sample,
7498 * we just take it into the track's queue.
7499 * This will then be utilized as the samples get written in either
7500 * mov_flush_fragment or when the mux is finalized in
7501 * mov_write_trailer.
7502 */
7503 148 int ret = AVERROR_BUG;
7504
7505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7506 av_log(s, AV_LOG_ERROR,
7507 "Packets without a valid presentation timestamp are "
7508 "not supported with packet squashing!\n");
7509 return AVERROR(EINVAL);
7510 }
7511
7512 /* The following will reset pkt and is only allowed to be used
7513 * because we return immediately. afterwards. */
7514
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7515 pkt, NULL, 0)) < 0) {
7516 return ret;
7517 }
7518
7519 148 return 0;
7520 }
7521
7522
7523
4/4
✓ Branch 0 taken 8037 times.
✓ Branch 1 taken 11569 times.
✓ Branch 2 taken 3914 times.
✓ Branch 3 taken 4123 times.
19606 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7524 3914 AVPacket *opkt = pkt;
7525 int reshuffle_ret, ret;
7526
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3889 times.
3914 if (trk->is_unaligned_qt_rgb) {
7527
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;
7528 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7529 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7531 return reshuffle_ret;
7532 } else
7533 3889 reshuffle_ret = 0;
7534
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3676 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3914 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7535 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7537 goto fail;
7538
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7539 5 trk->pal_done++;
7540
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 3084 times.
3909 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7541
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7543 ret = av_packet_make_writable(pkt);
7544 if (ret < 0)
7545 goto fail;
7546 for (i = 0; i < pkt->size; i++)
7547 pkt->data[i] = ~pkt->data[i];
7548 }
7549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3914 times.
3914 if (reshuffle_ret) {
7550 ret = mov_write_single_packet(s, pkt);
7551 fail:
7552 if (reshuffle_ret)
7553 av_packet_free(&pkt);
7554 return ret;
7555 }
7556 }
7557
7558 19606 return mov_write_single_packet(s, pkt);
7559 }
7560 }
7561
7562 // QuickTime chapters involve an additional text track with the chapter names
7563 // as samples, and a tref pointing from the other tracks to the chapter one.
7564 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7565 {
7566 static const uint8_t stub_header[] = {
7567 // TextSampleEntry
7568 0x00, 0x00, 0x00, 0x01, // displayFlags
7569 0x00, 0x00, // horizontal + vertical justification
7570 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7571 // BoxRecord
7572 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7573 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7574 // StyleRecord
7575 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7576 0x00, 0x01, // fontID
7577 0x00, 0x00, // fontStyleFlags + fontSize
7578 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7579 // FontTableBox
7580 0x00, 0x00, 0x00, 0x0D, // box size
7581 'f', 't', 'a', 'b', // box atom name
7582 0x00, 0x01, // entry count
7583 // FontRecord
7584 0x00, 0x01, // font ID
7585 0x00, // font name length
7586 };
7587 1 MOVMuxContext *mov = s->priv_data;
7588 1 MOVTrack *track = &mov->tracks[tracknum];
7589 1 AVPacket *pkt = mov->pkt;
7590 int i, len;
7591 int ret;
7592
7593 1 track->mode = mov->mode;
7594 1 track->tag = MKTAG('t','e','x','t');
7595 1 track->timescale = mov->movie_timescale;
7596 1 track->par = avcodec_parameters_alloc();
7597
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7598 return AVERROR(ENOMEM);
7599 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7600 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7601
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7602 return ret;
7603 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7604
7605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7606 track->stsd_count = 1;
7607 track->extradata = av_calloc(1, sizeof(*track->extradata));
7608 track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7609 if (!track->extradata || !track->extradata_size)
7610 return AVERROR(ENOMEM);
7611 }
7612
7613 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7615 return AVERROR(ENOMEM);
7616 1 track->extradata_size[0] = sizeof(stub_header);
7617
7618 1 pkt->stream_index = tracknum;
7619 1 pkt->flags = AV_PKT_FLAG_KEY;
7620
7621
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7622 4 AVChapter *c = s->chapters[i];
7623 AVDictionaryEntry *t;
7624
7625 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7626 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7627 4 pkt->duration = end - pkt->dts;
7628
7629
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7630 static const char encd[12] = {
7631 0x00, 0x00, 0x00, 0x0C,
7632 'e', 'n', 'c', 'd',
7633 0x00, 0x00, 0x01, 0x00 };
7634 4 len = strlen(t->value);
7635 4 pkt->size = len + 2 + 12;
7636 4 pkt->data = av_malloc(pkt->size);
7637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7638 av_packet_unref(pkt);
7639 return AVERROR(ENOMEM);
7640 }
7641 4 AV_WB16(pkt->data, len);
7642 4 memcpy(pkt->data + 2, t->value, len);
7643 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7644 4 ff_mov_write_packet(s, pkt);
7645 4 av_freep(&pkt->data);
7646 }
7647 }
7648
7649 1 av_packet_unref(mov->pkt);
7650
7651 1 return 0;
7652 }
7653
7654
7655 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7656 {
7657 int ret;
7658
7659 /* compute the frame number */
7660 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7661 13 return ret;
7662 }
7663
7664 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7665 {
7666 6 MOVMuxContext *mov = s->priv_data;
7667 6 MOVTrack *track = &mov->tracks[index];
7668 6 AVStream *src_st = mov->tracks[src_index].st;
7669 uint8_t data[4];
7670 6 AVPacket *pkt = mov->pkt;
7671 6 AVRational rate = src_st->avg_frame_rate;
7672 int ret;
7673
7674 /* tmcd track based on video stream */
7675 6 track->mode = mov->mode;
7676 6 track->tag = MKTAG('t','m','c','d');
7677 6 track->src_track = src_index;
7678 6 track->timescale = mov->tracks[src_index].timescale;
7679
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7680 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7681
7682 /* set st to src_st for metadata access*/
7683 6 track->st = src_st;
7684
7685 /* encode context: tmcd data stream */
7686 6 track->par = avcodec_parameters_alloc();
7687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7688 return AVERROR(ENOMEM);
7689 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7690 6 track->par->codec_tag = track->tag;
7691 6 track->st->avg_frame_rate = rate;
7692
7693 /* the tmcd track just contains one packet with the frame number */
7694 6 pkt->data = data;
7695 6 pkt->stream_index = index;
7696 6 pkt->flags = AV_PKT_FLAG_KEY;
7697 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7698 6 pkt->size = 4;
7699 6 AV_WB32(pkt->data, tc.start);
7700 6 ret = ff_mov_write_packet(s, pkt);
7701 6 av_packet_unref(pkt);
7702 6 return ret;
7703 }
7704
7705 /*
7706 * st->disposition controls the "enabled" flag in the tkhd tag.
7707 * QuickTime will not play a track if it is not enabled. So make sure
7708 * that one track of each type (audio, video, subtitle) is enabled.
7709 *
7710 * Subtitles are special. For audio and video, setting "enabled" also
7711 * makes the track "default" (i.e. it is rendered when played). For
7712 * subtitles, an "enabled" subtitle is not rendered by default, but
7713 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7714 * empty!
7715 */
7716 219 static void enable_tracks(AVFormatContext *s)
7717 {
7718 219 MOVMuxContext *mov = s->priv_data;
7719 int i;
7720 int enabled[AVMEDIA_TYPE_NB];
7721 int first[AVMEDIA_TYPE_NB];
7722
7723
2/2
✓ Branch 0 taken 1095 times.
✓ Branch 1 taken 219 times.
1314 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7724 1095 enabled[i] = 0;
7725 1095 first[i] = -1;
7726 }
7727
7728
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 219 times.
500 for (i = 0; i < mov->nb_streams; i++) {
7729 281 AVStream *st = mov->tracks[i].st;
7730
7731
1/2
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
281 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7732
3/4
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 279 times.
562 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7733 281 is_cover_image(st))
7734 2 continue;
7735
7736
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 15 times.
279 if (first[st->codecpar->codec_type] < 0)
7737 264 first[st->codecpar->codec_type] = i;
7738
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 247 times.
279 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7739 32 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7740 32 enabled[st->codecpar->codec_type]++;
7741 }
7742 }
7743
7744
2/2
✓ Branch 0 taken 1095 times.
✓ Branch 1 taken 219 times.
1314 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7745
2/2
✓ Branch 0 taken 657 times.
✓ Branch 1 taken 438 times.
1095 switch (i) {
7746 657 case AVMEDIA_TYPE_VIDEO:
7747 case AVMEDIA_TYPE_AUDIO:
7748 case AVMEDIA_TYPE_SUBTITLE:
7749
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 656 times.
657 if (enabled[i] > 1)
7750 1 mov->per_stream_grouping = 1;
7751
4/4
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 235 times.
✓ Branch 3 taken 395 times.
657 if (!enabled[i] && first[i] >= 0)
7752 235 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7753 657 break;
7754 }
7755 }
7756 219 }
7757
7758 219 static void mov_free(AVFormatContext *s)
7759 {
7760 219 MOVMuxContext *mov = s->priv_data;
7761
7762
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 219 times.
521 for (int i = 0; i < s->nb_streams; i++)
7763 302 s->streams[i]->priv_data = NULL;
7764
7765
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (!mov->tracks)
7766 return;
7767
7768
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->chapter_track) {
7769 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7770 }
7771
7772
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 219 times.
509 for (int i = 0; i < mov->nb_tracks; i++) {
7773 290 MOVTrack *const track = &mov->tracks[i];
7774
7775
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 288 times.
290 if (track->tag == MKTAG('r','t','p',' '))
7776 2 ff_mov_close_hinting(track);
7777
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 279 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
288 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7778 6 av_freep(&track->par);
7779 290 av_freep(&track->cluster);
7780 290 av_freep(&track->cluster_written);
7781 290 av_freep(&track->frag_info);
7782 290 av_packet_free(&track->cover_image);
7783
7784
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 285 times.
290 if (track->eac3_priv) {
7785 5 struct eac3_info *info = track->eac3_priv;
7786 5 av_packet_free(&info->pkt);
7787 5 av_freep(&track->eac3_priv);
7788 }
7789
2/2
✓ Branch 0 taken 291 times.
✓ Branch 1 taken 290 times.
581 for (int j = 0; j < track->stsd_count; j++)
7790 291 av_freep(&track->extradata[j]);
7791 290 av_freep(&track->extradata);
7792 290 av_freep(&track->extradata_size);
7793
7794 290 ff_mov_cenc_free(&track->cenc);
7795 290 ffio_free_dyn_buf(&track->mdat_buf);
7796
7797 #if CONFIG_IAMFENC
7798 290 ffio_free_dyn_buf(&track->iamf_buf);
7799
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 285 times.
290 if (track->iamf)
7800 5 ff_iamf_uninit_context(track->iamf);
7801 290 av_freep(&track->iamf);
7802 #endif
7803 290 ff_isom_close_apvc(&track->apv);
7804
7805 290 avpriv_packet_list_free(&track->squashed_packet_queue);
7806 }
7807
7808 219 av_freep(&mov->tracks);
7809 219 ffio_free_dyn_buf(&mov->mdat_buf);
7810 }
7811
7812 static uint32_t rgb_to_yuv(uint32_t rgb)
7813 {
7814 uint8_t r, g, b;
7815 int y, cb, cr;
7816
7817 r = (rgb >> 16) & 0xFF;
7818 g = (rgb >> 8) & 0xFF;
7819 b = (rgb ) & 0xFF;
7820
7821 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7822 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7823 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7824
7825 return (y << 16) | (cr << 8) | cb;
7826 }
7827
7828 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7829 AVStream *st)
7830 {
7831 int i, width = 720, height = 480;
7832 int have_palette = 0, have_size = 0;
7833 uint32_t palette[16];
7834 char *cur = track->extradata[track->last_stsd_index];
7835
7836 while (cur && *cur) {
7837 if (strncmp("palette:", cur, 8) == 0) {
7838 int i, count;
7839 count = sscanf(cur + 8,
7840 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7841 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7842 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7843 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7844 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7845 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7846 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7847 &palette[12], &palette[13], &palette[14], &palette[15]);
7848
7849 for (i = 0; i < count; i++) {
7850 palette[i] = rgb_to_yuv(palette[i]);
7851 }
7852 have_palette = 1;
7853 } else if (!strncmp("size:", cur, 5)) {
7854 sscanf(cur + 5, "%dx%d", &width, &height);
7855 have_size = 1;
7856 }
7857 if (have_palette && have_size)
7858 break;
7859 cur += strcspn(cur, "\n\r");
7860 cur += strspn(cur, "\n\r");
7861 }
7862 if (have_palette) {
7863 track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7864 if (!track->extradata[track->last_stsd_index])
7865 return AVERROR(ENOMEM);
7866 for (i = 0; i < 16; i++) {
7867 AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
7868 }
7869 memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7870 track->extradata_size[track->last_stsd_index] = 16 * 4;
7871 }
7872 st->codecpar->width = width;
7873 st->codecpar->height = track->height = height;
7874
7875 return 0;
7876 }
7877
7878 #if CONFIG_IAMFENC
7879 219 static int mov_init_iamf_track(AVFormatContext *s)
7880 {
7881 219 MOVMuxContext *mov = s->priv_data;
7882 MOVTrack *track;
7883 IAMFContext *iamf;
7884 219 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7885 219 int nb_audio_elements = 0, nb_mix_presentations = 0;
7886 int ret;
7887
7888
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 219 times.
229 for (int i = 0; i < s->nb_stream_groups; i++) {
7889 10 const AVStreamGroup *stg = s->stream_groups[i];
7890
7891
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7892 5 nb_audio_elements++;
7893
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7894 5 nb_mix_presentations++;
7895 }
7896
7897
3/4
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 214 times.
✗ Branch 3 not taken.
219 if (!nb_audio_elements && !nb_mix_presentations)
7898 214 return 0;
7899
7900
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) {
7901 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7902 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7903 return AVERROR(EINVAL);
7904 }
7905
7906 5 iamf = av_mallocz(sizeof(*iamf));
7907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7908 return AVERROR(ENOMEM);
7909
7910
7911
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7912 10 const AVStreamGroup *stg = s->stream_groups[i];
7913
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7914 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7915
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7916 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7917 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7918 }
7919
7920 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7921 5 break;
7922 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7923 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7924 5 break;
7925 default:
7926 av_assert0(0);
7927 }
7928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
7929 ff_iamf_uninit_context(iamf);
7930 av_free(iamf);
7931 return ret;
7932 }
7933 }
7934
7935 5 track = &mov->tracks[first_iamf_idx];
7936 5 track->iamf = iamf;
7937 5 track->first_iamf_idx = first_iamf_idx;
7938 5 track->last_iamf_idx = last_iamf_idx;
7939 5 track->tag = MKTAG('i','a','m','f');
7940
7941
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7942 10 AVStreamGroup *stg = s->stream_groups[i];
7943
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7944 5 continue;
7945
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7946 25 stg->streams[j]->priv_data = track;
7947 }
7948
7949 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7951 return ret;
7952
7953 5 return 0;
7954 }
7955 #endif
7956
7957 219 static int mov_init(AVFormatContext *s)
7958 {
7959 219 MOVMuxContext *mov = s->priv_data;
7960 219 int has_iamf = 0;
7961 int i, ret;
7962
7963 219 mov->fc = s;
7964 219 mov->pkt = ffformatcontext(s)->pkt;
7965
7966 /* Default mode == MP4 */
7967 219 mov->mode = MODE_MP4;
7968
7969 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7972
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 69 times.
219 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7973
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 68 times.
69 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7974
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
68 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7975
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 62 times.
67 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7978 #undef IS_MODE
7979
7980
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 201 times.
219 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7981 18 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7982
7983
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (mov->mode == MODE_AVIF)
7984 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7985
7986 /* Set the FRAGMENT flag if any of the fragmentation methods are
7987 * enabled. */
7988
3/4
✓ Branch 0 taken 217 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 217 times.
✗ Branch 3 not taken.
219 if (mov->max_fragment_duration || mov->max_fragment_size ||
7989
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 187 times.
217 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7990 FF_MOV_FLAG_FRAG_KEYFRAME |
7991 FF_MOV_FLAG_FRAG_CUSTOM |
7992 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7993 32 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7994
7995
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 217 times.
219 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
7996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
7997 av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
7998 return AVERROR(EINVAL);
7999 }
8000
8001 /* Set other implicit flags immediately */
8002
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 217 times.
219 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8003 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8004
8005
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 214 times.
219 if (mov->mode == MODE_ISM)
8006 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
8007 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8008
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 207 times.
219 if (mov->flags & FF_MOV_FLAG_DASH)
8009 12 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8010 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
8011
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 217 times.
219 if (mov->flags & FF_MOV_FLAG_CMAF)
8012 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8013 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8014
8015
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 185 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 2 times.
219 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
8016 32 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
8017 32 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
8018 }
8019
8020
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
219 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
8021 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
8022 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
8023 }
8024
8025
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 216 times.
219 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8026 3 mov->reserved_moov_size = -1;
8027 }
8028
8029
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 7 times.
219 if (mov->use_editlist < 0) {
8030 212 mov->use_editlist = 1;
8031
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 181 times.
212 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8032
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16 times.
31 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8033 // If we can avoid needing an edit list by shifting the
8034 // tracks, prefer that over (trying to) write edit lists
8035 // in fragmented output.
8036
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
15 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
8037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
8038 14 mov->use_editlist = 0;
8039 }
8040 }
8041
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 185 times.
219 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8042
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 15 times.
34 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
8043 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
8044
8045
4/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 1 times.
219 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
8046
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
8047 11 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
8048
8049 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
8050 * if the latter is set that's enough and omit_tfhd_offset doesn't
8051 * add anything extra on top of that. */
8052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
8053 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
8054 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
8055
8056
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->frag_interleave &&
8057
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)) {
8058 av_log(s, AV_LOG_ERROR,
8059 "Sample interleaving in fragments is mutually exclusive with "
8060 "omit_tfhd_offset and separate_moof\n");
8061 return AVERROR(EINVAL);
8062 }
8063
8064 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8065 * is enabled, we don't support non-seekable output at all. */
8066
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 191 times.
219 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
8067
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
8068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
8069 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
8070 return AVERROR(EINVAL);
8071 }
8072
8073 /* AVIF output must have at most two video streams (one for YUV and one for
8074 * alpha). */
8075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (mov->mode == MODE_AVIF) {
8076 if (s->nb_streams > 2) {
8077 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
8078 return AVERROR(EINVAL);
8079 }
8080 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
8081 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
8082 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
8083 return AVERROR(EINVAL);
8084 }
8085 if (s->nb_streams > 1) {
8086 const AVPixFmtDescriptor *pixdesc =
8087 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
8088 if (pixdesc->nb_components != 1) {
8089 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8090 return AVERROR(EINVAL);
8091 }
8092 }
8093 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
8094 }
8095
8096
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 219 times.
229 for (i = 0; i < s->nb_stream_groups; i++) {
8097 10 AVStreamGroup *stg = s->stream_groups[i];
8098
8099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_LCEVC) {
8100 if (stg->nb_streams != 2) {
8101 av_log(s, AV_LOG_ERROR, "Exactly two Streams are supported for Stream Groups of type LCEVC\n");
8102 return AVERROR(EINVAL);
8103 }
8104 AVStreamGroupLCEVC *lcevc = stg->params.lcevc;
8105 if (lcevc->lcevc_index > 1)
8106 return AVERROR(EINVAL);
8107 AVStream *st = stg->streams[lcevc->lcevc_index];
8108 if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) {
8109 av_log(s, AV_LOG_ERROR, "Stream #%u is not an LCEVC stream\n", lcevc->lcevc_index);
8110 return AVERROR(EINVAL);
8111 }
8112 }
8113
8114 #if CONFIG_IAMFENC
8115
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8116 5 continue;
8117
8118
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8119 25 AVStream *st = stg->streams[j];
8120
8121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8122 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8123 "IAMF Audio Element\n", j);
8124 return AVERROR(EINVAL);
8125 }
8126 25 st->priv_data = st;
8127 }
8128 5 has_iamf = 1;
8129
8130
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
8131 5 mov->nb_tracks++;
8132 #endif
8133 }
8134
8135
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 219 times.
521 for (i = 0; i < s->nb_streams; i++) {
8136 302 AVStream *st = s->streams[i];
8137
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 277 times.
302 if (st->priv_data)
8138 25 continue;
8139 // Don't produce a track in the output file for timed ID3 streams.
8140
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 276 times.
277 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8141 // Leave priv_data set to NULL for these AVStreams that don't
8142 // have a corresponding track.
8143 1 continue;
8144 }
8145 276 st->priv_data = st;
8146 276 mov->nb_tracks++;
8147 }
8148
8149 219 mov->nb_streams = mov->nb_tracks;
8150
8151
4/4
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 212 times.
219 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8152 1 mov->chapter_track = mov->nb_tracks++;
8153
8154
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8155
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8156
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8157 2 mov->nb_tracks++;
8158 }
8159
8160
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 if (mov->write_btrt < 0) {
8161 219 mov->write_btrt = mov->mode == MODE_MP4;
8162 }
8163
8164
6/6
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 62 times.
219 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8165
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8166 215 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8167 NULL, 0);
8168
8169 /* +1 tmcd track for each video stream with a timecode */
8170
2/2
✓ Branch 0 taken 295 times.
✓ Branch 1 taken 215 times.
510 for (i = 0; i < s->nb_streams; i++) {
8171 295 AVStream *st = s->streams[i];
8172 295 AVDictionaryEntry *t = global_tcr;
8173
4/4
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 7 times.
295 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8174
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
180 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8175 AVTimecode tc;
8176 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8177
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8178 7 mov->nb_meta_tmcd++;
8179 }
8180 }
8181
8182 /* check if there is already a tmcd track to remux */
8183
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 208 times.
215 if (mov->nb_meta_tmcd) {
8184
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8185 13 AVStream *st = s->streams[i];
8186
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8187 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8188 "so timecode metadata are now ignored\n");
8189 3 mov->nb_meta_tmcd = 0;
8190 }
8191 }
8192 }
8193
8194 215 mov->nb_tracks += mov->nb_meta_tmcd;
8195 }
8196
8197 // Reserve an extra stream for chapters for the case where chapters
8198 // are written in the trailer
8199 219 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (!mov->tracks)
8201 return AVERROR(ENOMEM);
8202
8203
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 219 times.
509 for (i = 0; i < mov->nb_tracks; i++) {
8204 290 MOVTrack *track = &mov->tracks[i];
8205
8206 290 track->stsd_count = 1;
8207 290 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8208 290 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8209
2/4
✓ Branch 0 taken 290 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 290 times.
290 if (!track->extradata || !track->extradata_size)
8210 return AVERROR(ENOMEM);
8211 }
8212
8213
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
219 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8214 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8215 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8216
8217 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8218 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8219 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8220 return AVERROR(EINVAL);
8221 }
8222
8223 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8224 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8225 mov->encryption_kid_len, CENC_KID_SIZE);
8226 return AVERROR(EINVAL);
8227 }
8228 } else {
8229 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8230 mov->encryption_scheme_str);
8231 return AVERROR(EINVAL);
8232 }
8233 }
8234
8235 #if CONFIG_IAMFENC
8236 219 ret = mov_init_iamf_track(s);
8237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (ret < 0)
8238 return ret;
8239 #endif
8240
8241
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 219 times.
521 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8242 302 AVStream *st = s->streams[j];
8243
8244
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 276 times.
302 if (st != st->priv_data) {
8245
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8246 5 i += has_iamf--;
8247 26 continue;
8248 }
8249 276 st->priv_data = &mov->tracks[i++];
8250 }
8251
8252
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 219 times.
521 for (i = 0; i < s->nb_streams; i++) {
8253 302 AVStream *st= s->streams[i];
8254 302 MOVTrack *track = st->priv_data;
8255 302 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8256
8257
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 301 times.
302 if (!track)
8258 1 continue;
8259
8260
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 20 times.
301 if (!track->st) {
8261 281 track->st = st;
8262 281 track->par = st->codecpar;
8263 }
8264
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 273 times.
301 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8265
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 143 times.
301 if (track->language < 0)
8266 158 track->language = 32767; // Unspecified Macintosh language code
8267 301 track->mode = mov->mode;
8268
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 25 times.
301 if (!track->tag)
8269 276 track->tag = mov_find_codec_tag(s, track);
8270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 301 times.
301 if (!track->tag) {
8271 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8272 "codec not currently supported in container\n",
8273 avcodec_get_name(st->codecpar->codec_id), i);
8274 return AVERROR(EINVAL);
8275 }
8276 /* If hinting of this track is enabled by a later hint track,
8277 * this is updated. */
8278 301 track->hint_track = -1;
8279 301 track->start_dts = AV_NOPTS_VALUE;
8280 301 track->start_cts = AV_NOPTS_VALUE;
8281 301 track->end_pts = AV_NOPTS_VALUE;
8282 301 track->dts_shift = AV_NOPTS_VALUE;
8283
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 111 times.
301 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8284
2/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
✗ Branch 3 not taken.
190 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8285
2/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
✗ Branch 3 not taken.
190 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8286
2/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 190 times.
190 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8287 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8288 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8289 return AVERROR(EINVAL);
8290 }
8291 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8292 }
8293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (mov->video_track_timescale) {
8294 track->timescale = mov->video_track_timescale;
8295 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8296 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8297 } else {
8298 190 track->timescale = st->time_base.den;
8299
2/2
✓ Branch 0 taken 1494 times.
✓ Branch 1 taken 190 times.
1684 while(track->timescale < 10000)
8300 1494 track->timescale *= 2;
8301 }
8302
2/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 190 times.
190 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8303 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8304 return AVERROR(EINVAL);
8305 }
8306
4/4
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 130 times.
190 if (track->mode == MODE_MOV && track->timescale > 100000)
8307 5 av_log(s, AV_LOG_WARNING,
8308 "WARNING codec timebase is very high. If duration is too long,\n"
8309 "file may not be playable by quicktime. Specify a shorter timebase\n"
8310 "or choose different container.\n");
8311
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 55 times.
190 if (track->mode == MODE_MOV &&
8312
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 118 times.
135 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8313
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8314 1 enum AVPixelFormat pix_fmt = track->par->format;
8315
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)
8316 pix_fmt = AV_PIX_FMT_MONOWHITE;
8317 1 track->is_unaligned_qt_rgb =
8318 pix_fmt == AV_PIX_FMT_RGB24 ||
8319 pix_fmt == AV_PIX_FMT_BGR24 ||
8320 pix_fmt == AV_PIX_FMT_PAL8 ||
8321 pix_fmt == AV_PIX_FMT_GRAY8 ||
8322
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 ||
8323 pix_fmt == AV_PIX_FMT_MONOBLACK;
8324 }
8325
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
190 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8326 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8327 return AVERROR(EINVAL);
8328
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 189 times.
190 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8329
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8330 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8331 return AVERROR(EINVAL);
8332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8333 /* altref frames handling is not defined in the spec as of version v1.0,
8334 * so just forbid muxing VP8 streams altogether until a new version does */
8335 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8336 return AVERROR_PATCHWELCOME;
8337
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 189 times.
190 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8338 1 ret = ff_isom_init_apvc(&track->apv, s);
8339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8340 return ret;
8341 }
8342
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 188 times.
190 if (is_cover_image(st)) {
8343 2 track->cover_image = av_packet_alloc();
8344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8345 return AVERROR(ENOMEM);
8346 }
8347
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 9 times.
111 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8348 102 track->timescale = st->codecpar->sample_rate;
8349
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 70 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 26 times.
102 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8350 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8351 6 track->audio_vbr = 1;
8352
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8353
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8355 if (!st->codecpar->block_align) {
8356 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8357 return AVERROR(EINVAL);
8358 }
8359 track->sample_size = st->codecpar->block_align;
8360
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 26 times.
96 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8361 70 track->audio_vbr = 1;
8362 }else{
8363 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8364 26 st->codecpar->ch_layout.nb_channels;
8365 }
8366
1/2
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
102 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8368 track->audio_vbr = 1;
8369 }
8370
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 32 times.
102 if (track->mode != MODE_MOV &&
8371
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8372 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8373 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8374 i, track->par->sample_rate);
8375 return AVERROR(EINVAL);
8376 } else {
8377 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8378 i, track->par->sample_rate);
8379 }
8380 }
8381
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 25 times.
102 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8382
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 track->par->codec_id == AV_CODEC_ID_OPUS) {
8384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8385 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8386 return AVERROR(EINVAL);
8387 }
8388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8389 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8390 av_log(s, AV_LOG_ERROR,
8391 "%s in MP4 support is experimental, add "
8392 "'-strict %d' if you want to use it.\n",
8393 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8394 return AVERROR_EXPERIMENTAL;
8395 }
8396 }
8397
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8398 5 track->timescale = st->time_base.den;
8399
8400
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8401 /* 14496-30 requires us to use a single sample per fragment
8402 for TTML, for which we define a per-track flag.
8403
8404 We set the flag in case we are receiving TTML paragraphs
8405 from the input, in other words in case we are not doing
8406 stream copy. */
8407 4 track->squash_fragment_samples_to_one =
8408 4 ff_is_ttml_stream_paragraph_based(track->par);
8409
8410
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8411
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8413 av_log(s, AV_LOG_ERROR,
8414 "ISMV style TTML support with the 'dfxp' tag in "
8415 "non-ISMV formats is not officially supported. Add "
8416 "'-strict unofficial' if you want to use it.\n");
8417 return AVERROR_EXPERIMENTAL;
8418 }
8419 }
8420
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8421 4 track->timescale = st->time_base.den;
8422 } else {
8423 track->timescale = mov->movie_timescale;
8424 }
8425
1/2
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
301 if (!track->height)
8426 301 track->height = st->codecpar->height;
8427 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8428 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8429 for video tracks, so if user-set, it isn't overwritten */
8430
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 294 times.
301 if (mov->mode == MODE_ISM &&
8431
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8432
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))) {
8433 7 track->timescale = 10000000;
8434 }
8435
8436 301 avpriv_set_pts_info(st, 64, 1, track->timescale);
8437
8438
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 301 times.
301 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8439 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8440 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8441 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8442 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8443 if (ret)
8444 return ret;
8445 }
8446 }
8447
8448
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 219 times.
229 for (i = 0; i < s->nb_stream_groups; i++) {
8449 10 AVStreamGroup *stg = s->stream_groups[i];
8450
8451
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
8452 10 continue;
8453
8454 AVStreamGroupLCEVC *lcevc = stg->params.lcevc;
8455 AVStream *st = stg->streams[lcevc->lcevc_index];
8456 MOVTrack *track = st->priv_data;
8457
8458 for (int j = 0; j < mov->nb_tracks; j++) {
8459 MOVTrack *trk = &mov->tracks[j];
8460
8461 if (trk->st == stg->streams[!lcevc->lcevc_index]) {
8462 track->src_track = j;
8463 break;
8464 }
8465 }
8466
8467 track->par->width = lcevc->width;
8468 track->par->height = track->height = lcevc->height;
8469 }
8470
8471 219 enable_tracks(s);
8472 219 return 0;
8473 }
8474
8475 219 static int mov_write_header(AVFormatContext *s)
8476 {
8477 219 AVIOContext *pb = s->pb;
8478 219 MOVMuxContext *mov = s->priv_data;
8479 219 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8480
8481
4/4
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 212 times.
219 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8482 1 nb_tracks++;
8483
8484
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8485 1 hint_track = nb_tracks;
8486
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8487
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8488 2 nb_tracks++;
8489 }
8490 }
8491
8492
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 213 times.
219 if (mov->nb_meta_tmcd)
8493 6 tmcd_track = nb_tracks;
8494
8495
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 219 times.
500 for (int i = 0; i < mov->nb_streams; i++) {
8496 281 MOVTrack *track = &mov->tracks[i];
8497 281 AVStream *st = track->st;
8498
8499 /* copy extradata if it exists */
8500
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 157 times.
281 if (st->codecpar->extradata_size) {
8501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8502 mov_create_dvd_sub_decoder_specific_info(track, st);
8503
15/30
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 124 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 124 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 124 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 124 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 124 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 124 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 124 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 124 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 124 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 124 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 124 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 124 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 124 times.
✗ Branch 29 not taken.
124 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8504 124 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8505 248 track->extradata[track->last_stsd_index] =
8506 124 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 if (!track->extradata[track->last_stsd_index]) {
8508 return AVERROR(ENOMEM);
8509 }
8510 124 memcpy(track->extradata[track->last_stsd_index],
8511 124 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8512 124 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8513 0, AV_INPUT_BUFFER_PADDING_SIZE);
8514 }
8515 }
8516
8517
4/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 14 times.
363 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8518 82 av_channel_layout_compare(&track->par->ch_layout,
8519 82 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8520 267 continue;
8521
8522
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8523 33 AVStream *stj= mov->tracks[j].st;
8524 33 MOVTrack *trackj= &mov->tracks[j];
8525
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8526 14 continue;
8527
8528
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8529
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 ||
8530 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8531 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8532 )
8533 4 track->mono_as_fc = -1;
8534
8535
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
30 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8536 11 av_channel_layout_compare(&trackj->par->ch_layout,
8537 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8538
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
8539 )
8540 7 track->mono_as_fc++;
8541
8542
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
30 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8543 11 av_channel_layout_compare(&trackj->par->ch_layout,
8544 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8545 trackj->language != track->language ||
8546 trackj->tag != track->tag
8547 )
8548 19 continue;
8549 track->multichannel_as_mono++;
8550 }
8551 }
8552
8553
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 201 times.
219 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8555
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 201 times.
201 if ((ret = mov_write_identification(pb, s)) < 0)
8556 return ret;
8557 }
8558
8559
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 216 times.
219 if (mov->reserved_moov_size){
8560 3 mov->reserved_header_pos = avio_tell(pb);
8561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8562 avio_skip(pb, mov->reserved_moov_size);
8563 }
8564
8565
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 181 times.
219 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8566 /* If no fragmentation options have been set, set a default. */
8567
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 31 times.
38 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8568 FF_MOV_FLAG_FRAG_CUSTOM |
8569 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8570
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)
8571 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8572
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
38 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8573 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8574
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8575 2 mov->mdat_pos = avio_tell(pb);
8576 // The free/wide header that later will be converted into an
8577 // mdat, covering the initial moov and all the fragments.
8578 2 avio_wb32(pb, 0);
8579
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8580 // Write an ftyp atom, hidden in a free/wide. This is neither
8581 // exposed while the file is written, as fragmented, nor when the
8582 // file is finalized into non-fragmented form. However, this allows
8583 // accessing a pristine, sequential ftyp+moov init segment, even
8584 // after the file is finalized. It also allows dumping the whole
8585 // contents of the mdat box, to get the fragmented form of the
8586 // file.
8587
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_identification(pb, s)) < 0)
8588 return ret;
8589 2 update_size(pb, mov->mdat_pos);
8590 }
8591
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 } else if (mov->mode != MODE_AVIF) {
8592
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 178 times.
181 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8593 3 mov->reserved_header_pos = avio_tell(pb);
8594 181 mov_write_mdat_tag(pb, mov);
8595 }
8596
8597 219 ff_parse_creation_time_metadata(s, &mov->time, 1);
8598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (mov->time)
8599 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8600
8601
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->chapter_track)
8602
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8603 return ret;
8604
8605
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
219 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8606
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8607
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8608
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8609 return ret;
8610 2 hint_track++;
8611 }
8612 }
8613 }
8614
8615
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 213 times.
219 if (mov->nb_meta_tmcd) {
8616 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8617 "timecode", NULL, 0);
8618 /* Initialize the tmcd tracks */
8619
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8620 8 AVStream *st = mov->tracks[i].st;
8621 8 t = global_tcr;
8622
8623
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8624 AVTimecode tc;
8625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8626 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8628 continue;
8629
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8630 continue;
8631
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8632 return ret;
8633 6 tmcd_track++;
8634 }
8635 }
8636 }
8637
8638 219 avio_flush(pb);
8639
8640
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 if (mov->flags & FF_MOV_FLAG_ISML)
8641 mov_write_isml_manifest(pb, mov, s);
8642
8643
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 185 times.
219 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8644
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18 times.
34 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8645
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8646 return ret;
8647 16 mov->moov_written = 1;
8648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8649 mov->reserved_header_pos = avio_tell(pb);
8650 }
8651
8652 219 return 0;
8653 }
8654
8655 28 static int get_moov_size(AVFormatContext *s)
8656 {
8657 int ret;
8658 AVIOContext *moov_buf;
8659 28 MOVMuxContext *mov = s->priv_data;
8660
8661
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8662 return ret;
8663
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8664 return ret;
8665 28 return ffio_close_null_buf(moov_buf);
8666 }
8667
8668 static int get_sidx_size(AVFormatContext *s)
8669 {
8670 int ret;
8671 AVIOContext *buf;
8672 MOVMuxContext *mov = s->priv_data;
8673
8674 if ((ret = ffio_open_null_buf(&buf)) < 0)
8675 return ret;
8676 mov_write_sidx_tags(buf, mov, -1, 0);
8677 return ffio_close_null_buf(buf);
8678 }
8679
8680 /*
8681 * This function gets the moov size if moved to the top of the file: the chunk
8682 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8683 * entries) when the moov is moved to the beginning, so the size of the moov
8684 * would change. It also updates the chunk offset tables.
8685 */
8686 3 static int compute_moov_size(AVFormatContext *s)
8687 {
8688 int i, moov_size, moov_size2;
8689 3 MOVMuxContext *mov = s->priv_data;
8690
8691 3 moov_size = get_moov_size(s);
8692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8693 return moov_size;
8694
8695
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8696 8 mov->tracks[i].data_offset += moov_size;
8697
8698 3 moov_size2 = get_moov_size(s);
8699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8700 return moov_size2;
8701
8702 /* if the size changed, we just switched from stco to co64 and need to
8703 * update the offsets */
8704
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8705 for (i = 0; i < mov->nb_tracks; i++)
8706 mov->tracks[i].data_offset += moov_size2 - moov_size;
8707
8708 3 return moov_size2;
8709 }
8710
8711 static int compute_sidx_size(AVFormatContext *s)
8712 {
8713 int i, sidx_size;
8714 MOVMuxContext *mov = s->priv_data;
8715
8716 sidx_size = get_sidx_size(s);
8717 if (sidx_size < 0)
8718 return sidx_size;
8719
8720 for (i = 0; i < mov->nb_tracks; i++)
8721 mov->tracks[i].data_offset += sidx_size;
8722
8723 return sidx_size;
8724 }
8725
8726 3 static int shift_data(AVFormatContext *s)
8727 {
8728 int moov_size;
8729 3 MOVMuxContext *mov = s->priv_data;
8730
8731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8732 moov_size = compute_sidx_size(s);
8733 else
8734 3 moov_size = compute_moov_size(s);
8735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8736 return moov_size;
8737
8738 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8739 }
8740
8741 183 static void mov_write_mdat_size(AVFormatContext *s)
8742 {
8743 183 MOVMuxContext *mov = s->priv_data;
8744 183 AVIOContext *pb = s->pb;
8745
8746 /* Write size of mdat tag */
8747
1/2
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
183 if (mov->mdat_size + 8 <= UINT32_MAX) {
8748 183 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8749 183 avio_wb32(pb, mov->mdat_size + 8);
8750
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 181 times.
183 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8751 2 ffio_wfourcc(pb, "mdat"); // overwrite the original free/wide into a mdat
8752 } else {
8753 /* overwrite 'wide' placeholder atom */
8754 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8755 /* special value: real atom size will be 64 bit value after
8756 * tag field */
8757 avio_wb32(pb, 1);
8758 ffio_wfourcc(pb, "mdat");
8759 avio_wb64(pb, mov->mdat_size + 16);
8760 }
8761 183 }
8762
8763 219 static int mov_write_trailer(AVFormatContext *s)
8764 {
8765 219 MOVMuxContext *mov = s->priv_data;
8766 219 AVIOContext *pb = s->pb;
8767 219 int res = 0;
8768 int i;
8769 int64_t moov_pos;
8770
8771 /*
8772 * Before actually writing the trailer, make sure that there are no
8773 * dangling subtitles, that need a terminating sample.
8774 */
8775
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 219 times.
509 for (i = 0; i < mov->nb_tracks; i++) {
8776 290 MOVTrack *trk = &mov->tracks[i];
8777
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 289 times.
290 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8778
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8779 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8780 1 trk->last_sample_is_subtitle_end = 1;
8781 }
8782 }
8783
8784 // Check if we have any tracks that require squashing.
8785 // In that case, we'll have to write the packet here.
8786
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 219 times.
219 if ((res = mov_write_squashed_packets(s)) < 0)
8787 return res;
8788
8789 // If there were no chapters when the header was written, but there
8790 // are chapters now, write them in the trailer. This only works
8791 // when we are not doing fragments.
8792
4/4
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 38 times.
219 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
8793
3/4
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 179 times.
180 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
8794 mov->chapter_track = mov->nb_tracks++;
8795 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8796 return res;
8797 }
8798 }
8799
8800
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 181 times.
219 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8801
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
38 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8802
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 181 times.
183 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8803 2 mov_auto_flush_fragment(s, 1);
8804 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8805
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
8806 4 MOVTrack *track = &mov->tracks[i];
8807 4 track->data_offset = 0;
8808 4 av_free(track->cluster);
8809 4 track->cluster = track->cluster_written;
8810 4 track->entry = track->entry_written;
8811 4 track->cluster_written = NULL;
8812 4 track->entry_written = 0;
8813 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8814 }
8815 // Clear the empty_moov flag, as we do want the moov to include
8816 // all the samples at this point.
8817 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8818 }
8819
8820 183 moov_pos = avio_tell(pb);
8821
8822
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 2 times.
183 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
8823 181 mov_write_mdat_size(s);
8824
8825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
183 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
8826
8827
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 180 times.
183 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8828 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8829 3 res = shift_data(s);
8830
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8831 return res;
8832 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8833
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8834 return res;
8835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 } else if (mov->reserved_moov_size > 0) {
8836 int64_t size;
8837 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8838 return res;
8839 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8840 if (size < 8){
8841 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8842 return AVERROR(EINVAL);
8843 }
8844 avio_wb32(pb, size);
8845 ffio_wfourcc(pb, "free");
8846 ffio_fill(pb, 0, size - 8);
8847 avio_seek(pb, moov_pos, SEEK_SET);
8848 } else {
8849
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
180 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8850 return res;
8851 }
8852
8853
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 181 times.
183 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8854 // With hybrid fragmentation, only write the mdat size (hiding
8855 // the original moov and all the fragments within the mdat)
8856 // after we've successfully written the complete moov, to avoid
8857 // risk for an unreadable file if writing the final moov fails.
8858 2 mov_write_mdat_size(s);
8859 }
8860
8861 183 res = 0;
8862 } else {
8863 36 mov_auto_flush_fragment(s, 1);
8864
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 36 times.
104 for (i = 0; i < mov->nb_tracks; i++)
8865 68 mov->tracks[i].data_offset = 0;
8866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8867 int64_t end;
8868 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8869 res = shift_data(s);
8870 if (res < 0)
8871 return res;
8872 end = avio_tell(pb);
8873 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8874 mov_write_sidx_tags(pb, mov, -1, 0);
8875 avio_seek(pb, end, SEEK_SET);
8876 }
8877
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8878 36 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8879 36 res = mov_write_mfra_tag(pb, mov);
8880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (res < 0)
8881 return res;
8882 }
8883 }
8884
8885 219 return res;
8886 }
8887
8888 239 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8889 const AVPacket *pkt)
8890 {
8891 239 int ret = 1;
8892
8893
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 230 times.
239 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8894
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
8895 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 230 times.
230 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8897 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8898 }
8899
8900 239 return ret;
8901 }
8902
8903 #if CONFIG_AVIF_MUXER
8904 static int avif_write_trailer(AVFormatContext *s)
8905 {
8906 AVIOContext *pb = s->pb;
8907 MOVMuxContext *mov = s->priv_data;
8908 int64_t pos_backup, extent_offsets[2];
8909 uint8_t *buf;
8910 int buf_size, moov_size;
8911
8912 if (mov->moov_written) return 0;
8913
8914 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8915 if (mov->is_animated_avif && mov->nb_streams > 1) {
8916 // For animated avif with alpha channel, we need to write a tref tag
8917 // with type "auxl".
8918 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8919 mov->tracks[1].tref_id = 1;
8920 }
8921 mov_write_identification(pb, s);
8922 mov_write_meta_tag(pb, mov, s);
8923
8924 moov_size = get_moov_size(s);
8925 for (int i = 0; i < mov->nb_tracks; i++)
8926 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8927
8928 if (mov->is_animated_avif) {
8929 int ret;
8930 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8931 return ret;
8932 }
8933
8934 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8935 avio_wb32(pb, buf_size + 8);
8936 ffio_wfourcc(pb, "mdat");
8937
8938 // The offset for the YUV planes is the starting position of mdat.
8939 extent_offsets[0] = avio_tell(pb);
8940 // The offset for alpha plane is YUV offset + YUV size.
8941 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8942
8943 avio_write(pb, buf, buf_size);
8944
8945 // write extent offsets.
8946 pos_backup = avio_tell(pb);
8947 for (int i = 0; i < mov->nb_streams; i++) {
8948 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8949 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8950 return AVERROR_INVALIDDATA;
8951 }
8952 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8953 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8954 }
8955 avio_seek(pb, pos_backup, SEEK_SET);
8956
8957 return 0;
8958 }
8959 #endif
8960
8961 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8962 static const AVCodecTag codec_3gp_tags[] = {
8963 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8964 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8965 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8966 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8967 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8968 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8969 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8970 { AV_CODEC_ID_NONE, 0 },
8971 };
8972 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8973 #endif
8974
8975 static const AVCodecTag codec_mp4_tags[] = {
8976 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8977 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8978 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8979 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8980 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8981 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8982 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8983 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8984 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8985 { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') },
8986 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
8987 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8988 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8989 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8990 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8991 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8992 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8993 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8994 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8995 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8996 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8997 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8998 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8999 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
9000 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
9001 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
9002 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
9003 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
9004 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
9005 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
9006 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
9007 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
9008 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
9009 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
9010 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
9011 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
9012 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
9013 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
9014 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
9015 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
9016 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
9017 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
9018
9019 /* ISO/IEC 23003-5 integer formats */
9020 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
9021 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
9022 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
9023 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
9024 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
9025 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
9026 /* ISO/IEC 23003-5 floating-point formats */
9027 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
9028 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
9029 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
9030 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
9031
9032 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
9033
9034 { AV_CODEC_ID_NONE, 0 },
9035 };
9036 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
9037 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
9038 #endif
9039
9040 static const AVCodecTag codec_ism_tags[] = {
9041 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
9042 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
9043 { AV_CODEC_ID_NONE , 0 },
9044 };
9045
9046 static const AVCodecTag codec_ipod_tags[] = {
9047 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9048 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9049 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9050 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
9051 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
9052 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9053 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
9054 { AV_CODEC_ID_NONE, 0 },
9055 };
9056
9057 static const AVCodecTag codec_f4v_tags[] = {
9058 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
9059 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9060 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9061 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
9062 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
9063 { AV_CODEC_ID_NONE, 0 },
9064 };
9065
9066 #if CONFIG_AVIF_MUXER
9067
9068 static const AVOption avif_options[] = {
9069 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
9070 { "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 },
9071 { NULL },
9072 };
9073 static const AVCodecTag codec_avif_tags[] = {
9074 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
9075 { AV_CODEC_ID_NONE, 0 },
9076 };
9077 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
9078
9079 static const AVClass mov_avif_muxer_class = {
9080 .class_name = "avif muxer",
9081 .item_name = av_default_item_name,
9082 .option = avif_options,
9083 .version = LIBAVUTIL_VERSION_INT,
9084 };
9085 #endif
9086
9087 #if CONFIG_MOV_MUXER
9088 const FFOutputFormat ff_mov_muxer = {
9089 .p.name = "mov",
9090 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
9091 .p.extensions = "mov",
9092 .priv_data_size = sizeof(MOVMuxContext),
9093 .p.audio_codec = AV_CODEC_ID_AAC,
9094 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9095 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9096 .init = mov_init,
9097 .write_header = mov_write_header,
9098 .write_packet = mov_write_packet,
9099 .write_trailer = mov_write_trailer,
9100 .deinit = mov_free,
9101 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9102 .p.codec_tag = (const AVCodecTag* const []){
9103 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
9104 },
9105 .check_bitstream = mov_check_bitstream,
9106 .p.priv_class = &mov_isobmff_muxer_class,
9107 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9108 };
9109 #endif
9110 #if CONFIG_TGP_MUXER
9111 const FFOutputFormat ff_tgp_muxer = {
9112 .p.name = "3gp",
9113 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9114 .p.extensions = "3gp",
9115 .priv_data_size = sizeof(MOVMuxContext),
9116 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9117 .p.video_codec = AV_CODEC_ID_H263,
9118 .init = mov_init,
9119 .write_header = mov_write_header,
9120 .write_packet = mov_write_packet,
9121 .write_trailer = mov_write_trailer,
9122 .deinit = mov_free,
9123 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9124 .p.codec_tag = codec_3gp_tags_list,
9125 .check_bitstream = mov_check_bitstream,
9126 .p.priv_class = &mov_isobmff_muxer_class,
9127 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9128 };
9129 #endif
9130 #if CONFIG_MP4_MUXER
9131 const FFOutputFormat ff_mp4_muxer = {
9132 .p.name = "mp4",
9133 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9134 .p.mime_type = "video/mp4",
9135 .p.extensions = "mp4",
9136 .priv_data_size = sizeof(MOVMuxContext),
9137 .p.audio_codec = AV_CODEC_ID_AAC,
9138 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9139 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9140 .init = mov_init,
9141 .write_header = mov_write_header,
9142 .write_packet = mov_write_packet,
9143 .write_trailer = mov_write_trailer,
9144 .deinit = mov_free,
9145 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9146 .p.codec_tag = mp4_codec_tags_list,
9147 .check_bitstream = mov_check_bitstream,
9148 .p.priv_class = &mov_isobmff_muxer_class,
9149 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9150 };
9151 #endif
9152 #if CONFIG_PSP_MUXER
9153 const FFOutputFormat ff_psp_muxer = {
9154 .p.name = "psp",
9155 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9156 .p.extensions = "mp4,psp",
9157 .priv_data_size = sizeof(MOVMuxContext),
9158 .p.audio_codec = AV_CODEC_ID_AAC,
9159 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9160 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9161 .init = mov_init,
9162 .write_header = mov_write_header,
9163 .write_packet = mov_write_packet,
9164 .write_trailer = mov_write_trailer,
9165 .deinit = mov_free,
9166 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9167 .p.codec_tag = mp4_codec_tags_list,
9168 .check_bitstream = mov_check_bitstream,
9169 .p.priv_class = &mov_isobmff_muxer_class,
9170 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9171 };
9172 #endif
9173 #if CONFIG_TG2_MUXER
9174 const FFOutputFormat ff_tg2_muxer = {
9175 .p.name = "3g2",
9176 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9177 .p.extensions = "3g2",
9178 .priv_data_size = sizeof(MOVMuxContext),
9179 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9180 .p.video_codec = AV_CODEC_ID_H263,
9181 .init = mov_init,
9182 .write_header = mov_write_header,
9183 .write_packet = mov_write_packet,
9184 .write_trailer = mov_write_trailer,
9185 .deinit = mov_free,
9186 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9187 .p.codec_tag = codec_3gp_tags_list,
9188 .check_bitstream = mov_check_bitstream,
9189 .p.priv_class = &mov_isobmff_muxer_class,
9190 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9191 };
9192 #endif
9193 #if CONFIG_IPOD_MUXER
9194 const FFOutputFormat ff_ipod_muxer = {
9195 .p.name = "ipod",
9196 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9197 .p.mime_type = "video/mp4",
9198 .p.extensions = "m4v,m4a,m4b",
9199 .priv_data_size = sizeof(MOVMuxContext),
9200 .p.audio_codec = AV_CODEC_ID_AAC,
9201 .p.video_codec = AV_CODEC_ID_H264,
9202 .init = mov_init,
9203 .write_header = mov_write_header,
9204 .write_packet = mov_write_packet,
9205 .write_trailer = mov_write_trailer,
9206 .deinit = mov_free,
9207 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9208 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9209 .check_bitstream = mov_check_bitstream,
9210 .p.priv_class = &mov_isobmff_muxer_class,
9211 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9212 };
9213 #endif
9214 #if CONFIG_ISMV_MUXER
9215 const FFOutputFormat ff_ismv_muxer = {
9216 .p.name = "ismv",
9217 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9218 .p.mime_type = "video/mp4",
9219 .p.extensions = "ismv,isma",
9220 .priv_data_size = sizeof(MOVMuxContext),
9221 .p.audio_codec = AV_CODEC_ID_AAC,
9222 .p.video_codec = AV_CODEC_ID_H264,
9223 .init = mov_init,
9224 .write_header = mov_write_header,
9225 .write_packet = mov_write_packet,
9226 .write_trailer = mov_write_trailer,
9227 .deinit = mov_free,
9228 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9229 .p.codec_tag = (const AVCodecTag* const []){
9230 codec_mp4_tags, codec_ism_tags, 0 },
9231 .check_bitstream = mov_check_bitstream,
9232 .p.priv_class = &mov_isobmff_muxer_class,
9233 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9234 };
9235 #endif
9236 #if CONFIG_F4V_MUXER
9237 const FFOutputFormat ff_f4v_muxer = {
9238 .p.name = "f4v",
9239 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9240 .p.mime_type = "application/f4v",
9241 .p.extensions = "f4v",
9242 .priv_data_size = sizeof(MOVMuxContext),
9243 .p.audio_codec = AV_CODEC_ID_AAC,
9244 .p.video_codec = AV_CODEC_ID_H264,
9245 .init = mov_init,
9246 .write_header = mov_write_header,
9247 .write_packet = mov_write_packet,
9248 .write_trailer = mov_write_trailer,
9249 .deinit = mov_free,
9250 .p.flags = AVFMT_GLOBALHEADER,
9251 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9252 .check_bitstream = mov_check_bitstream,
9253 .p.priv_class = &mov_isobmff_muxer_class,
9254 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9255 };
9256 #endif
9257 #if CONFIG_AVIF_MUXER
9258 const FFOutputFormat ff_avif_muxer = {
9259 .p.name = "avif",
9260 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9261 .p.mime_type = "image/avif",
9262 .p.extensions = "avif",
9263 .priv_data_size = sizeof(MOVMuxContext),
9264 .p.video_codec = AV_CODEC_ID_AV1,
9265 .init = mov_init,
9266 .write_header = mov_write_header,
9267 .write_packet = mov_write_packet,
9268 .write_trailer = avif_write_trailer,
9269 .deinit = mov_free,
9270 .p.flags = AVFMT_GLOBALHEADER,
9271 .p.codec_tag = codec_avif_tags_list,
9272 .p.priv_class = &mov_avif_muxer_class,
9273 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9274 };
9275 #endif
9276