FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2025-10-29 00:48:36
Exec Total Coverage
Lines: 3702 5504 67.3%
Functions: 175 229 76.4%
Branches: 2175 3775 57.6%

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 "libavcodec/ac3_parser_internal.h"
42 #include "libavcodec/dnxhddata.h"
43 #include "libavcodec/flac.h"
44 #include "libavcodec/get_bits.h"
45
46 #include "libavcodec/internal.h"
47 #include "libavcodec/put_bits.h"
48 #include "libavcodec/vc1_common.h"
49 #include "libavcodec/raw.h"
50 #include "internal.h"
51 #include "libavutil/avstring.h"
52 #include "libavutil/channel_layout.h"
53 #include "libavutil/csp.h"
54 #include "libavutil/intfloat.h"
55 #include "libavutil/mathematics.h"
56 #include "libavutil/libm.h"
57 #include "libavutil/mem.h"
58 #include "libavutil/opt.h"
59 #include "libavutil/dict.h"
60 #include "libavutil/pixdesc.h"
61 #include "libavutil/stereo3d.h"
62 #include "libavutil/timecode.h"
63 #include "libavutil/dovi_meta.h"
64 #include "libavutil/uuid.h"
65 #include "hevc.h"
66 #include "rtpenc.h"
67 #include "nal.h"
68 #include "mov_chan.h"
69 #include "movenc_ttml.h"
70 #include "mux.h"
71 #include "rawutils.h"
72 #include "ttmlenc.h"
73 #include "version.h"
74 #include "vpcc.h"
75 #include "vvc.h"
76
77 static const AVOption options[] = {
78 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
79 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
80 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
82 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
84 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
85 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
87 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
88 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
89 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
90 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
91 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
92 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
104 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
105 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
106 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
107 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
116 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
117 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
118 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
119 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
120 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
121 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
122 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
124 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
125 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
128 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
129 { NULL },
130 };
131
132 static const AVClass mov_isobmff_muxer_class = {
133 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
134 .item_name = av_default_item_name,
135 .option = options,
136 .version = LIBAVUTIL_VERSION_INT,
137 };
138
139 static int get_moov_size(AVFormatContext *s);
140 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
141
142 29 static int utf8len(const uint8_t *b)
143 {
144 29 int len = 0;
145 int val;
146
2/2
✓ Branch 0 taken 552 times.
✓ Branch 1 taken 29 times.
581 while (*b) {
147
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;)
148 552 len++;
149 }
150 29 return len;
151 }
152
153 //FIXME support 64 bit variant with wide placeholders
154 6950 static int64_t update_size(AVIOContext *pb, int64_t pos)
155 {
156 6950 int64_t curpos = avio_tell(pb);
157 6950 avio_seek(pb, pos, SEEK_SET);
158 6950 avio_wb32(pb, curpos - pos); /* rewrite size */
159 6950 avio_seek(pb, curpos, SEEK_SET);
160
161 6950 return curpos - pos;
162 }
163
164 347 static int co64_required(const MOVTrack *track)
165 {
166
3/4
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 249 times.
347 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
167 return 1;
168 347 return 0;
169 }
170
171 20704 static int is_cover_image(const AVStream *st)
172 {
173 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
174 * is encoded as sparse video track */
175
3/4
✓ Branch 0 taken 20704 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 20692 times.
20704 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
176 }
177
178 6 static int rtp_hinting_needed(const AVStream *st)
179 {
180 /* Add hint tracks for each real audio and video stream */
181
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
182 return 0;
183
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
184
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
185 }
186
187 /* Chunk offset atom */
188 347 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
189 {
190 int i;
191 347 int mode64 = co64_required(track); // use 32 bit size variant if possible
192 347 int64_t pos = avio_tell(pb);
193 347 avio_wb32(pb, 0); /* size */
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 347 times.
347 if (mode64)
195 ffio_wfourcc(pb, "co64");
196 else
197 347 ffio_wfourcc(pb, "stco");
198 347 avio_wb32(pb, 0); /* version & flags */
199 347 avio_wb32(pb, track->chunkCount); /* entry count */
200
2/2
✓ Branch 0 taken 13678 times.
✓ Branch 1 taken 347 times.
14025 for (i = 0; i < track->entry; i++) {
201
2/2
✓ Branch 0 taken 10571 times.
✓ Branch 1 taken 3107 times.
13678 if (!track->cluster[i].chunkNum)
202 10571 continue;
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3107 times.
3107 if (mode64 == 1)
204 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
205 else
206 3107 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
207 }
208 347 return update_size(pb, pos);
209 }
210
211 /* Sample size atom */
212 347 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
213 {
214 347 int equalChunks = 1;
215 347 int i, j, entries = 0, tst = -1, oldtst = -1;
216
217 347 int64_t pos = avio_tell(pb);
218 347 avio_wb32(pb, 0); /* size */
219 347 ffio_wfourcc(pb, "stsz");
220 347 avio_wb32(pb, 0); /* version & flags */
221
222
2/2
✓ Branch 0 taken 13678 times.
✓ Branch 1 taken 347 times.
14025 for (i = 0; i < track->entry; i++) {
223 13678 tst = track->cluster[i].size / track->cluster[i].entries;
224
4/4
✓ Branch 0 taken 13429 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 8736 times.
✓ Branch 3 taken 4693 times.
13678 if (oldtst != -1 && tst != oldtst)
225 8736 equalChunks = 0;
226 13678 oldtst = tst;
227 13678 entries += track->cluster[i].entries;
228 }
229
4/4
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 98 times.
460 if (equalChunks && track->entry) {
230
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;
231 113 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
232 113 avio_wb32(pb, sSize); // sample size
233 113 avio_wb32(pb, entries); // sample count
234 } else {
235 234 avio_wb32(pb, 0); // sample size
236 234 avio_wb32(pb, entries); // sample count
237
2/2
✓ Branch 0 taken 9899 times.
✓ Branch 1 taken 234 times.
10133 for (i = 0; i < track->entry; i++) {
238
2/2
✓ Branch 0 taken 9899 times.
✓ Branch 1 taken 9899 times.
19798 for (j = 0; j < track->cluster[i].entries; j++) {
239 9899 avio_wb32(pb, track->cluster[i].size /
240 9899 track->cluster[i].entries);
241 }
242 }
243 }
244 347 return update_size(pb, pos);
245 }
246
247 /* Sample to chunk atom */
248 347 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
249 {
250 347 int index = 0, oldidx = -1, oldval = -1, i;
251 int64_t entryPos, curpos;
252
253 347 int64_t pos = avio_tell(pb);
254 347 avio_wb32(pb, 0); /* size */
255 347 ffio_wfourcc(pb, "stsc");
256 347 avio_wb32(pb, 0); // version & flags
257 347 entryPos = avio_tell(pb);
258 347 avio_wb32(pb, track->chunkCount); // entry count
259
2/2
✓ Branch 0 taken 13678 times.
✓ Branch 1 taken 347 times.
14025 for (i = 0; i < track->entry; i++) {
260
2/2
✓ Branch 0 taken 2283 times.
✓ Branch 1 taken 11395 times.
13678 if ((oldval != track->cluster[i].samples_in_chunk ||
261
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2282 times.
✓ Branch 2 taken 825 times.
✓ Branch 3 taken 10571 times.
13678 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
262 825 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
263 825 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
264 825 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
265 825 oldval = track->cluster[i].samples_in_chunk;
266 825 oldidx = track->cluster[i].stsd_index;
267 825 index++;
268 }
269 }
270 347 curpos = avio_tell(pb);
271 347 avio_seek(pb, entryPos, SEEK_SET);
272 347 avio_wb32(pb, index); // rewrite size
273 347 avio_seek(pb, curpos, SEEK_SET);
274
275 347 return update_size(pb, pos);
276 }
277
278 /* Sync sample atom */
279 59 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
280 {
281 int64_t curpos, entryPos;
282 59 int i, index = 0;
283 59 int64_t pos = avio_tell(pb);
284 59 avio_wb32(pb, 0); // size
285
1/2
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
59 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
286 59 avio_wb32(pb, 0); // version & flags
287 59 entryPos = avio_tell(pb);
288 59 avio_wb32(pb, track->entry); // entry count
289
2/2
✓ Branch 0 taken 3213 times.
✓ Branch 1 taken 59 times.
3272 for (i = 0; i < track->entry; i++) {
290
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 3004 times.
3213 if (track->cluster[i].flags & flag) {
291 209 avio_wb32(pb, i + 1);
292 209 index++;
293 }
294 }
295 59 curpos = avio_tell(pb);
296 59 avio_seek(pb, entryPos, SEEK_SET);
297 59 avio_wb32(pb, index); // rewrite size
298 59 avio_seek(pb, curpos, SEEK_SET);
299 59 return update_size(pb, pos);
300 }
301
302 /* Sample dependency atom */
303 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
304 {
305 int i;
306 uint8_t leading, dependent, reference, redundancy;
307 3 int64_t pos = avio_tell(pb);
308 3 avio_wb32(pb, 0); // size
309 3 ffio_wfourcc(pb, "sdtp");
310 3 avio_wb32(pb, 0); // version & flags
311
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
312 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
313 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
314
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
315 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
316 }
317
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
318 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
319 }
320 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
321 13 (reference << 2) | redundancy);
322 }
323 3 return update_size(pb, pos);
324 }
325
326 #if CONFIG_IAMFENC
327 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
328 {
329 AVIOContext *dyn_bc;
330 5 int64_t pos = avio_tell(pb);
331 5 uint8_t *dyn_buf = NULL;
332 int dyn_size;
333 5 int ret = avio_open_dyn_buf(&dyn_bc);
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
335 return ret;
336
337 5 avio_wb32(pb, 0);
338 5 ffio_wfourcc(pb, "iacb");
339 5 avio_w8(pb, 1); // configurationVersion
340
341 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
343 return ret;
344
345 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
346 5 ffio_write_leb(pb, dyn_size);
347 5 avio_write(pb, dyn_buf, dyn_size);
348 5 av_free(dyn_buf);
349
350 5 return update_size(pb, pos);
351 }
352 #endif
353
354 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
355 {
356 avio_wb32(pb, 0x11); /* size */
357 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
358 else ffio_wfourcc(pb, "damr");
359 ffio_wfourcc(pb, "FFMP");
360 avio_w8(pb, 0); /* decoder version */
361
362 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
363 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
364 avio_w8(pb, 0x01); /* Frames per sample */
365 return 0x11;
366 }
367
368 struct eac3_info {
369 AVPacket *pkt;
370 uint8_t ec3_done;
371 uint8_t num_blocks;
372
373 /* Layout of the EC3SpecificBox */
374 /* maximum bitrate */
375 uint16_t data_rate;
376 int8_t ac3_bit_rate_code;
377 /* number of independent substreams */
378 uint8_t num_ind_sub;
379 struct {
380 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
381 uint8_t fscod;
382 /* bit stream identification 5 bits */
383 uint8_t bsid;
384 /* one bit reserved */
385 /* audio service mixing (not supported yet) 1 bit */
386 /* bit stream mode 3 bits */
387 uint8_t bsmod;
388 /* audio coding mode 3 bits */
389 uint8_t acmod;
390 /* sub woofer on 1 bit */
391 uint8_t lfeon;
392 /* 3 bits reserved */
393 /* number of dependent substreams associated with this substream 4 bits */
394 uint8_t num_dep_sub;
395 /* channel locations of the dependent substream(s), if any, 9 bits */
396 uint16_t chan_loc;
397 /* if there is no dependent substream, then one bit reserved instead */
398 } substream[1]; /* TODO: support 8 independent substreams */
399 /* indicates the decoding complexity, 8 bits */
400 uint8_t complexity_index_type_a;
401 };
402
403 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
404 {
405 5 struct eac3_info *info = track->eac3_priv;
406 PutBitContext pbc;
407 uint8_t buf[3];
408
409
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) {
410 av_log(s, AV_LOG_ERROR,
411 "Cannot write moov atom before AC3 packets."
412 " Set the delay_moov flag to fix this.\n");
413 return AVERROR(EINVAL);
414 }
415
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
417 av_log(s, AV_LOG_ERROR,
418 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
419 "ISOBMFF specification in ETSI TS 102 366!\n",
420 info->substream[0].bsid);
421 return AVERROR(EINVAL);
422 }
423
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
425 av_log(s, AV_LOG_ERROR,
426 "No valid AC3 bit rate code for data rate of %d!\n",
427 info->data_rate);
428 return AVERROR(EINVAL);
429 }
430
431 5 avio_wb32(pb, 11);
432 5 ffio_wfourcc(pb, "dac3");
433
434 5 init_put_bits(&pbc, buf, sizeof(buf));
435 5 put_bits(&pbc, 2, info->substream[0].fscod);
436 5 put_bits(&pbc, 5, info->substream[0].bsid);
437 5 put_bits(&pbc, 3, info->substream[0].bsmod);
438 5 put_bits(&pbc, 3, info->substream[0].acmod);
439 5 put_bits(&pbc, 1, info->substream[0].lfeon);
440 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
441 5 put_bits(&pbc, 5, 0); // reserved
442
443 5 flush_put_bits(&pbc);
444 5 avio_write(pb, buf, sizeof(buf));
445
446 5 return 11;
447 }
448
449 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
450 {
451 1039 AC3HeaderInfo *hdr = NULL;
452 struct eac3_info *info;
453 int num_blocks, ret;
454
455
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
456
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
457 return AVERROR(ENOMEM);
458
459 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
460 }
461 1039 info = track->eac3_priv;
462
463
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()))
464 return AVERROR(ENOMEM);
465
466
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) {
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
468 goto end;
469
470 /* drop the packets until we see a good one */
471
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
472 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
473 1 ret = 0;
474 } else
475 ret = AVERROR_INVALIDDATA;
476 1 goto end;
477 }
478
479 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
480 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
481 hdr->ac3_bit_rate_code);
482 1038 info->complexity_index_type_a = hdr->complexity_index_type_a;
483
484 1038 num_blocks = hdr->num_blocks;
485
486
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
487 /* AC-3 substream must be the first one */
488
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) {
489 ret = AVERROR(EINVAL);
490 goto end;
491 }
492
493 /* this should always be the case, given that our AC-3 parser
494 * concatenates dependent frames to their independent parent */
495
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
496
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
497 /* substream ids must be incremental */
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
499 ret = AVERROR(EINVAL);
500 goto end;
501 }
502
503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
504 //info->num_ind_sub++;
505 avpriv_request_sample(mov->fc, "Multiple independent substreams");
506 ret = AVERROR_PATCHWELCOME;
507 goto end;
508
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
509
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) {
510 1 info->ec3_done = 1;
511 1 goto concatenate;
512 }
513 } else {
514 if (hdr->substreamid != 0) {
515 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
516 ret = AVERROR_PATCHWELCOME;
517 goto end;
518 }
519 }
520
521 /* fill the info needed for the "dec3" atom */
522 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
523 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
524 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
525 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
526 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
527
528
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
529 // with AC-3 we only require the information of a single packet,
530 // so we can finish as soon as the basic values of the bit stream
531 // have been set to the track's informational structure.
532 4 info->ec3_done = 1;
533 4 goto concatenate;
534 }
535
536 /* Parse dependent substream(s), if any */
537
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
538 int cumul_size = hdr->frame_size;
539 int parent = hdr->substreamid;
540
541 while (cumul_size != pkt->size) {
542 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
543 if (ret < 0)
544 goto end;
545 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
546 ret = AVERROR(EINVAL);
547 goto end;
548 }
549 info->substream[parent].num_dep_sub++;
550 ret /= 8;
551
552 /* get the dependent stream channel map, if exists */
553 if (hdr->channel_map_present)
554 info->substream[parent].chan_loc |= (hdr->channel_map >> 5) & 0x1f;
555 else
556 info->substream[parent].chan_loc |= hdr->channel_mode;
557 cumul_size += hdr->frame_size;
558 }
559 }
560 }
561
562 1033 concatenate:
563
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) {
564 1038 ret = pkt->size;
565 1038 goto end;
566 }
567 else if (info->num_blocks + num_blocks > 6) {
568 ret = AVERROR_INVALIDDATA;
569 goto end;
570 }
571
572 if (!info->num_blocks) {
573 ret = av_packet_ref(info->pkt, pkt);
574 if (!ret)
575 info->num_blocks = num_blocks;
576 goto end;
577 } else {
578 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
579 goto end;
580 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
581 info->num_blocks += num_blocks;
582 info->pkt->duration += pkt->duration;
583 if (info->num_blocks != 6)
584 goto end;
585 av_packet_unref(pkt);
586 av_packet_move_ref(pkt, info->pkt);
587 info->num_blocks = 0;
588 }
589 ret = pkt->size;
590
591 1039 end:
592 1039 av_free(hdr);
593
594 1039 return ret;
595 }
596
597 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
598 {
599 PutBitContext pbc;
600 uint8_t *buf;
601 struct eac3_info *info;
602 int size, i;
603
604
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
605 av_log(s, AV_LOG_ERROR,
606 "Cannot write moov atom before EAC3 packets parsed.\n");
607 return AVERROR(EINVAL);
608 }
609
610 1 info = track->eac3_priv;
611
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);
612 1 buf = av_malloc(size);
613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
614 return AVERROR(ENOMEM);
615 }
616
617 1 init_put_bits(&pbc, buf, size);
618 1 put_bits(&pbc, 13, info->data_rate);
619 1 put_bits(&pbc, 3, info->num_ind_sub);
620
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
621 1 put_bits(&pbc, 2, info->substream[i].fscod);
622 1 put_bits(&pbc, 5, info->substream[i].bsid);
623 1 put_bits(&pbc, 1, 0); /* reserved */
624 1 put_bits(&pbc, 1, 0); /* asvc */
625 1 put_bits(&pbc, 3, info->substream[i].bsmod);
626 1 put_bits(&pbc, 3, info->substream[i].acmod);
627 1 put_bits(&pbc, 1, info->substream[i].lfeon);
628 1 put_bits(&pbc, 3, 0); /* reserved */
629 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
630
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
631 1 put_bits(&pbc, 1, 0); /* reserved */
632 } else {
633 put_bits(&pbc, 9, info->substream[i].chan_loc);
634 }
635 }
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (info->complexity_index_type_a) {
637 put_bits(&pbc, 7, 0); /* reserved */
638 put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
639 put_bits(&pbc, 8, info->complexity_index_type_a);
640 }
641 1 flush_put_bits(&pbc);
642 1 size = put_bytes_output(&pbc);
643
644 1 avio_wb32(pb, size + 8);
645 1 ffio_wfourcc(pb, "dec3");
646 1 avio_write(pb, buf, size);
647
648 1 av_free(buf);
649
650 1 return size;
651 }
652
653 /**
654 * This function writes extradata "as is".
655 * Extradata must be formatted like a valid atom (with size and tag).
656 */
657 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
658 {
659 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
660 12 return track->extradata_size[track->last_stsd_index];
661 }
662
663 static int mov_write_enda_tag(AVIOContext *pb)
664 {
665 avio_wb32(pb, 10);
666 ffio_wfourcc(pb, "enda");
667 avio_wb16(pb, 1); /* little endian */
668 return 10;
669 }
670
671 2 static int mov_write_enda_tag_be(AVIOContext *pb)
672 {
673 2 avio_wb32(pb, 10);
674 2 ffio_wfourcc(pb, "enda");
675 2 avio_wb16(pb, 0); /* big endian */
676 2 return 10;
677 }
678
679 336 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
680 {
681 336 int i = 3;
682 336 avio_w8(pb, tag);
683
2/2
✓ Branch 0 taken 1008 times.
✓ Branch 1 taken 336 times.
1344 for (; i > 0; i--)
684 1008 avio_w8(pb, (size >> (7 * i)) | 0x80);
685 336 avio_w8(pb, size & 0x7F);
686 336 }
687
688 227 static unsigned compute_avg_bitrate(MOVTrack *track)
689 {
690 227 uint64_t size = 0;
691 int i;
692
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 183 times.
227 if (!track->track_duration)
693 44 return 0;
694
2/2
✓ Branch 0 taken 9074 times.
✓ Branch 1 taken 183 times.
9257 for (i = 0; i < track->entry; i++)
695 9074 size += track->cluster[i].size;
696 183 return size * 8 * track->timescale / track->track_duration;
697 }
698
699 struct mpeg4_bit_rate_values {
700 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
701 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
702 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
703 };
704
705 227 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
706 {
707 454 const AVPacketSideData *sd = track->st ?
708 226 av_packet_side_data_get(track->st->codecpar->coded_side_data,
709 226 track->st->codecpar->nb_coded_side_data,
710
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 1 times.
227 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
711
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 190 times.
227 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
712 227 struct mpeg4_bit_rate_values bit_rates = { 0 };
713
714 227 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
715
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 89 times.
227 if (!bit_rates.avg_bit_rate) {
716 // if the average bit rate cannot be calculated at this point, such as
717 // in the case of fragmented MP4, utilize the following values as
718 // fall-back in priority order:
719 //
720 // 1. average bit rate property
721 // 2. bit rate (usually average over the whole clip)
722 // 3. maximum bit rate property
723
724
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) {
725 6 bit_rates.avg_bit_rate = props->avg_bitrate;
726
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 123 times.
132 } else if (track->par->bit_rate) {
727 9 bit_rates.avg_bit_rate = track->par->bit_rate;
728
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) {
729 bit_rates.avg_bit_rate = props->max_bitrate;
730 }
731 }
732
733 // (FIXME should be max rate in any 1 sec window)
734 227 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
735 bit_rates.avg_bit_rate);
736
737 // utilize values from properties if we have them available
738
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 190 times.
227 if (props) {
739 // no avg_bitrate signals that the track is VBR
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (!props->avg_bitrate)
741 bit_rates.avg_bit_rate = props->avg_bitrate;
742 37 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
743 props->max_bitrate);
744 37 bit_rates.buffer_size = props->buffer_size / 8;
745 }
746
747 227 return bit_rates;
748 }
749
750 85 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
751 {
752 85 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
753 85 int64_t pos = avio_tell(pb);
754 170 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
755
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 4 times.
85 5 + track->extradata_size[track->last_stsd_index] : 0;
756
757 85 avio_wb32(pb, 0); // size
758 85 ffio_wfourcc(pb, "esds");
759 85 avio_wb32(pb, 0); // Version
760
761 // ES descriptor
762 85 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
763 85 avio_wb16(pb, track->track_id);
764 85 avio_w8(pb, 0x00); // flags (= no flags)
765
766 // DecoderConfig descriptor
767 85 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
768
769 // Object type indication
770
1/2
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
85 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 track->par->codec_id == AV_CODEC_ID_MP3) &&
772 track->par->sample_rate > 24000)
773 avio_w8(pb, 0x6B); // 11172-3
774 else
775 85 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
776
777 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
778 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
780 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
781
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 29 times.
85 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
782 56 avio_w8(pb, 0x15); // flags (= Audiostream)
783 else
784 29 avio_w8(pb, 0x11); // flags (= Visualstream)
785
786 85 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
787 85 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
788 85 avio_wb32(pb, bit_rates.avg_bit_rate);
789
790
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 4 times.
85 if (track->extradata_size[track->last_stsd_index]) {
791 // DecoderSpecific info descriptor
792 81 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
793 81 avio_write(pb, track->extradata[track->last_stsd_index],
794 81 track->extradata_size[track->last_stsd_index]);
795 }
796
797 // SL descriptor
798 85 put_descr(pb, 0x06, 1);
799 85 avio_w8(pb, 0x02);
800 85 return update_size(pb, pos);
801 }
802
803 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
804 {
805
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
806
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
807
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 ||
808 codec_id == AV_CODEC_ID_PCM_F64LE;
809 }
810
811 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
812 {
813
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
814
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
815
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 ||
816 codec_id == AV_CODEC_ID_PCM_F64BE;
817 }
818
819 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
820 {
821 int ret;
822 int64_t pos = avio_tell(pb);
823 avio_wb32(pb, 0);
824 avio_wl32(pb, track->tag); // store it byteswapped
825 track->par->codec_tag = av_bswap16(track->tag >> 16);
826 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
827 return ret;
828 return update_size(pb, pos);
829 }
830
831 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
832 {
833 int ret;
834 int64_t pos = avio_tell(pb);
835 avio_wb32(pb, 0);
836 ffio_wfourcc(pb, "wfex");
837 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
838 return ret;
839 return update_size(pb, pos);
840 }
841
842 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
843 {
844 int64_t pos = avio_tell(pb);
845 avio_wb32(pb, 0);
846 ffio_wfourcc(pb, "dfLa");
847 avio_w8(pb, 0); /* version */
848 avio_wb24(pb, 0); /* flags */
849
850 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
851 if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
852 return AVERROR_INVALIDDATA;
853
854 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
855 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
856 avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
857 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
858
859 return update_size(pb, pos);
860 }
861
862 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
863 {
864 int64_t pos = avio_tell(pb);
865 int channels, channel_map;
866 avio_wb32(pb, 0);
867 ffio_wfourcc(pb, "dOps");
868 avio_w8(pb, 0); /* Version */
869 if (track->extradata_size[track->last_stsd_index] < 19) {
870 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
871 return AVERROR_INVALIDDATA;
872 }
873 /* extradata contains an Ogg OpusHead, other than byte-ordering and
874 OpusHead's preceding magic/version, OpusSpecificBox is currently
875 identical. */
876 channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
877 channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
878
879 avio_w8(pb, channels); /* OuputChannelCount */
880 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
881 avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
882 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
883 avio_w8(pb, channel_map); /* ChannelMappingFamily */
884 /* Write the rest of the header out without byte-swapping. */
885 if (channel_map) {
886 if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
887 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
888 return AVERROR_INVALIDDATA;
889 }
890 avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
891 }
892
893 return update_size(pb, pos);
894 }
895
896 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
897 {
898 int64_t pos = avio_tell(pb);
899 int length;
900 avio_wb32(pb, 0);
901 ffio_wfourcc(pb, "dmlp");
902
903 if (track->extradata_size[track->last_stsd_index] < 20) {
904 av_log(s, AV_LOG_ERROR,
905 "Cannot write moov atom before TrueHD packets."
906 " Set the delay_moov flag to fix this.\n");
907 return AVERROR(EINVAL);
908 }
909
910 length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
911 if (length < 20 || length > track->extradata_size[track->last_stsd_index])
912 return AVERROR_INVALIDDATA;
913
914 // Only TrueHD is supported
915 if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
916 return AVERROR_INVALIDDATA;
917
918 avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
919 avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
920 avio_wb32(pb, 0); /* reserved */
921
922 return update_size(pb, pos);
923 }
924
925 69 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
926 {
927 69 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
928 69 AVChannelLayout ch_layout = { 0 };
929 int64_t pos;
930 int ambisonic_order, ambi_channels, non_diegetic_channels;
931 int i, ret;
932
933
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if (!str)
934 69 return 0;
935
936 ret = av_channel_layout_from_string(&ch_layout, str->value);
937 if (ret < 0) {
938 if (ret == AVERROR(EINVAL)) {
939 invalid:
940 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
941 ret = 0;
942 }
943 av_channel_layout_uninit(&ch_layout);
944 return ret;
945 }
946
947 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
948 goto invalid;
949
950 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
951 if (ambisonic_order < 0)
952 goto invalid;
953
954 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
955 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
956 if (non_diegetic_channels &&
957 (non_diegetic_channels != 2 ||
958 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
959 goto invalid;
960
961 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
962
963 pos = avio_tell(pb);
964
965 avio_wb32(pb, 0); // Size
966 ffio_wfourcc(pb, "SA3D");
967 avio_w8(pb, 0); // version
968 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
969 avio_wb32(pb, ambisonic_order); // ambisonic_order
970 avio_w8(pb, 0); // ambisonic_channel_ordering
971 avio_w8(pb, 0); // ambisonic_normalization
972 avio_wb32(pb, ch_layout.nb_channels); // num_channels
973 for (i = 0; i < ambi_channels; i++)
974 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
975 for (; i < ch_layout.nb_channels; i++)
976 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
977
978 av_channel_layout_uninit(&ch_layout);
979
980 return update_size(pb, pos);
981 }
982
983 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
984 {
985 uint32_t layout_tag, bitmap, *channel_desc;
986 40 int64_t pos = avio_tell(pb);
987 int num_desc, ret;
988
989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
990 return 0;
991
992 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
993 &bitmap, &channel_desc);
994
995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
996 if (ret == AVERROR(ENOSYS)) {
997 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
998 "lack of channel information\n");
999 ret = 0;
1000 }
1001
1002 return ret;
1003 }
1004
1005
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) {
1006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1007 1 channel_desc = av_malloc(sizeof(*channel_desc));
1008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1009 return AVERROR(ENOMEM);
1010
1011 1 layout_tag = 0;
1012 1 bitmap = 0;
1013 1 *channel_desc = 3; // channel label "Center"
1014 }
1015
1016
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1017
1018 40 avio_wb32(pb, 0); // Size
1019 40 ffio_wfourcc(pb, "chan"); // Type
1020 40 avio_w8(pb, 0); // Version
1021 40 avio_wb24(pb, 0); // Flags
1022 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1023 40 avio_wb32(pb, bitmap); // mChannelBitmap
1024 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1025
1026
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1027 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1028 3 avio_wb32(pb, 0); // mChannelFlags
1029 3 avio_wl32(pb, 0); // mCoordinates[0]
1030 3 avio_wl32(pb, 0); // mCoordinates[1]
1031 3 avio_wl32(pb, 0); // mCoordinates[2]
1032 }
1033
1034 40 av_free(channel_desc);
1035
1036 40 return update_size(pb, pos);
1037 }
1038
1039 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1040 {
1041 15 int64_t pos = avio_tell(pb);
1042
1043 15 avio_wb32(pb, 0); /* size */
1044 15 ffio_wfourcc(pb, "wave");
1045
1046
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1047 15 avio_wb32(pb, 12); /* size */
1048 15 ffio_wfourcc(pb, "frma");
1049 15 avio_wl32(pb, track->tag);
1050 }
1051
1052
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1053 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1054 3 avio_wb32(pb, 12); /* size */
1055 3 ffio_wfourcc(pb, "mp4a");
1056 3 avio_wb32(pb, 0);
1057 3 mov_write_esds_tag(pb, track);
1058
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1059 mov_write_enda_tag(pb);
1060
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1061 2 mov_write_enda_tag_be(pb);
1062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1063 mov_write_amr_tag(pb, track);
1064
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1065 1 mov_write_ac3_tag(s, pb, track);
1066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1067 mov_write_eac3_tag(s, pb, track);
1068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1069 track->par->codec_id == AV_CODEC_ID_QDM2) {
1070 9 mov_write_extradata_tag(pb, track);
1071 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1072 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1073 mov_write_ms_tag(s, pb, track);
1074 }
1075
1076 15 avio_wb32(pb, 8); /* size */
1077 15 avio_wb32(pb, 0); /* null tag */
1078
1079 15 return update_size(pb, pos);
1080 }
1081
1082 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1083 {
1084 uint8_t *unescaped;
1085 const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1086 track->extradata_size[track->last_stsd_index];
1087 int unescaped_size, seq_found = 0;
1088 int level = 0, interlace = 0;
1089 int packet_seq = track->vc1_info.packet_seq;
1090 int packet_entry = track->vc1_info.packet_entry;
1091 int slices = track->vc1_info.slices;
1092 PutBitContext pbc;
1093
1094 if (track->start_dts == AV_NOPTS_VALUE) {
1095 /* No packets written yet, vc1_info isn't authoritative yet. */
1096 /* Assume inline sequence and entry headers. */
1097 packet_seq = packet_entry = 1;
1098 av_log(NULL, AV_LOG_WARNING,
1099 "moov atom written before any packets, unable to write correct "
1100 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1101 }
1102
1103 unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1104 if (!unescaped)
1105 return AVERROR(ENOMEM);
1106 start = find_next_marker(track->extradata[track->last_stsd_index], end);
1107 for (next = start; next < end; start = next) {
1108 GetBitContext gb;
1109 int size;
1110 next = find_next_marker(start + 4, end);
1111 size = next - start - 4;
1112 if (size <= 0)
1113 continue;
1114 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1115 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1116 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1117 int profile = get_bits(&gb, 2);
1118 if (profile != PROFILE_ADVANCED) {
1119 av_free(unescaped);
1120 return AVERROR(ENOSYS);
1121 }
1122 seq_found = 1;
1123 level = get_bits(&gb, 3);
1124 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1125 * width, height */
1126 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1127 skip_bits(&gb, 1); /* broadcast */
1128 interlace = get_bits1(&gb);
1129 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1130 }
1131 }
1132 if (!seq_found) {
1133 av_free(unescaped);
1134 return AVERROR(ENOSYS);
1135 }
1136
1137 init_put_bits(&pbc, buf, 7);
1138 /* VC1DecSpecStruc */
1139 put_bits(&pbc, 4, 12); /* profile - advanced */
1140 put_bits(&pbc, 3, level);
1141 put_bits(&pbc, 1, 0); /* reserved */
1142 /* VC1AdvDecSpecStruc */
1143 put_bits(&pbc, 3, level);
1144 put_bits(&pbc, 1, 0); /* cbr */
1145 put_bits(&pbc, 6, 0); /* reserved */
1146 put_bits(&pbc, 1, !interlace); /* no interlace */
1147 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1148 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1149 put_bits(&pbc, 1, !slices); /* no slice code */
1150 put_bits(&pbc, 1, 0); /* no bframe */
1151 put_bits(&pbc, 1, 0); /* reserved */
1152
1153 /* framerate */
1154 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1155 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1156 else
1157 put_bits32(&pbc, 0xffffffff);
1158
1159 flush_put_bits(&pbc);
1160
1161 av_free(unescaped);
1162
1163 return 0;
1164 }
1165
1166 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1167 {
1168 uint8_t buf[7] = { 0 };
1169 int ret;
1170
1171 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1172 return ret;
1173
1174 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1175 ffio_wfourcc(pb, "dvc1");
1176 avio_write(pb, buf, sizeof(buf));
1177 avio_write(pb, track->extradata[track->last_stsd_index],
1178 track->extradata_size[track->last_stsd_index]);
1179
1180 return 0;
1181 }
1182
1183 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1184 {
1185 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1186 4 ffio_wfourcc(pb, "glbl");
1187 4 avio_write(pb, track->extradata[track->last_stsd_index],
1188 4 track->extradata_size[track->last_stsd_index]);
1189 4 return 8 + track->extradata_size[track->last_stsd_index];
1190 }
1191
1192 /**
1193 * Compute flags for 'lpcm' tag.
1194 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1195 */
1196 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1197 {
1198
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) {
1199 case AV_CODEC_ID_PCM_F32BE:
1200 case AV_CODEC_ID_PCM_F64BE:
1201 return 11;
1202 case AV_CODEC_ID_PCM_F32LE:
1203 case AV_CODEC_ID_PCM_F64LE:
1204 return 9;
1205 case AV_CODEC_ID_PCM_U8:
1206 return 10;
1207 case AV_CODEC_ID_PCM_S16BE:
1208 case AV_CODEC_ID_PCM_S24BE:
1209 case AV_CODEC_ID_PCM_S32BE:
1210 return 14;
1211 case AV_CODEC_ID_PCM_S8:
1212 case AV_CODEC_ID_PCM_S16LE:
1213 case AV_CODEC_ID_PCM_S24LE:
1214 case AV_CODEC_ID_PCM_S32LE:
1215 return 12;
1216 8 default:
1217 8 return 0;
1218 }
1219 }
1220
1221 29265 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1222 {
1223 int64_t next_dts;
1224
1225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29265 times.
29265 if (cluster_idx >= track->entry)
1226 return 0;
1227
1228
2/2
✓ Branch 0 taken 872 times.
✓ Branch 1 taken 28393 times.
29265 if (cluster_idx + 1 == track->entry)
1229 872 next_dts = track->track_duration + track->start_dts;
1230 else
1231 28393 next_dts = track->cluster[cluster_idx + 1].dts;
1232
1233 29265 next_dts -= track->cluster[cluster_idx].dts;
1234
1235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29265 times.
29265 av_assert0(next_dts >= 0);
1236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29265 times.
29265 av_assert0(next_dts <= INT_MAX);
1237
1238 29265 return next_dts;
1239 }
1240
1241 4 static int get_samples_per_packet(MOVTrack *track)
1242 {
1243 int i, first_duration;
1244
1245 /* use 1 for raw PCM */
1246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1247 return 1;
1248
1249 /* check to see if duration is constant for all clusters */
1250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1251 return 0;
1252 4 first_duration = get_cluster_duration(track, 0);
1253
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1254
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1255 4 return 0;
1256 }
1257 return first_duration;
1258 }
1259
1260 142 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1261 {
1262 142 int64_t pos = avio_tell(pb);
1263 142 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1264
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 &&
1265
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 !bit_rates.buffer_size)
1266 // no useful data to be written, skip
1267 82 return 0;
1268
1269 60 avio_wb32(pb, 0); /* size */
1270 60 ffio_wfourcc(pb, "btrt");
1271
1272 60 avio_wb32(pb, bit_rates.buffer_size);
1273 60 avio_wb32(pb, bit_rates.max_bit_rate);
1274 60 avio_wb32(pb, bit_rates.avg_bit_rate);
1275
1276 60 return update_size(pb, pos);
1277 }
1278
1279 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1280 {
1281 7 int64_t pos = avio_tell(pb);
1282 7 int config = 0;
1283 int ret;
1284 7 uint8_t *speaker_pos = NULL;
1285 7 const AVChannelLayout *layout = &track->par->ch_layout;
1286
1287 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1288
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) {
1289 4 config = 0;
1290 4 speaker_pos = av_malloc(layout->nb_channels);
1291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1292 return AVERROR(ENOMEM);
1293 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1294 4 speaker_pos, layout->nb_channels);
1295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1296 char buf[128] = {0};
1297
1298 av_freep(&speaker_pos);
1299 av_channel_layout_describe(layout, buf, sizeof(buf));
1300 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1301 return ret;
1302 }
1303 }
1304
1305 7 avio_wb32(pb, 0); /* size */
1306 7 ffio_wfourcc(pb, "chnl");
1307 7 avio_wb32(pb, 0); /* version & flags */
1308
1309 7 avio_w8(pb, 1); /* stream_structure */
1310 7 avio_w8(pb, config);
1311
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1312 3 avio_wb64(pb, 0);
1313 } else {
1314 4 avio_write(pb, speaker_pos, layout->nb_channels);
1315 4 av_freep(&speaker_pos);
1316 }
1317
1318 7 return update_size(pb, pos);
1319 }
1320
1321 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1322 {
1323 9 int64_t pos = avio_tell(pb);
1324 int format_flags;
1325 int sample_size;
1326
1327 9 avio_wb32(pb, 0); /* size */
1328 9 ffio_wfourcc(pb, "pcmC");
1329 9 avio_wb32(pb, 0); /* version & flags */
1330
1331 /* 0x01: indicates little-endian format */
1332 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1333
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1335
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 ||
1336 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1337 9 avio_w8(pb, format_flags);
1338 9 sample_size = track->par->bits_per_raw_sample;
1339
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1340 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1342 9 avio_w8(pb, sample_size);
1343
1344 9 return update_size(pb, pos);
1345 }
1346
1347 112 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1348 {
1349 112 int64_t pos = avio_tell(pb);
1350 112 int version = 0;
1351 112 uint32_t tag = track->tag;
1352 112 int ret = 0;
1353
1354
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
112 if (track->mode == MODE_MOV) {
1355
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) {
1356
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1357 tag = AV_RL32("lpcm");
1358 4 version = 2;
1359
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) ||
1360 26 mov_pcm_be_gt16(track->par->codec_id) ||
1361
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1362
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1364 12 version = 1;
1365 }
1366 }
1367
1368 112 avio_wb32(pb, 0); /* size */
1369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (mov->encryption_scheme != MOV_ENC_NONE) {
1370 ffio_wfourcc(pb, "enca");
1371 } else {
1372 112 avio_wl32(pb, tag); // store it byteswapped
1373 }
1374 112 avio_wb32(pb, 0); /* Reserved */
1375 112 avio_wb16(pb, 0); /* Reserved */
1376 112 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1377
1378 /* SoundDescription */
1379 112 avio_wb16(pb, version); /* Version */
1380 112 avio_wb16(pb, 0); /* Revision level */
1381 112 avio_wb32(pb, 0); /* Reserved */
1382
1383
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 108 times.
112 if (version == 2) {
1384 4 avio_wb16(pb, 3);
1385 4 avio_wb16(pb, 16);
1386 4 avio_wb16(pb, 0xfffe);
1387 4 avio_wb16(pb, 0);
1388 4 avio_wb32(pb, 0x00010000);
1389 4 avio_wb32(pb, 72);
1390 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1391 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1392 4 avio_wb32(pb, 0x7F000000);
1393 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1394 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1395 4 avio_wb32(pb, track->sample_size);
1396 4 avio_wb32(pb, get_samples_per_packet(track));
1397 } else {
1398
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 72 times.
108 if (track->mode == MODE_MOV) {
1399 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1400
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1401
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1402 1 avio_wb16(pb, 8); /* bits per sample */
1403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1404 avio_wb16(pb, track->par->bits_per_coded_sample);
1405 else
1406 35 avio_wb16(pb, 16);
1407
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1408 } else { /* reserved for mp4/3gp */
1409
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
139 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1410 67 0 : track->par->ch_layout.nb_channels);
1411
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
72 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 track->par->codec_id == AV_CODEC_ID_ALAC) {
1413 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1414 } else {
1415 67 avio_wb16(pb, 16);
1416 }
1417 72 avio_wb16(pb, 0);
1418 }
1419
1420 108 avio_wb16(pb, 0); /* packet size (= 0) */
1421
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 103 times.
108 if (track->tag == MKTAG('i','a','m','f'))
1422 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1424 avio_wb16(pb, 48000);
1425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1426 avio_wb32(pb, track->par->sample_rate);
1427 else
1428
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
206 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1429 103 track->par->sample_rate : 0);
1430
1431
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1432 108 avio_wb16(pb, 0); /* Reserved */
1433 }
1434
1435
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 100 times.
112 if (version == 1) { /* SoundDescription V1 extended info */
1436
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) ||
1437 12 mov_pcm_be_gt16(track->par->codec_id))
1438 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1439 else
1440 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1441 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1442 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1443 12 avio_wb32(pb, 2); /* Bytes per sample */
1444 }
1445
1446
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
112 if (track->mode == MODE_MOV &&
1447
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1448
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1449
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1450
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1451
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1452
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1453
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1454
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 ||
1455
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) ||
1456
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1457 15 ret = mov_write_wave_tag(s, pb, track);
1458
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 44 times.
97 else if (track->tag == MKTAG('m','p','4','a'))
1459 53 ret = mov_write_esds_tag(pb, track);
1460 #if CONFIG_IAMFENC
1461
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 39 times.
44 else if (track->tag == MKTAG('i','a','m','f'))
1462 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1463 #endif
1464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1465 ret = mov_write_amr_tag(pb, track);
1466
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1467 4 ret = mov_write_ac3_tag(s, pb, track);
1468
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1469 1 ret = mov_write_eac3_tag(s, pb, track);
1470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1471 ret = mov_write_extradata_tag(pb, track);
1472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1473 ret = mov_write_wfex_tag(s, pb, track);
1474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1475 ret = mov_write_dfla_tag(pb, track);
1476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1477 ret = mov_write_dops_tag(s, pb, track);
1478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1479 ret = mov_write_dmlp_tag(s, pb, track);
1480
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) {
1481
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1482 7 ret = mov_write_chnl_tag(s, pb, track);
1483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1484 return ret;
1485 9 ret = mov_write_pcmc_tag(s, pb, track);
1486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1487 ret = mov_write_glbl_tag(pb, track);
1488
1489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (ret < 0)
1490 return ret;
1491
1492
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
1493
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
69 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1494 return ret;
1495 }
1496
1497
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
1498
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1499 return ret;
1500 }
1501
1502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (mov->encryption_scheme != MOV_ENC_NONE
1503 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1504 return ret;
1505 }
1506
1507
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 &&
1508 69 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1509 return ret;
1510
1511 112 ret = update_size(pb, pos);
1512 112 return ret;
1513 }
1514
1515 static int mov_write_d263_tag(AVIOContext *pb)
1516 {
1517 avio_wb32(pb, 0xf); /* size */
1518 ffio_wfourcc(pb, "d263");
1519 ffio_wfourcc(pb, "FFMP");
1520 avio_w8(pb, 0); /* decoder version */
1521 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1522 avio_w8(pb, 0xa); /* level */
1523 avio_w8(pb, 0); /* profile */
1524 return 0xf;
1525 }
1526
1527 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1528 {
1529 1 int64_t pos = avio_tell(pb);
1530
1531 1 avio_wb32(pb, 0);
1532 1 ffio_wfourcc(pb, "av1C");
1533 1 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1534 1 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1535 1 return update_size(pb, pos);
1536 }
1537
1538 55 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1539 {
1540 55 int64_t pos = avio_tell(pb);
1541
1542 55 avio_wb32(pb, 0);
1543 55 ffio_wfourcc(pb, "avcC");
1544 55 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1545 55 track->extradata_size[track->last_stsd_index]);
1546 55 return update_size(pb, pos);
1547 }
1548
1549 /* AVS3 Intelligent Media Coding
1550 * Information Technology - Intelligent Media Coding
1551 * Part 6: Intelligent Media Format
1552 */
1553 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1554 {
1555 if (len < 4)
1556 return AVERROR_INVALIDDATA;
1557
1558 if (data[0] == 1) {
1559 // In Avs3DecoderConfigurationRecord format
1560 avio_write(pb, data, len);
1561 return 0;
1562 }
1563
1564 avio_w8(pb, 1); // version
1565 avio_wb16(pb, len); // sequence_header_length
1566 avio_write(pb, data, len); // sequence_header
1567 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1568
1569 return 0;
1570 }
1571
1572 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1573 {
1574 int64_t pos = avio_tell(pb);
1575 avio_wb32(pb, 0);
1576 ffio_wfourcc(pb, "av3c");
1577 mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1578 track->extradata_size[track->last_stsd_index]);
1579 return update_size(pb, pos);
1580 }
1581
1582 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1583 {
1584 int64_t pos = avio_tell(pb);
1585
1586 avio_wb32(pb, 0);
1587 ffio_wfourcc(pb, "vpcC");
1588 ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1589 track->extradata_size[track->last_stsd_index], track->par);
1590 return update_size(pb, pos);
1591 }
1592
1593 3 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1594 {
1595 3 int64_t pos = avio_tell(pb);
1596
1597 3 avio_wb32(pb, 0);
1598 3 ffio_wfourcc(pb, "hvcC");
1599
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1600 1 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1601 1 track->extradata_size[track->last_stsd_index], 1, s);
1602 else
1603 2 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1604 2 track->extradata_size[track->last_stsd_index], 0, s);
1605 3 return update_size(pb, pos);
1606 }
1607
1608 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1609 {
1610 1 int64_t pos = avio_tell(pb);
1611 int ret;
1612
1613 1 avio_wb32(pb, 0);
1614 1 ffio_wfourcc(pb, "lhvC");
1615
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1616 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1617 1 track->extradata_size[track->last_stsd_index], 1, s);
1618 else
1619 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1620 track->extradata_size[track->last_stsd_index], 0, s);
1621
1622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1623 avio_seek(pb, pos, SEEK_SET);
1624 return ret;
1625 }
1626
1627 1 return update_size(pb, pos);
1628 }
1629
1630 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1631 {
1632 1 int64_t pos = avio_tell(pb);
1633
1634 1 avio_wb32(pb, 0);
1635 1 ffio_wfourcc(pb, "evcC");
1636
1637
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1638 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1639 1 track->extradata_size[track->last_stsd_index], 1);
1640 else
1641 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1642 track->extradata_size[track->last_stsd_index], 0);
1643
1644 1 return update_size(pb, pos);
1645 }
1646
1647 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1648 {
1649 1 int64_t pos = avio_tell(pb);
1650
1651 1 avio_wb32(pb, 0);
1652 1 ffio_wfourcc(pb, "vvcC");
1653
1654 1 avio_w8 (pb, 0); /* version */
1655 1 avio_wb24(pb, 0); /* flags */
1656
1657
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1658 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1659 1 track->extradata_size[track->last_stsd_index], 1);
1660 else
1661 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1662 track->extradata_size[track->last_stsd_index], 0);
1663 1 return update_size(pb, pos);
1664 }
1665
1666 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1667 {
1668 1 int64_t pos = avio_tell(pb);
1669
1670 1 avio_wb32(pb, 0);
1671 1 ffio_wfourcc(pb, "apvC");
1672
1673 1 avio_w8 (pb, 0); /* version */
1674 1 avio_wb24(pb, 0); /* flags */
1675
1676 1 ff_isom_write_apvc(pb, track->apv, s);
1677
1678 1 return update_size(pb, pos);
1679 }
1680
1681 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1682 /* https://community.avid.com/forums/t/136517.aspx */
1683 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1684 {
1685 int interlaced;
1686 int cid;
1687 23 int display_width = track->par->width;
1688 const uint8_t *extradata;
1689
1690
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) {
1691
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) {
1692 /* looks like a DNxHD bit stream */
1693 23 extradata = track->extradata[track->last_stsd_index];
1694 } else {
1695 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1696 return 0;
1697 }
1698 } else {
1699 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1700 return 0;
1701 }
1702
1703 23 cid = AV_RB32(extradata + 0x28);
1704
1705 23 avio_wb32(pb, 24); /* size */
1706 23 ffio_wfourcc(pb, "ACLR");
1707 23 ffio_wfourcc(pb, "ACLR");
1708 23 ffio_wfourcc(pb, "0001");
1709 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1710 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1712 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1713 23 avio_wb32(pb, 1);
1714 } else {
1715 avio_wb32(pb, 2);
1716 }
1717 23 avio_wb32(pb, 0); /* reserved */
1718
1719
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1720 12 int alp = extradata[0x07] & 1;
1721 12 int pma = (extradata[0x07] >> 2) & 1;
1722 12 int sbd = (extradata[0x21] >> 5) & 3;
1723 12 int ssc = (extradata[0x2C] >> 5) & 3;
1724 12 int clv = (extradata[0x2C] >> 1) & 3;
1725 12 int clf = extradata[0x2C] & 1;
1726
1727 12 avio_wb32(pb, 32);
1728 12 ffio_wfourcc(pb, "ADHR");
1729 12 ffio_wfourcc(pb, "0001");
1730 12 avio_wb32(pb, cid); // Compression ID
1731 // 0: 4:2:2 Sub Sampling
1732 // 1: 4:2:0 Sub Sampling
1733 // 2: 4:4:4 Sub Sampling
1734 12 avio_wb32(pb, ssc); // Sub Sampling Control
1735 // 1: 8-bits per sample
1736 // 2: 10-bits per sample
1737 // 3: 12-bits per sample
1738 12 avio_wb32(pb, sbd); // Sample Bit Depth
1739 // 0: Bitstream is encoded using the YCBCR format rules and tables
1740 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1741 12 avio_wb16(pb, clf); // Color Format
1742 // 0: ITU-R BT.709
1743 // 1: ITU-R BT.2020
1744 // 2: ITU-R BT.2020 C
1745 // 3: Out-of-band
1746 12 avio_wb16(pb, clv); // Color Volume
1747 // 0: Alpha channel not present
1748 // 1: Alpha channel present
1749 12 avio_wb16(pb, alp); // Alpha Present
1750 // 0: Alpha has not been applied to video channels
1751 // 1: Alpha has been applied to the video channels prior to encoding
1752 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1753 12 return 0;
1754 }
1755
1756 11 interlaced = extradata[5] & 2;
1757
1758 11 avio_wb32(pb, 24); /* size */
1759 11 ffio_wfourcc(pb, "APRG");
1760 11 ffio_wfourcc(pb, "APRG");
1761 11 ffio_wfourcc(pb, "0001");
1762 // 1 for progressive or 2 for interlaced
1763
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1764 11 avio_wb32(pb, 2);
1765 else
1766 avio_wb32(pb, 1);
1767 11 avio_wb32(pb, 0); /* reserved */
1768
1769 11 avio_wb32(pb, 120); /* size */
1770 11 ffio_wfourcc(pb, "ARES");
1771 11 ffio_wfourcc(pb, "ARES");
1772 11 ffio_wfourcc(pb, "0001");
1773 11 avio_wb32(pb, cid); /* cid */
1774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1775 && track->par->sample_aspect_ratio.den > 0)
1776 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1777 11 avio_wb32(pb, display_width); // field width
1778
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1779 11 avio_wb32(pb, track->par->height / 2); // field height
1780 11 avio_wb32(pb, 2); // num fields
1781 11 avio_wb32(pb, 0); // num black lines (must be 0)
1782 // 4: HD1080i
1783 // 5: HD1080P
1784 // 6: HD720P
1785 11 avio_wb32(pb, 4); // video format
1786 } else {
1787 avio_wb32(pb, track->par->height);
1788 avio_wb32(pb, 1); // num fields
1789 avio_wb32(pb, 0);
1790 if (track->par->height == 1080)
1791 avio_wb32(pb, 5);
1792 else
1793 avio_wb32(pb, 6);
1794 }
1795 /* padding */
1796 11 ffio_fill(pb, 0, 10 * 8);
1797
1798 11 return 0;
1799 }
1800
1801 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1802 {
1803 avio_wb32(pb, 12);
1804 ffio_wfourcc(pb, "DpxE");
1805 if (track->extradata_size[track->last_stsd_index] >= 12 &&
1806 !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1807 avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1808 } else {
1809 avio_wb32(pb, 1);
1810 }
1811 return 0;
1812 }
1813
1814 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1815 {
1816 int tag;
1817
1818
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1819
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1820
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');
1821 1 else tag = MKTAG('d','v','c',' ');
1822 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1823 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1824 else tag = MKTAG('d','v','p','p');
1825 } else if (track->par->height == 720) { /* HD 720 line */
1826 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1827 else tag = MKTAG('d','v','h','p');
1828 } else if (track->par->height == 1080) { /* HD 1080 line */
1829 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1830 else tag = MKTAG('d','v','h','6');
1831 } else {
1832 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1833 return 0;
1834 }
1835
1836 1 return tag;
1837 }
1838
1839 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1840 {
1841 3 AVRational rational_framerate = st->avg_frame_rate;
1842 3 int rate = 0;
1843
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1844 3 rate = av_q2d(rational_framerate);
1845 3 return rate;
1846 }
1847
1848 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1849 {
1850 1 int tag = track->par->codec_tag;
1851 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1852 1 AVStream *st = track->st;
1853 1 int rate = defined_frame_rate(s, st);
1854
1855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1856 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1857
1858
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1859
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) {
1860 if (!interlaced) {
1861 if (rate == 24) tag = MKTAG('x','d','v','4');
1862 else if (rate == 25) tag = MKTAG('x','d','v','5');
1863 else if (rate == 30) tag = MKTAG('x','d','v','1');
1864 else if (rate == 50) tag = MKTAG('x','d','v','a');
1865 else if (rate == 60) tag = MKTAG('x','d','v','9');
1866 }
1867
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) {
1868 if (!interlaced) {
1869 if (rate == 24) tag = MKTAG('x','d','v','6');
1870 else if (rate == 25) tag = MKTAG('x','d','v','7');
1871 else if (rate == 30) tag = MKTAG('x','d','v','8');
1872 } else {
1873 if (rate == 25) tag = MKTAG('x','d','v','3');
1874 else if (rate == 30) tag = MKTAG('x','d','v','2');
1875 }
1876
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) {
1877 if (!interlaced) {
1878 if (rate == 24) tag = MKTAG('x','d','v','d');
1879 else if (rate == 25) tag = MKTAG('x','d','v','e');
1880 else if (rate == 30) tag = MKTAG('x','d','v','f');
1881 } else {
1882 if (rate == 25) tag = MKTAG('x','d','v','c');
1883 else if (rate == 30) tag = MKTAG('x','d','v','b');
1884 }
1885 }
1886 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1887 if (track->par->width == 1280 && track->par->height == 720) {
1888 if (!interlaced) {
1889 if (rate == 24) tag = MKTAG('x','d','5','4');
1890 else if (rate == 25) tag = MKTAG('x','d','5','5');
1891 else if (rate == 30) tag = MKTAG('x','d','5','1');
1892 else if (rate == 50) tag = MKTAG('x','d','5','a');
1893 else if (rate == 60) tag = MKTAG('x','d','5','9');
1894 }
1895 } else if (track->par->width == 1920 && track->par->height == 1080) {
1896 if (!interlaced) {
1897 if (rate == 24) tag = MKTAG('x','d','5','d');
1898 else if (rate == 25) tag = MKTAG('x','d','5','e');
1899 else if (rate == 30) tag = MKTAG('x','d','5','f');
1900 } else {
1901 if (rate == 25) tag = MKTAG('x','d','5','c');
1902 else if (rate == 30) tag = MKTAG('x','d','5','b');
1903 }
1904 }
1905 }
1906
1907 1 return tag;
1908 }
1909
1910 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1911 {
1912 2 int tag = track->par->codec_tag;
1913 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1914 2 AVStream *st = track->st;
1915 2 int rate = defined_frame_rate(s, st);
1916
1917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1918 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1919
1920
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
1921
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
1922 2 return tag;
1923
1924 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1925 if (track->par->width == 960 && track->par->height == 720) {
1926 if (!interlaced) {
1927 if (rate == 24) tag = MKTAG('a','i','5','p');
1928 else if (rate == 25) tag = MKTAG('a','i','5','q');
1929 else if (rate == 30) tag = MKTAG('a','i','5','p');
1930 else if (rate == 50) tag = MKTAG('a','i','5','q');
1931 else if (rate == 60) tag = MKTAG('a','i','5','p');
1932 }
1933 } else if (track->par->width == 1440 && track->par->height == 1080) {
1934 if (!interlaced) {
1935 if (rate == 24) tag = MKTAG('a','i','5','3');
1936 else if (rate == 25) tag = MKTAG('a','i','5','2');
1937 else if (rate == 30) tag = MKTAG('a','i','5','3');
1938 } else {
1939 if (rate == 50) tag = MKTAG('a','i','5','5');
1940 else if (rate == 60) tag = MKTAG('a','i','5','6');
1941 }
1942 }
1943 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1944 if (track->par->width == 1280 && track->par->height == 720) {
1945 if (!interlaced) {
1946 if (rate == 24) tag = MKTAG('a','i','1','p');
1947 else if (rate == 25) tag = MKTAG('a','i','1','q');
1948 else if (rate == 30) tag = MKTAG('a','i','1','p');
1949 else if (rate == 50) tag = MKTAG('a','i','1','q');
1950 else if (rate == 60) tag = MKTAG('a','i','1','p');
1951 }
1952 } else if (track->par->width == 1920 && track->par->height == 1080) {
1953 if (!interlaced) {
1954 if (rate == 24) tag = MKTAG('a','i','1','3');
1955 else if (rate == 25) tag = MKTAG('a','i','1','2');
1956 else if (rate == 30) tag = MKTAG('a','i','1','3');
1957 } else {
1958 if (rate == 25) tag = MKTAG('a','i','1','5');
1959 else if (rate == 50) tag = MKTAG('a','i','1','5');
1960 else if (rate == 60) tag = MKTAG('a','i','1','6');
1961 }
1962 } else if ( track->par->width == 4096 && track->par->height == 2160
1963 || track->par->width == 3840 && track->par->height == 2160
1964 || track->par->width == 2048 && track->par->height == 1080) {
1965 tag = MKTAG('a','i','v','x');
1966 }
1967 }
1968
1969 return tag;
1970 }
1971
1972 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1973 {
1974 int tag = track->par->codec_tag;
1975
1976 if (!tag)
1977 tag = MKTAG('e', 'v', 'c', '1');
1978
1979 return tag;
1980 }
1981
1982 static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
1983 {
1984 int tag = track->par->codec_tag;
1985
1986 if (!tag)
1987 tag = MKTAG('a', 'p', 'v', '1');
1988
1989 return tag;
1990 }
1991
1992
1993 static const struct {
1994 enum AVPixelFormat pix_fmt;
1995 uint32_t tag;
1996 unsigned bps;
1997 } mov_pix_fmt_tags[] = {
1998 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1999 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2000 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2001 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2002 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2003 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2004 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2005 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2006 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2007 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2008 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2009 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2010 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2011 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2012 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2013 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2014 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2015 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2016 };
2017
2018 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2019 {
2020 23 int tag = MKTAG('A','V','d','n');
2021
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2022
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2023 12 tag = MKTAG('A','V','d','h');
2024 23 return tag;
2025 }
2026
2027 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2028 {
2029 17 int tag = track->par->codec_tag;
2030 int i;
2031 enum AVPixelFormat pix_fmt;
2032
2033
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++) {
2034
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2035 17 tag = mov_pix_fmt_tags[i].tag;
2036 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2037
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2038 5 break;
2039 }
2040 }
2041
2042 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2043 17 track->par->bits_per_coded_sample);
2044
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2046 track->par->format != AV_PIX_FMT_GRAY8 &&
2047 track->par->format != AV_PIX_FMT_NONE)
2048 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2049 av_get_pix_fmt_name(track->par->format));
2050 17 return tag;
2051 }
2052
2053 167 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2054 {
2055 167 unsigned int tag = track->par->codec_tag;
2056
2057 // "rtp " is used to distinguish internally created RTP-hint tracks
2058 // (with rtp_ctx) from other tracks.
2059
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (tag == MKTAG('r','t','p',' '))
2060 tag = 0;
2061
3/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✓ Branch 3 taken 36 times.
167 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
2062
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 1 times.
131 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2063
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 17 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2064
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 track->par->codec_id == AV_CODEC_ID_H263 ||
2065
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2 times.
113 track->par->codec_id == AV_CODEC_ID_H264 ||
2066
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 23 times.
111 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2067
4/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 69 times.
175 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
2068 87 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2069
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2070 1 tag = mov_get_dv_codec_tag(s, track);
2071
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2072 17 tag = mov_get_rawvideo_codec_tag(s, track);
2073
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2074 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2075
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2076 2 tag = mov_get_h264_codec_tag(s, track);
2077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2078 tag = mov_get_evc_codec_tag(s, track);
2079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2080 tag = mov_get_apv_codec_tag(s, track);
2081
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2082 23 tag = mov_get_dnxhd_codec_tag(s, track);
2083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2084 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2085 if (!tag) { // if no mac fcc found, try with Microsoft tags
2086 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2087 if (tag)
2088 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2089 "the file may be unplayable!\n");
2090 }
2091
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2092 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2094 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2095 if (ms_tag) {
2096 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2097 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2098 "the file may be unplayable!\n");
2099 }
2100 }
2101 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2102 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2103 }
2104
2105 167 return tag;
2106 }
2107
2108 static const AVCodecTag codec_cover_image_tags[] = {
2109 { AV_CODEC_ID_MJPEG, 0xD },
2110 { AV_CODEC_ID_PNG, 0xE },
2111 { AV_CODEC_ID_BMP, 0x1B },
2112 { AV_CODEC_ID_NONE, 0 },
2113 };
2114
2115 104 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2116 unsigned int tag, int codec_id)
2117 {
2118 int i;
2119
2120 /**
2121 * Check that tag + id is in the table
2122 */
2123
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++) {
2124 104 const AVCodecTag *codec_tags = tags[i];
2125
1/2
✓ Branch 0 taken 1536 times.
✗ Branch 1 not taken.
1536 while (codec_tags->id != AV_CODEC_ID_NONE) {
2126
2/2
✓ Branch 2 taken 123 times.
✓ Branch 3 taken 1413 times.
1536 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2127
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 19 times.
123 codec_tags->id == codec_id)
2128 104 return codec_tags->tag;
2129 1432 codec_tags++;
2130 }
2131 }
2132 return 0;
2133 }
2134
2135 273 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2136 {
2137
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 271 times.
273 if (is_cover_image(track->st))
2138 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2139
2140
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 270 times.
271 if (track->mode == MODE_IPOD)
2141
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") &&
2142
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2143 1 !av_match_ext(s->url, "m4b"))
2144 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2145 "Quicktime/Ipod might not play the file\n");
2146
2147
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 104 times.
271 if (track->mode == MODE_MOV) {
2148 167 return mov_get_codec_tag(s, track);
2149 } else
2150 104 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2151 104 track->par->codec_id);
2152 }
2153
2154 /** Write uuid atom.
2155 * Needed to make file play in iPods running newest firmware
2156 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2157 */
2158 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2159 {
2160 avio_wb32(pb, 28);
2161 ffio_wfourcc(pb, "uuid");
2162 avio_wb32(pb, 0x6b6840f2);
2163 avio_wb32(pb, 0x5f244fc5);
2164 avio_wb32(pb, 0xba39a51b);
2165 avio_wb32(pb, 0xcf0323f3);
2166 avio_wb32(pb, 0x0);
2167 return 28;
2168 }
2169
2170 static const uint16_t fiel_data[] = {
2171 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2172 };
2173
2174 99 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2175 {
2176 99 unsigned mov_field_order = 0;
2177
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2178 99 mov_field_order = fiel_data[field_order];
2179 else
2180 return 0;
2181 99 avio_wb32(pb, 10);
2182 99 ffio_wfourcc(pb, "fiel");
2183 99 avio_wb16(pb, mov_field_order);
2184 99 return 10;
2185 }
2186
2187 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2188 {
2189 6 MOVMuxContext *mov = s->priv_data;
2190 6 int ret = AVERROR_BUG;
2191 6 int64_t pos = avio_tell(pb);
2192 6 avio_wb32(pb, 0); /* size */
2193 6 avio_wl32(pb, track->tag); // store it byteswapped
2194 6 avio_wb32(pb, 0); /* Reserved */
2195 6 avio_wb16(pb, 0); /* Reserved */
2196 6 avio_wb16(pb, 1); /* Data-reference index */
2197
2198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2199 mov_write_esds_tag(pb, track);
2200
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2201
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2202 2 case MOV_ISMV_TTML_TAG:
2203 // ISMV dfxp requires no extradata.
2204 4 break;
2205 2 case MOV_MP4_TTML_TAG:
2206 // As specified in 14496-30, XMLSubtitleSampleEntry
2207 // Namespace
2208 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2209 // Empty schema_location
2210 2 avio_w8(pb, 0);
2211 // Empty auxiliary_mime_types
2212 2 avio_w8(pb, 0);
2213 2 break;
2214 default:
2215 av_log(NULL, AV_LOG_ERROR,
2216 "Unknown codec tag '%s' utilized for TTML stream with "
2217 "index %d (track id %d)!\n",
2218 av_fourcc2str(track->par->codec_tag), track->st->index,
2219 track->track_id);
2220 return AVERROR(EINVAL);
2221 }
2222
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2223 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2224
2225
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 &&
2226 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2227 return ret;
2228
2229 6 return update_size(pb, pos);
2230 }
2231
2232 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2233 {
2234 int8_t stereo_mode;
2235
2236 if (stereo_3d->flags != 0) {
2237 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2238 return 0;
2239 }
2240
2241 switch (stereo_3d->type) {
2242 case AV_STEREO3D_2D:
2243 stereo_mode = 0;
2244 break;
2245 case AV_STEREO3D_TOPBOTTOM:
2246 stereo_mode = 1;
2247 break;
2248 case AV_STEREO3D_SIDEBYSIDE:
2249 stereo_mode = 2;
2250 break;
2251 default:
2252 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2253 return 0;
2254 }
2255 avio_wb32(pb, 13); /* size */
2256 ffio_wfourcc(pb, "st3d");
2257 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2258 avio_w8(pb, stereo_mode);
2259 return 13;
2260 }
2261
2262 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2263 {
2264 int64_t sv3d_pos, svhd_pos, proj_pos;
2265 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2266
2267 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2268 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2269 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2270 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2271 return 0;
2272 }
2273
2274 sv3d_pos = avio_tell(pb);
2275 avio_wb32(pb, 0); /* size */
2276 ffio_wfourcc(pb, "sv3d");
2277
2278 svhd_pos = avio_tell(pb);
2279 avio_wb32(pb, 0); /* size */
2280 ffio_wfourcc(pb, "svhd");
2281 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2282 avio_put_str(pb, metadata_source);
2283 update_size(pb, svhd_pos);
2284
2285 proj_pos = avio_tell(pb);
2286 avio_wb32(pb, 0); /* size */
2287 ffio_wfourcc(pb, "proj");
2288
2289 avio_wb32(pb, 24); /* size */
2290 ffio_wfourcc(pb, "prhd");
2291 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2292 avio_wb32(pb, spherical_mapping->yaw);
2293 avio_wb32(pb, spherical_mapping->pitch);
2294 avio_wb32(pb, spherical_mapping->roll);
2295
2296 switch (spherical_mapping->projection) {
2297 case AV_SPHERICAL_EQUIRECTANGULAR:
2298 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2299 avio_wb32(pb, 28); /* size */
2300 ffio_wfourcc(pb, "equi");
2301 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2302 avio_wb32(pb, spherical_mapping->bound_top);
2303 avio_wb32(pb, spherical_mapping->bound_bottom);
2304 avio_wb32(pb, spherical_mapping->bound_left);
2305 avio_wb32(pb, spherical_mapping->bound_right);
2306 break;
2307 case AV_SPHERICAL_CUBEMAP:
2308 avio_wb32(pb, 20); /* size */
2309 ffio_wfourcc(pb, "cbmp");
2310 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2311 avio_wb32(pb, 0); /* layout */
2312 avio_wb32(pb, spherical_mapping->padding); /* padding */
2313 break;
2314 }
2315 update_size(pb, proj_pos);
2316
2317 return update_size(pb, sv3d_pos);
2318 }
2319
2320 5 static inline int64_t rescale_rational(AVRational q, int b)
2321 {
2322 5 return av_rescale(q.num, b, q.den);
2323 }
2324
2325 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2326 const AVStereo3D *stereo3d)
2327 {
2328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2329 return;
2330
2331 1 avio_wb32(pb, 12); /* size */
2332 1 ffio_wfourcc(pb, "hfov");
2333 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2334 }
2335
2336 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2337 const AVSphericalMapping *spherical_mapping)
2338 {
2339 1 avio_wb32(pb, 24); /* size */
2340 1 ffio_wfourcc(pb, "proj");
2341 1 avio_wb32(pb, 16); /* size */
2342 1 ffio_wfourcc(pb, "prji");
2343 1 avio_wb32(pb, 0); /* version + flags */
2344
2345
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) {
2346 1 case AV_SPHERICAL_RECTILINEAR:
2347 1 ffio_wfourcc(pb, "rect");
2348 1 break;
2349 case AV_SPHERICAL_EQUIRECTANGULAR:
2350 ffio_wfourcc(pb, "equi");
2351 break;
2352 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2353 ffio_wfourcc(pb, "hequ");
2354 break;
2355 case AV_SPHERICAL_FISHEYE:
2356 ffio_wfourcc(pb, "fish");
2357 break;
2358 default:
2359 av_assert0(0);
2360 }
2361 1 }
2362
2363 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2364 const AVStereo3D *stereo3d)
2365 {
2366 1 int64_t pos = avio_tell(pb);
2367 1 int view = 0;
2368
2369 1 avio_wb32(pb, 0); /* size */
2370 1 ffio_wfourcc(pb, "eyes");
2371
2372 // stri is mandatory
2373 1 avio_wb32(pb, 13); /* size */
2374 1 ffio_wfourcc(pb, "stri");
2375 1 avio_wb32(pb, 0); /* version + flags */
2376
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2377 case AV_STEREO3D_VIEW_LEFT:
2378 view |= 1 << 0;
2379 break;
2380 case AV_STEREO3D_VIEW_RIGHT:
2381 view |= 1 << 1;
2382 break;
2383 1 case AV_STEREO3D_VIEW_PACKED:
2384 1 view |= (1 << 0) | (1 << 1);
2385 1 break;
2386 }
2387 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2388 1 avio_w8(pb, view);
2389
2390 // hero is optional
2391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2392 avio_wb32(pb, 13); /* size */
2393 ffio_wfourcc(pb, "hero");
2394 avio_wb32(pb, 0); /* version + flags */
2395 avio_w8(pb, stereo3d->primary_eye);
2396 }
2397
2398 // it's not clear if cams is mandatory or optional
2399
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2400 1 avio_wb32(pb, 24); /* size */
2401 1 ffio_wfourcc(pb, "cams");
2402 1 avio_wb32(pb, 16); /* size */
2403 1 ffio_wfourcc(pb, "blin");
2404 1 avio_wb32(pb, 0); /* version + flags */
2405 1 avio_wb32(pb, stereo3d->baseline);
2406 }
2407
2408 // it's not clear if cmfy is mandatory or optional
2409
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2410 1 avio_wb32(pb, 24); /* size */
2411 1 ffio_wfourcc(pb, "cmfy");
2412 1 avio_wb32(pb, 16); /* size */
2413 1 ffio_wfourcc(pb, "dadj");
2414 1 avio_wb32(pb, 0); /* version + flags */
2415 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2416 }
2417
2418 1 return update_size(pb, pos);
2419 }
2420
2421 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2422 const AVStereo3D *stereo3d,
2423 const AVSphericalMapping *spherical_mapping)
2424 {
2425 int64_t pos;
2426
2427
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2429 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2430 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2431 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2432 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2433 spherical_mapping->projection);
2434 spherical_mapping = NULL;
2435 }
2436
2437
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 ||
2438
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2440 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2441 !stereo3d->baseline &&
2442 !stereo3d->horizontal_disparity_adjustment.num))) {
2443 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2444 stereo3d = NULL;
2445 }
2446
2447
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2448 return 0;
2449
2450 1 pos = avio_tell(pb);
2451 1 avio_wb32(pb, 0); /* size */
2452 1 ffio_wfourcc(pb, "vexu");
2453
2454
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2455 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2456
2457
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2458 1 mov_write_eyes_tag(s, pb, stereo3d);
2459
2460 1 return update_size(pb, pos);
2461 }
2462
2463 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2464 {
2465 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2466
2467 avio_wb32(pb, 32); /* size = 8 + 24 */
2468 if (dovi->dv_profile > 10)
2469 ffio_wfourcc(pb, "dvwC");
2470 else if (dovi->dv_profile > 7)
2471 ffio_wfourcc(pb, "dvvC");
2472 else
2473 ffio_wfourcc(pb, "dvcC");
2474
2475 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2476 avio_write(pb, buf, sizeof(buf));
2477
2478 return 32; /* 8 + 24 */
2479 }
2480
2481 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2482 uint32_t top, uint32_t bottom,
2483 uint32_t left, uint32_t right)
2484 {
2485 5 uint32_t cropped_width = track->par->width - left - right;
2486 5 uint32_t cropped_height = track->height - top - bottom;
2487 AVRational horizOff =
2488 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2489 5 (AVRational) { left, 1 });
2490 AVRational vertOff =
2491 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2492 5 (AVRational) { top, 1 });
2493
2494 5 avio_wb32(pb, 40);
2495 5 ffio_wfourcc(pb, "clap");
2496 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2497 5 avio_wb32(pb, 1); /* apertureWidthD */
2498 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2499 5 avio_wb32(pb, 1); /* apertureHeightD */
2500
2501 5 avio_wb32(pb, -horizOff.num);
2502 5 avio_wb32(pb, horizOff.den);
2503 5 avio_wb32(pb, -vertOff.num);
2504 5 avio_wb32(pb, vertOff.den);
2505
2506 5 return 40;
2507 }
2508
2509 13 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2510 {
2511 AVRational sar;
2512 13 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2513 13 track->par->sample_aspect_ratio.den, INT_MAX);
2514
2515 13 avio_wb32(pb, 16);
2516 13 ffio_wfourcc(pb, "pasp");
2517 13 avio_wb32(pb, sar.num);
2518 13 avio_wb32(pb, sar.den);
2519 13 return 16;
2520 }
2521
2522 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2523 {
2524 uint32_t gama = 0;
2525 if (gamma <= 0.0)
2526 gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2527 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2528
2529 if (gamma > 1e-6) {
2530 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2531 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2532
2533 av_assert0(track->mode == MODE_MOV);
2534 avio_wb32(pb, 12);
2535 ffio_wfourcc(pb, "gama");
2536 avio_wb32(pb, gama);
2537 return 12;
2538 } else {
2539 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2540 }
2541 return 0;
2542 }
2543
2544 10 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2545 {
2546 10 int64_t pos = avio_tell(pb);
2547
2548 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2549 // Ref (MP4): ISO/IEC 14496-12:2012
2550
2551
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if (prefer_icc) {
2552 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2553 4 track->st->codecpar->nb_coded_side_data,
2554 AV_PKT_DATA_ICC_PROFILE);
2555
2556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2557 avio_wb32(pb, 12 + sd->size);
2558 ffio_wfourcc(pb, "colr");
2559 ffio_wfourcc(pb, "prof");
2560 avio_write(pb, sd->data, sd->size);
2561 return 12 + sd->size;
2562 }
2563 else {
2564 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2565 }
2566 }
2567
2568 /* We should only ever be called for MOV, MP4 and AVIF. */
2569
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 ||
2570 track->mode == MODE_AVIF);
2571
2572 10 avio_wb32(pb, 0); /* size */
2573 10 ffio_wfourcc(pb, "colr");
2574
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)
2575 2 ffio_wfourcc(pb, "nclx");
2576 else
2577 8 ffio_wfourcc(pb, "nclc");
2578 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2579 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2580 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2581 10 avio_wb16(pb, track->par->color_primaries);
2582 10 avio_wb16(pb, track->par->color_trc);
2583 10 avio_wb16(pb, track->par->color_space);
2584
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) {
2585 2 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2586 2 avio_w8(pb, full_range << 7);
2587 }
2588
2589 10 return update_size(pb, pos);
2590 }
2591
2592 208 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2593 {
2594 const AVPacketSideData *side_data;
2595 const AVContentLightMetadata *content_light_metadata;
2596
2597 208 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2598 208 track->st->codecpar->nb_coded_side_data,
2599 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2600
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 if (!side_data) {
2601 208 return 0;
2602 }
2603 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2604
2605 avio_wb32(pb, 12); // size
2606 ffio_wfourcc(pb, "clli");
2607 avio_wb16(pb, content_light_metadata->MaxCLL);
2608 avio_wb16(pb, content_light_metadata->MaxFALL);
2609 return 12;
2610 }
2611
2612 208 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2613 {
2614 208 const int chroma_den = 50000;
2615 208 const int luma_den = 10000;
2616 const AVPacketSideData *side_data;
2617 208 const AVMasteringDisplayMetadata *metadata = NULL;
2618
2619 208 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2620 208 track->st->codecpar->nb_coded_side_data,
2621 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (side_data)
2623 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2624
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
208 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2625 208 return 0;
2626 }
2627
2628 avio_wb32(pb, 32); // size
2629 ffio_wfourcc(pb, "mdcv");
2630 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2631 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2632 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2633 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2634 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2635 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2636 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2637 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2638 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2639 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2640 return 32;
2641 }
2642
2643 208 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2644 {
2645 208 const int illuminance_den = 10000;
2646 208 const int ambient_den = 50000;
2647 const AVPacketSideData *side_data;
2648 const AVAmbientViewingEnvironment *ambient;
2649
2650
2651 208 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2652 208 track->st->codecpar->nb_coded_side_data,
2653 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2654
2655
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 1 times.
208 if (!side_data)
2656 207 return 0;
2657
2658 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2659
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)
2660 return 0;
2661
2662 1 avio_wb32(pb, 16); // size
2663 1 ffio_wfourcc(pb, "amve");
2664 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2665 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2666 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2667 1 return 16;
2668 }
2669
2670 214 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2671 {
2672 AVDictionaryEntry *encoder;
2673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2674
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 213 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
213 || (track->par->width == 1440 && track->par->height == 1080)
2675
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 200 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
428 || (track->par->width == 1920 && track->par->height == 1080);
2676
2677
1/2
✓ Branch 0 taken 214 times.
✗ Branch 1 not taken.
214 if ((track->mode == MODE_AVIF ||
2678
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 140 times.
214 track->mode == MODE_MOV ||
2679
4/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 56 times.
282 track->mode == MODE_MP4) &&
2680 208 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2681 152 av_strlcpy(compressor_name, encoder->value, 32);
2682
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
62 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2683 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2684 AVStream *st = track->st;
2685 int rate = defined_frame_rate(NULL, st);
2686 av_strlcatf(compressor_name, len, "XDCAM");
2687 if (track->par->format == AV_PIX_FMT_YUV422P) {
2688 av_strlcatf(compressor_name, len, " HD422");
2689 } else if(track->par->width == 1440) {
2690 av_strlcatf(compressor_name, len, " HD");
2691 } else
2692 av_strlcatf(compressor_name, len, " EX");
2693
2694 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2695
2696 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2697 }
2698 214 }
2699
2700 static int mov_write_ccst_tag(AVIOContext *pb)
2701 {
2702 int64_t pos = avio_tell(pb);
2703 // Write sane defaults:
2704 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2705 // intra_pred_used = 1 : intra prediction may or may not be used.
2706 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2707 // reference images can be used.
2708 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2709 (1 << 6) | /* intra_pred_used */
2710 (15 << 2); /* max_ref_per_pic */
2711 avio_wb32(pb, 0); /* size */
2712 ffio_wfourcc(pb, "ccst");
2713 avio_wb32(pb, 0); /* Version & flags */
2714 avio_w8(pb, ccstValue);
2715 avio_wb24(pb, 0); /* reserved */
2716 return update_size(pb, pos);
2717 }
2718
2719 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2720 {
2721 int64_t pos = avio_tell(pb);
2722 avio_wb32(pb, 0); /* size */
2723 ffio_wfourcc(pb, aux_type);
2724 avio_wb32(pb, 0); /* Version & flags */
2725 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2726 return update_size(pb, pos);
2727 }
2728
2729 214 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2730 {
2731 214 int ret = AVERROR_BUG;
2732 214 int64_t pos = avio_tell(pb);
2733 const AVPacketSideData *sd;
2734 214 char compressor_name[32] = { 0 };
2735 214 int avid = 0;
2736
2737
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)
2738
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
214 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2739
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
214 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2740
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
214 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2741
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
214 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2742 #if FF_API_V408_CODECID
2743
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 || track->par->codec_id == AV_CODEC_ID_V308
2744
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 || track->par->codec_id == AV_CODEC_ID_V408
2745
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 || track->par->codec_id == AV_CODEC_ID_V410
2746 #endif
2747
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 210 times.
428 || track->par->codec_id == AV_CODEC_ID_V210);
2748
2749 214 avio_wb32(pb, 0); /* size */
2750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->encryption_scheme != MOV_ENC_NONE) {
2751 ffio_wfourcc(pb, "encv");
2752 } else {
2753 214 avio_wl32(pb, track->tag); // store it byteswapped
2754 }
2755 214 avio_wb32(pb, 0); /* Reserved */
2756 214 avio_wb16(pb, 0); /* Reserved */
2757 214 avio_wb16(pb, 1); /* Data-reference index */
2758
2759
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 210 times.
214 if (uncompressed_ycbcr) {
2760 4 avio_wb16(pb, 2); /* Codec stream version */
2761 } else {
2762 210 avio_wb16(pb, 0); /* Codec stream version */
2763 }
2764 214 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2765
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 74 times.
214 if (track->mode == MODE_MOV) {
2766 140 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2767
3/4
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
140 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2768 17 avio_wb32(pb, 0); /* Temporal Quality */
2769 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2770 } else {
2771 123 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2772 123 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2773 }
2774 } else {
2775 74 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2776 }
2777 214 avio_wb16(pb, track->par->width); /* Video width */
2778 214 avio_wb16(pb, track->height); /* Video height */
2779 214 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2780 214 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2781 214 avio_wb32(pb, 0); /* Data size (= 0) */
2782 214 avio_wb16(pb, 1); /* Frame count (= 1) */
2783
2784 214 find_compressor(compressor_name, 32, track);
2785 214 avio_w8(pb, strlen(compressor_name));
2786 214 avio_write(pb, compressor_name, 31);
2787
2788
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 74 times.
214 if (track->mode == MODE_MOV &&
2789
2/4
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 140 times.
140 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2790 avio_wb16(pb, 0x18);
2791
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 107 times.
214 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2792 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2793
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2794 else
2795 181 avio_wb16(pb, 0x18); /* Reserved */
2796
2797
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 135 times.
219 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2798 int pal_size, i;
2799 5 avio_wb16(pb, 0); /* Color table ID */
2800 5 avio_wb32(pb, 0); /* Color table seed */
2801 5 avio_wb16(pb, 0x8000); /* Color table flags */
2802
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)
2803 return AVERROR(EINVAL);
2804 5 pal_size = 1 << track->par->bits_per_coded_sample;
2805 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2806
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2807 1040 uint32_t rgb = track->palette[i];
2808 1040 uint16_t r = (rgb >> 16) & 0xff;
2809 1040 uint16_t g = (rgb >> 8) & 0xff;
2810 1040 uint16_t b = rgb & 0xff;
2811 1040 avio_wb16(pb, 0);
2812 1040 avio_wb16(pb, (r << 8) | r);
2813 1040 avio_wb16(pb, (g << 8) | g);
2814 1040 avio_wb16(pb, (b << 8) | b);
2815 }
2816 } else
2817 209 avio_wb16(pb, 0xffff); /* Reserved */
2818
2819
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 185 times.
214 if (track->tag == MKTAG('m','p','4','v'))
2820 29 mov_write_esds_tag(pb, track);
2821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 else if (track->par->codec_id == AV_CODEC_ID_H263)
2822 mov_write_d263_tag(pb);
2823
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 3 times.
185 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
182 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2825 3 mov_write_extradata_tag(pb, track);
2826 3 avio_wb32(pb, 0);
2827
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 159 times.
182 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2828 23 mov_write_avid_tag(pb, track);
2829 23 avid = 1;
2830
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 156 times.
159 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2831 3 mov_write_hvcc_tag(mov->fc, pb, track);
2832
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2833 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2835 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2836 }
2837
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 155 times.
156 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2838 1 mov_write_vvcc_tag(pb, track);
2839
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)) {
2840 55 mov_write_avcc_tag(pb, track);
2841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (track->mode == MODE_IPOD)
2842 mov_write_uuid_tag_ipod(pb);
2843 }
2844
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2845 1 mov_write_evcc_tag(pb, track);
2846
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 98 times.
99 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2847 1 mov_write_apvc_tag(mov->fc, pb, track);
2848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2849 mov_write_vpcc_tag(mov->fc, pb, track);
2850
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2851 1 mov_write_av1c_tag(pb, track);
2852
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)
2853 mov_write_dvc1_tag(pb, track);
2854
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2855
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2856 /* Don't write any potential extradata here - the cropping
2857 * is signalled via the normal width/height fields. */
2858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2859 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2860 mov_write_dpxe_tag(pb, track);
2861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2862 mov_write_av3c_tag(pb, track);
2863
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
2864 4 mov_write_glbl_tag(pb, track);
2865
2866
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 55 times.
214 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2867
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 25 times.
159 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2868
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23 times.
134 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2869 111 int field_order = track->par->field_order;
2870
2871
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 12 times.
111 if (field_order != AV_FIELD_UNKNOWN)
2872 99 mov_write_fiel_tag(pb, track, field_order);
2873 }
2874
2875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2876 if (track->mode == MODE_MOV)
2877 mov_write_gama_tag(s, pb, track, mov->gamma);
2878 else
2879 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2880 }
2881
5/6
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
422 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2882 422 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2883
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
214 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2884
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2885
5/6
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 198 times.
406 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2886 198 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2887 AV_PKT_DATA_ICC_PROFILE)) {
2888
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;
2889 10 mov_write_colr_tag(pb, track, prefer_icc);
2890 }
2891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2892 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2893 }
2894
2895
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 6 times.
214 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2896 208 mov_write_clli_tag(pb, track);
2897 208 mov_write_mdcv_tag(pb, track);
2898 208 mov_write_amve_tag(pb, track);
2899 }
2900
2901
3/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
214 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2902 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2903 track->st->codecpar->nb_coded_side_data,
2904 AV_PKT_DATA_STEREO3D);
2905 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2906 track->st->codecpar->nb_coded_side_data,
2907 AV_PKT_DATA_SPHERICAL);
2908 if (stereo_3d)
2909 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2910 if (spherical_mapping)
2911 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2912 }
2913
2914
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 6 times.
214 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2916 140 const AVStereo3D *stereo3d = NULL;
2917 140 const AVSphericalMapping *spherical_mapping = NULL;
2918
2919 140 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2920 140 track->st->codecpar->nb_coded_side_data,
2921 AV_PKT_DATA_STEREO3D);
2922
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (sd)
2923 1 stereo3d = (AVStereo3D *)sd->data;
2924
2925 140 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2926 140 track->st->codecpar->nb_coded_side_data,
2927 AV_PKT_DATA_SPHERICAL);
2928
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (sd)
2929 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2930
2931
3/4
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
140 if (stereo3d || spherical_mapping)
2932 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2933
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (stereo3d)
2934 1 mov_write_hfov_tag(s, pb, stereo3d);
2935 }
2936
2937
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 146 times.
214 if (track->mode == MODE_MP4) {
2938 68 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2939 68 track->st->codecpar->nb_coded_side_data,
2940 AV_PKT_DATA_DOVI_CONF);
2941
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) {
2942 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 } else if (dovi) {
2944 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2945 }
2946 }
2947
2948
3/4
✓ Branch 0 taken 214 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 201 times.
214 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2949 13 mov_write_pasp_tag(pb, track);
2950 }
2951
2952 214 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2953 214 track->st->codecpar->nb_coded_side_data,
2954 AV_PKT_DATA_FRAME_CROPPING);
2955
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
215 if (sd && sd->size >= sizeof(uint32_t) * 4) {
2956 1 uint64_t top = AV_RL32(sd->data + 0);
2957 1 uint64_t bottom = AV_RL32(sd->data + 4);
2958 1 uint64_t left = AV_RL32(sd->data + 8);
2959 1 uint64_t right = AV_RL32(sd->data + 12);
2960
2961
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2963 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2964 return AVERROR(EINVAL);
2965 }
2966
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)
2967 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2968
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 209 times.
213 } else if (uncompressed_ycbcr)
2969 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2970
2971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->encryption_scheme != MOV_ENC_NONE) {
2972 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2973 }
2974
2975
3/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
282 if (mov->write_btrt &&
2976 68 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2977 return ret;
2978
2979 /* extra padding for avid stsd */
2980 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2981
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 191 times.
214 if (avid)
2982 23 avio_wb32(pb, 0);
2983
2984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (track->mode == MODE_AVIF) {
2985 mov_write_ccst_tag(pb);
2986 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2987 mov_write_aux_tag(pb, "auxi");
2988 }
2989
2990 214 return update_size(pb, pos);
2991 }
2992
2993 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2994 {
2995 2 int64_t pos = avio_tell(pb);
2996 2 avio_wb32(pb, 0); /* size */
2997 2 ffio_wfourcc(pb, "rtp ");
2998 2 avio_wb32(pb, 0); /* Reserved */
2999 2 avio_wb16(pb, 0); /* Reserved */
3000 2 avio_wb16(pb, 1); /* Data-reference index */
3001
3002 2 avio_wb16(pb, 1); /* Hint track version */
3003 2 avio_wb16(pb, 1); /* Highest compatible version */
3004 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3005
3006 2 avio_wb32(pb, 12); /* size */
3007 2 ffio_wfourcc(pb, "tims");
3008 2 avio_wb32(pb, track->timescale);
3009
3010 2 return update_size(pb, pos);
3011 }
3012
3013 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3014 {
3015 2 uint64_t str_size =strlen(reel_name);
3016 2 int64_t pos = avio_tell(pb);
3017
3018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3019 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3020 avio_wb16(pb, 0);
3021 return AVERROR(EINVAL);
3022 }
3023
3024 2 avio_wb32(pb, 0); /* size */
3025 2 ffio_wfourcc(pb, "name"); /* Data format */
3026 2 avio_wb16(pb, str_size); /* string size */
3027 2 avio_wb16(pb, track->language); /* langcode */
3028 2 avio_write(pb, reel_name, str_size); /* reel name */
3029 2 return update_size(pb,pos);
3030 }
3031
3032 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3033 {
3034 13 int64_t pos = avio_tell(pb);
3035 #if 1
3036 int frame_duration;
3037 int nb_frames;
3038 13 AVDictionaryEntry *t = NULL;
3039
3040
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) {
3041 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3042 return AVERROR(EINVAL);
3043 } else {
3044 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3045
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);
3046 }
3047
3048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3049 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3050 return AVERROR(EINVAL);
3051 }
3052
3053 13 avio_wb32(pb, 0); /* size */
3054 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3055 13 avio_wb32(pb, 0); /* Reserved */
3056 13 avio_wb32(pb, 1); /* Data reference index */
3057 13 avio_wb32(pb, 0); /* Flags */
3058 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3059 13 avio_wb32(pb, track->timescale); /* Timescale */
3060 13 avio_wb32(pb, frame_duration); /* Frame duration */
3061 13 avio_w8(pb, nb_frames); /* Number of frames */
3062 13 avio_w8(pb, 0); /* Reserved */
3063
3064 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3065
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)
3066 2 mov_write_source_reference_tag(pb, track, t->value);
3067 else
3068 11 avio_wb16(pb, 0); /* zero size */
3069 #else
3070
3071 avio_wb32(pb, 0); /* size */
3072 ffio_wfourcc(pb, "tmcd"); /* Data format */
3073 avio_wb32(pb, 0); /* Reserved */
3074 avio_wb32(pb, 1); /* Data reference index */
3075 if (track->par->extradata_size)
3076 avio_write(pb, track->par->extradata, track->par->extradata_size);
3077 #endif
3078 13 return update_size(pb, pos);
3079 }
3080
3081 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3082 {
3083 1 int64_t pos = avio_tell(pb);
3084 1 avio_wb32(pb, 0); /* size */
3085 1 ffio_wfourcc(pb, "gpmd");
3086 1 avio_wb32(pb, 0); /* Reserved */
3087 1 avio_wb16(pb, 0); /* Reserved */
3088 1 avio_wb16(pb, 1); /* Data-reference index */
3089 1 avio_wb32(pb, 0); /* Reserved */
3090 1 return update_size(pb, pos);
3091 }
3092
3093 347 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3094 {
3095 347 int64_t pos = avio_tell(pb);
3096 347 int ret = 0;
3097 347 avio_wb32(pb, 0); /* size */
3098 347 ffio_wfourcc(pb, "stsd");
3099 347 avio_wb32(pb, 0); /* version & flags */
3100 347 avio_wb32(pb, track->stsd_count);
3101
3102 347 int stsd_index_back = track->last_stsd_index;
3103 347 for (track->last_stsd_index = 0;
3104
2/2
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 347 times.
695 track->last_stsd_index < track->stsd_count;
3105 348 track->last_stsd_index++) {
3106
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 134 times.
348 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3107 214 ret = mov_write_video_tag(s, pb, mov, track);
3108
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
134 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3109 112 ret = mov_write_audio_tag(s, pb, mov, track);
3110
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3111 6 ret = mov_write_subtitle_tag(s, pb, track);
3112
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3113 2 ret = mov_write_rtp_tag(pb, track);
3114
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3115 13 ret = mov_write_tmcd_tag(pb, track);
3116
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3117 1 ret = mov_write_gpmd_tag(pb, track);
3118
3119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 348 times.
348 if (ret < 0)
3120 return ret;
3121 }
3122
3123 347 track->last_stsd_index = stsd_index_back;
3124
3125 347 return update_size(pb, pos);
3126 }
3127
3128 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3129 {
3130 9 MOVMuxContext *mov = s->priv_data;
3131 MOVCtts *ctts_entries;
3132 9 uint32_t entries = 0;
3133 uint32_t atom_size;
3134 int i;
3135
3136 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3138 return AVERROR(ENOMEM);
3139 9 ctts_entries[0].count = 1;
3140 9 ctts_entries[0].offset = track->cluster[0].cts;
3141
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3142
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3143 130 ctts_entries[entries].count++; /* compress */
3144 } else {
3145 421 entries++;
3146 421 ctts_entries[entries].offset = track->cluster[i].cts;
3147 421 ctts_entries[entries].count = 1;
3148 }
3149 }
3150 9 entries++; /* last one */
3151 9 atom_size = 16 + (entries * 8);
3152 9 avio_wb32(pb, atom_size); /* size */
3153 9 ffio_wfourcc(pb, "ctts");
3154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3155 avio_w8(pb, 1); /* version */
3156 else
3157 9 avio_w8(pb, 0); /* version */
3158 9 avio_wb24(pb, 0); /* flags */
3159 9 avio_wb32(pb, entries); /* entry count */
3160
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3161 430 avio_wb32(pb, ctts_entries[i].count);
3162 430 avio_wb32(pb, ctts_entries[i].offset);
3163 }
3164 9 av_free(ctts_entries);
3165 9 return atom_size;
3166 }
3167
3168 /* Time to sample atom */
3169 347 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3170 {
3171 347 MOVStts *stts_entries = NULL;
3172 347 uint32_t entries = -1;
3173 uint32_t atom_size;
3174 int i;
3175
3176
4/4
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 77 times.
347 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3177 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3179 return AVERROR(ENOMEM);
3180 35 stts_entries[0].count = track->sample_count;
3181 35 stts_entries[0].duration = 1;
3182 35 entries = 1;
3183 } else {
3184
2/2
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 97 times.
312 if (track->entry) {
3185 215 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 215 times.
215 if (!stts_entries)
3187 return AVERROR(ENOMEM);
3188 }
3189
2/2
✓ Branch 0 taken 12216 times.
✓ Branch 1 taken 312 times.
12528 for (i = 0; i < track->entry; i++) {
3190 12216 int duration = get_cluster_duration(track, i);
3191 #if CONFIG_IAMFENC
3192
3/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 12166 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
12216 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3193 duration = av_rescale(duration, 48000, track->par->sample_rate);
3194 #endif
3195
4/4
✓ Branch 0 taken 12001 times.
✓ Branch 1 taken 215 times.
✓ Branch 2 taken 11598 times.
✓ Branch 3 taken 403 times.
12216 if (i && duration == stts_entries[entries].duration) {
3196 11598 stts_entries[entries].count++; /* compress */
3197 } else {
3198 618 entries++;
3199 618 stts_entries[entries].duration = duration;
3200 618 stts_entries[entries].count = 1;
3201 }
3202 }
3203 312 entries++; /* last one */
3204 }
3205 347 atom_size = 16 + (entries * 8);
3206 347 avio_wb32(pb, atom_size); /* size */
3207 347 ffio_wfourcc(pb, "stts");
3208 347 avio_wb32(pb, 0); /* version & flags */
3209 347 avio_wb32(pb, entries); /* entry count */
3210
2/2
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 347 times.
1000 for (i = 0; i < entries; i++) {
3211 653 avio_wb32(pb, stts_entries[i].count);
3212 653 avio_wb32(pb, stts_entries[i].duration);
3213 }
3214 347 av_free(stts_entries);
3215 347 return atom_size;
3216 }
3217
3218 347 static int mov_write_dref_tag(AVIOContext *pb)
3219 {
3220 347 avio_wb32(pb, 28); /* size */
3221 347 ffio_wfourcc(pb, "dref");
3222 347 avio_wb32(pb, 0); /* version & flags */
3223 347 avio_wb32(pb, 1); /* entry count */
3224
3225 347 avio_wb32(pb, 0xc); /* size */
3226 //FIXME add the alis and rsrc atom
3227 347 ffio_wfourcc(pb, "url ");
3228 347 avio_wb32(pb, 1); /* version & flags */
3229
3230 347 return 28;
3231 }
3232
3233 55 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3234 {
3235 struct sgpd_entry {
3236 int count;
3237 int16_t roll_distance;
3238 int group_description_index;
3239 };
3240
3241 55 struct sgpd_entry *sgpd_entries = NULL;
3242 55 int entries = -1;
3243 55 int group = 0;
3244 int i, j;
3245
3246 55 const int OPUS_SEEK_PREROLL_MS = 80;
3247 55 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3248 55 (AVRational){1, 1000},
3249 55 (AVRational){1, 48000});
3250
3251
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 12 times.
55 if (!track->entry)
3252 43 return 0;
3253
3254 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3256 return AVERROR(ENOMEM);
3257
3258
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);
3259
3260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3261 for (i = 0; i < track->entry; i++) {
3262 int roll_samples_remaining = roll_samples;
3263 int distance = 0;
3264 for (j = i - 1; j >= 0; j--) {
3265 roll_samples_remaining -= get_cluster_duration(track, j);
3266 distance++;
3267 if (roll_samples_remaining <= 0)
3268 break;
3269 }
3270 /* We don't have enough preceding samples to compute a valid
3271 roll_distance here, so this sample can't be independently
3272 decoded. */
3273 if (roll_samples_remaining > 0)
3274 distance = 0;
3275 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3276 if (distance > 32)
3277 return AVERROR_INVALIDDATA;
3278 if (i && distance == sgpd_entries[entries].roll_distance) {
3279 sgpd_entries[entries].count++;
3280 } else {
3281 entries++;
3282 sgpd_entries[entries].count = 1;
3283 sgpd_entries[entries].roll_distance = distance;
3284 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3285 }
3286 }
3287 } else {
3288 12 entries++;
3289 12 sgpd_entries[entries].count = track->sample_count;
3290 12 sgpd_entries[entries].roll_distance = 1;
3291 12 sgpd_entries[entries].group_description_index = ++group;
3292 }
3293 12 entries++;
3294
3295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3296 av_free(sgpd_entries);
3297 return 0;
3298 }
3299
3300 /* Write sgpd tag */
3301 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3302 12 ffio_wfourcc(pb, "sgpd");
3303 12 avio_wb32(pb, 1 << 24); /* fullbox */
3304 12 ffio_wfourcc(pb, "roll");
3305 12 avio_wb32(pb, 2); /* default_length */
3306 12 avio_wb32(pb, group); /* entry_count */
3307
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3308
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3309 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3310 }
3311 }
3312
3313 /* Write sbgp tag */
3314 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3315 12 ffio_wfourcc(pb, "sbgp");
3316 12 avio_wb32(pb, 0); /* fullbox */
3317 12 ffio_wfourcc(pb, "roll");
3318 12 avio_wb32(pb, entries); /* entry_count */
3319
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3320 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3321 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3322 }
3323
3324 12 av_free(sgpd_entries);
3325 12 return 0;
3326 }
3327
3328 347 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3329 {
3330 347 int64_t pos = avio_tell(pb);
3331 347 int ret = 0;
3332
3333 347 avio_wb32(pb, 0); /* size */
3334 347 ffio_wfourcc(pb, "stbl");
3335
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 347 times.
347 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3336 return ret;
3337 347 mov_write_stts_tag(pb, track);
3338
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 213 times.
347 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3339
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3340
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3341
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) ||
3342
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 132 times.
134 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3343
4/4
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 104 times.
215 track->has_keyframes && track->has_keyframes < track->entry)
3344 59 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3345
5/6
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 210 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
347 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3346 3 mov_write_sdtp_tag(pb, track);
3347
3/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 189 times.
347 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3348 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3349
2/2
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 134 times.
347 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3350
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 22 times.
213 track->flags & MOV_TRACK_CTTS && track->entry) {
3351
3352
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3353 return ret;
3354 }
3355 347 mov_write_stsc_tag(pb, track);
3356 347 mov_write_stsz_tag(pb, track);
3357 347 mov_write_stco_tag(pb, track);
3358
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 347 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
347 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3359 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3360 }
3361
3/4
✓ Branch 0 taken 347 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 292 times.
347 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3362 55 mov_preroll_write_stbl_atoms(pb, track);
3363 }
3364 347 return update_size(pb, pos);
3365 }
3366
3367 347 static int mov_write_dinf_tag(AVIOContext *pb)
3368 {
3369 347 int64_t pos = avio_tell(pb);
3370 347 avio_wb32(pb, 0); /* size */
3371 347 ffio_wfourcc(pb, "dinf");
3372 347 mov_write_dref_tag(pb);
3373 347 return update_size(pb, pos);
3374 }
3375
3376 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3377 {
3378 7 avio_wb32(pb, 12);
3379 7 ffio_wfourcc(pb, "nmhd");
3380 7 avio_wb32(pb, 0);
3381 7 return 12;
3382 }
3383
3384 2 static int mov_write_sthd_tag(AVIOContext *pb)
3385 {
3386 2 avio_wb32(pb, 12);
3387 2 ffio_wfourcc(pb, "sthd");
3388 2 avio_wb32(pb, 0);
3389 2 return 12;
3390 }
3391
3392 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3393 {
3394 9 int64_t pos = avio_tell(pb);
3395 9 const char *font = "Lucida Grande";
3396 9 avio_wb32(pb, 0); /* size */
3397 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3398 9 avio_wb32(pb, 0); /* version & flags */
3399 9 avio_wb16(pb, 0); /* text font */
3400 9 avio_wb16(pb, 0); /* text face */
3401 9 avio_wb16(pb, 12); /* text size */
3402 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3403 9 avio_wb16(pb, 0x0000); /* text color (red) */
3404 9 avio_wb16(pb, 0x0000); /* text color (green) */
3405 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3406 9 avio_wb16(pb, 0xffff); /* background color (red) */
3407 9 avio_wb16(pb, 0xffff); /* background color (green) */
3408 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3409 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3410 9 avio_write(pb, font, strlen(font)); /* font name */
3411 9 return update_size(pb, pos);
3412 }
3413
3414 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3415 {
3416 11 int64_t pos = avio_tell(pb);
3417 11 avio_wb32(pb, 0); /* size */
3418 11 ffio_wfourcc(pb, "gmhd");
3419 11 avio_wb32(pb, 0x18); /* gmin size */
3420 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3421 11 avio_wb32(pb, 0); /* version & flags */
3422 11 avio_wb16(pb, 0x40); /* graphics mode = */
3423 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3424 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3425 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3426 11 avio_wb16(pb, 0); /* balance */
3427 11 avio_wb16(pb, 0); /* reserved */
3428
3429 /*
3430 * This special text atom is required for
3431 * Apple Quicktime chapters. The contents
3432 * don't appear to be documented, so the
3433 * bytes are copied verbatim.
3434 */
3435
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3436 11 avio_wb32(pb, 0x2C); /* size */
3437 11 ffio_wfourcc(pb, "text");
3438 11 avio_wb16(pb, 0x01);
3439 11 avio_wb32(pb, 0x00);
3440 11 avio_wb32(pb, 0x00);
3441 11 avio_wb32(pb, 0x00);
3442 11 avio_wb32(pb, 0x01);
3443 11 avio_wb32(pb, 0x00);
3444 11 avio_wb32(pb, 0x00);
3445 11 avio_wb32(pb, 0x00);
3446 11 avio_wb32(pb, 0x00004000);
3447 11 avio_wb16(pb, 0x0000);
3448 }
3449
3450
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3451 9 int64_t tmcd_pos = avio_tell(pb);
3452 9 avio_wb32(pb, 0); /* size */
3453 9 ffio_wfourcc(pb, "tmcd");
3454 9 mov_write_tcmi_tag(pb, track);
3455 9 update_size(pb, tmcd_pos);
3456
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3457 1 int64_t gpmd_pos = avio_tell(pb);
3458 1 avio_wb32(pb, 0); /* size */
3459 1 ffio_wfourcc(pb, "gpmd");
3460 1 avio_wb32(pb, 0); /* version */
3461 1 update_size(pb, gpmd_pos);
3462 }
3463 11 return update_size(pb, pos);
3464 }
3465
3466 112 static int mov_write_smhd_tag(AVIOContext *pb)
3467 {
3468 112 avio_wb32(pb, 16); /* size */
3469 112 ffio_wfourcc(pb, "smhd");
3470 112 avio_wb32(pb, 0); /* version & flags */
3471 112 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3472 112 avio_wb16(pb, 0); /* reserved */
3473 112 return 16;
3474 }
3475
3476 213 static int mov_write_vmhd_tag(AVIOContext *pb)
3477 {
3478 213 avio_wb32(pb, 0x14); /* size (always 0x14) */
3479 213 ffio_wfourcc(pb, "vmhd");
3480 213 avio_wb32(pb, 0x01); /* version & flags */
3481 213 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3482 213 return 0x14;
3483 }
3484
3485 226 static int is_clcp_track(MOVTrack *track)
3486 {
3487
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
452 return track->tag == MKTAG('c','7','0','8') ||
3488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 226 times.
226 track->tag == MKTAG('c','6','0','8');
3489 }
3490
3491 536 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3492 {
3493 536 MOVMuxContext *mov = s->priv_data;
3494 536 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3495 536 int64_t pos = avio_tell(pb);
3496 size_t descr_len;
3497
3498 536 hdlr = "dhlr";
3499 536 hdlr_type = "url ";
3500 536 descr = "DataHandler";
3501
3502
2/2
✓ Branch 0 taken 347 times.
✓ Branch 1 taken 189 times.
536 if (track) {
3503
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 158 times.
347 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3504
2/2
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 134 times.
347 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 213 times.
213 if (track->mode == MODE_AVIF) {
3506 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3507 descr = "PictureHandler";
3508 } else {
3509 213 hdlr_type = "vide";
3510 213 descr = "VideoHandler";
3511 }
3512
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
134 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3513 112 hdlr_type = "soun";
3514 112 descr = "SoundHandler";
3515
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3516
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3517 hdlr_type = "clcp";
3518 descr = "ClosedCaptionHandler";
3519 } else {
3520
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3521 1 hdlr_type = "sbtl";
3522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3523 hdlr_type = "subp";
3524
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3525 2 hdlr_type = "subt";
3526 } else {
3527 3 hdlr_type = "text";
3528 }
3529 6 descr = "SubtitleHandler";
3530 }
3531
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3532 2 hdlr_type = "hint";
3533 2 descr = "HintHandler";
3534
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3535 13 hdlr_type = "tmcd";
3536 13 descr = "TimeCodeHandler";
3537
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3538 1 hdlr_type = "meta";
3539 1 descr = "GoPro MET"; // GoPro Metadata
3540 } else {
3541 av_log(s, AV_LOG_WARNING,
3542 "Unknown hdlr_type for %s, writing dummy values\n",
3543 av_fourcc2str(track->par->codec_tag));
3544 }
3545
2/2
✓ Branch 0 taken 344 times.
✓ Branch 1 taken 3 times.
347 if (track->st) {
3546 // hdlr.name is used by some players to identify the content title
3547 // of the track. So if an alternate handler description is
3548 // specified, use it.
3549 AVDictionaryEntry *t;
3550 344 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3551
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 318 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
344 if (t && utf8len(t->value))
3552 26 descr = t->value;
3553 }
3554 }
3555
3556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 536 times.
536 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3557 descr = "";
3558
3559 536 avio_wb32(pb, 0); /* size */
3560 536 ffio_wfourcc(pb, "hdlr");
3561 536 avio_wb32(pb, 0); /* Version & flags */
3562 536 avio_write(pb, hdlr, 4); /* handler */
3563 536 ffio_wfourcc(pb, hdlr_type); /* handler type */
3564 536 avio_wb32(pb, 0); /* reserved */
3565 536 avio_wb32(pb, 0); /* reserved */
3566 536 avio_wb32(pb, 0); /* reserved */
3567 536 descr_len = strlen(descr);
3568
4/4
✓ Branch 0 taken 347 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 158 times.
536 if (!track || track->mode == MODE_MOV)
3569 378 avio_w8(pb, descr_len); /* pascal string */
3570 536 avio_write(pb, descr, descr_len); /* handler description */
3571
4/4
✓ Branch 0 taken 347 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 158 times.
✓ Branch 3 taken 189 times.
536 if (track && track->mode != MODE_MOV)
3572 158 avio_w8(pb, 0); /* c string */
3573 536 return update_size(pb, pos);
3574 }
3575
3576 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3577 {
3578 int64_t pos = avio_tell(pb);
3579 avio_wb32(pb, 0); /* size */
3580 ffio_wfourcc(pb, "pitm");
3581 avio_wb32(pb, 0); /* Version & flags */
3582 avio_wb16(pb, item_id); /* item_id */
3583 return update_size(pb, pos);
3584 }
3585
3586 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3587 {
3588 int64_t pos = avio_tell(pb);
3589 avio_wb32(pb, 0); /* size */
3590 ffio_wfourcc(pb, "iloc");
3591 avio_wb32(pb, 0); /* Version & flags */
3592 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3593 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3594 avio_wb16(pb, mov->nb_streams); /* item_count */
3595
3596 for (int i = 0; i < mov->nb_streams; i++) {
3597 avio_wb16(pb, i + 1); /* item_id */
3598 avio_wb16(pb, 0); /* data_reference_index */
3599 avio_wb16(pb, 1); /* extent_count */
3600 mov->avif_extent_pos[i] = avio_tell(pb);
3601 avio_wb32(pb, 0); /* extent_offset (written later) */
3602 // For animated AVIF, we simply write the first packet's size.
3603 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3604 }
3605
3606 return update_size(pb, pos);
3607 }
3608
3609 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3610 {
3611 int64_t iinf_pos = avio_tell(pb);
3612 avio_wb32(pb, 0); /* size */
3613 ffio_wfourcc(pb, "iinf");
3614 avio_wb32(pb, 0); /* Version & flags */
3615 avio_wb16(pb, mov->nb_streams); /* entry_count */
3616
3617 for (int i = 0; i < mov->nb_streams; i++) {
3618 int64_t infe_pos = avio_tell(pb);
3619 avio_wb32(pb, 0); /* size */
3620 ffio_wfourcc(pb, "infe");
3621 avio_w8(pb, 0x2); /* Version */
3622 avio_wb24(pb, 0); /* flags */
3623 avio_wb16(pb, i + 1); /* item_id */
3624 avio_wb16(pb, 0); /* item_protection_index */
3625 avio_write(pb, "av01", 4); /* item_type */
3626 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3627 update_size(pb, infe_pos);
3628 }
3629
3630 return update_size(pb, iinf_pos);
3631 }
3632
3633
3634 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3635 {
3636 int64_t auxl_pos;
3637 int64_t iref_pos = avio_tell(pb);
3638 avio_wb32(pb, 0); /* size */
3639 ffio_wfourcc(pb, "iref");
3640 avio_wb32(pb, 0); /* Version & flags */
3641
3642 auxl_pos = avio_tell(pb);
3643 avio_wb32(pb, 0); /* size */
3644 ffio_wfourcc(pb, "auxl");
3645 avio_wb16(pb, 2); /* from_item_ID */
3646 avio_wb16(pb, 1); /* reference_count */
3647 avio_wb16(pb, 1); /* to_item_ID */
3648 update_size(pb, auxl_pos);
3649
3650 return update_size(pb, iref_pos);
3651 }
3652
3653 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3654 int stream_index)
3655 {
3656 int64_t pos = avio_tell(pb);
3657 avio_wb32(pb, 0); /* size */
3658 ffio_wfourcc(pb, "ispe");
3659 avio_wb32(pb, 0); /* Version & flags */
3660 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3661 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3662 return update_size(pb, pos);
3663 }
3664
3665 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3666 int stream_index)
3667 {
3668 int64_t pos = avio_tell(pb);
3669 const AVPixFmtDescriptor *pixdesc =
3670 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3671 avio_wb32(pb, 0); /* size */
3672 ffio_wfourcc(pb, "pixi");
3673 avio_wb32(pb, 0); /* Version & flags */
3674 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3675 for (int i = 0; i < pixdesc->nb_components; ++i) {
3676 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3677 }
3678 return update_size(pb, pos);
3679 }
3680
3681 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3682 {
3683 int64_t pos = avio_tell(pb);
3684 avio_wb32(pb, 0); /* size */
3685 ffio_wfourcc(pb, "ipco");
3686 for (int i = 0; i < mov->nb_streams; i++) {
3687 mov_write_ispe_tag(pb, mov, s, i);
3688 mov_write_pixi_tag(pb, mov, s, i);
3689 mov_write_av1c_tag(pb, &mov->tracks[i]);
3690 if (!i)
3691 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3692 else
3693 mov_write_aux_tag(pb, "auxC");
3694 }
3695 return update_size(pb, pos);
3696 }
3697
3698 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3699 {
3700 int64_t pos = avio_tell(pb);
3701 avio_wb32(pb, 0); /* size */
3702 ffio_wfourcc(pb, "ipma");
3703 avio_wb32(pb, 0); /* Version & flags */
3704 avio_wb32(pb, mov->nb_streams); /* entry_count */
3705
3706 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3707 avio_wb16(pb, i + 1); /* item_ID */
3708 avio_w8(pb, 4); /* association_count */
3709
3710 // ispe association.
3711 avio_w8(pb, index++); /* essential and property_index */
3712 // pixi association.
3713 avio_w8(pb, index++); /* essential and property_index */
3714 // av1C association.
3715 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3716 // colr/auxC association.
3717 avio_w8(pb, index++); /* essential and property_index */
3718 }
3719 return update_size(pb, pos);
3720 }
3721
3722 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3723 {
3724 int64_t pos = avio_tell(pb);
3725 avio_wb32(pb, 0); /* size */
3726 ffio_wfourcc(pb, "iprp");
3727 mov_write_ipco_tag(pb, mov, s);
3728 mov_write_ipma_tag(pb, mov, s);
3729 return update_size(pb, pos);
3730 }
3731
3732 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3733 {
3734 /* This atom must be present, but leaving the values at zero
3735 * seems harmless. */
3736 2 avio_wb32(pb, 28); /* size */
3737 2 ffio_wfourcc(pb, "hmhd");
3738 2 avio_wb32(pb, 0); /* version, flags */
3739 2 avio_wb16(pb, 0); /* maxPDUsize */
3740 2 avio_wb16(pb, 0); /* avgPDUsize */
3741 2 avio_wb32(pb, 0); /* maxbitrate */
3742 2 avio_wb32(pb, 0); /* avgbitrate */
3743 2 avio_wb32(pb, 0); /* reserved */
3744 2 return 28;
3745 }
3746
3747 347 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3748 {
3749 347 int64_t pos = avio_tell(pb);
3750 int ret;
3751
3752 347 avio_wb32(pb, 0); /* size */
3753 347 ffio_wfourcc(pb, "minf");
3754
2/2
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 134 times.
347 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3755 213 mov_write_vmhd_tag(pb);
3756
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 22 times.
134 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3757 112 mov_write_smhd_tag(pb);
3758
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3759
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)) {
3760 1 mov_write_gmhd_tag(pb, track);
3761
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3762 2 mov_write_sthd_tag(pb);
3763 } else {
3764 3 mov_write_nmhd_tag(pb);
3765 }
3766
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3767 2 mov_write_hmhd_tag(pb);
3768
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3769
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3770 4 mov_write_nmhd_tag(pb);
3771 else
3772 9 mov_write_gmhd_tag(pb, track);
3773
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3774 1 mov_write_gmhd_tag(pb, track);
3775 }
3776
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 158 times.
347 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3777 189 mov_write_hdlr_tag(s, pb, NULL);
3778 347 mov_write_dinf_tag(pb);
3779
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 347 times.
347 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3780 return ret;
3781 347 return update_size(pb, pos);
3782 }
3783
3784 1336 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3785 int64_t *start, int64_t *end)
3786 {
3787
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1286 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1336 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3788 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3789 // another track's duration, while the end_pts may be left at zero.
3790 // Calculate the pts duration for that track instead.
3791 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3792 38 *start = av_rescale(*start, track->timescale,
3793 38 mov->tracks[track->src_track].timescale);
3794 38 *end = av_rescale(*end, track->timescale,
3795 38 mov->tracks[track->src_track].timescale);
3796 38 return;
3797 }
3798
2/2
✓ Branch 0 taken 1228 times.
✓ Branch 1 taken 70 times.
1298 if (track->end_pts != AV_NOPTS_VALUE &&
3799
1/2
✓ Branch 0 taken 1228 times.
✗ Branch 1 not taken.
1228 track->start_dts != AV_NOPTS_VALUE &&
3800
1/2
✓ Branch 0 taken 1228 times.
✗ Branch 1 not taken.
1228 track->start_cts != AV_NOPTS_VALUE) {
3801 1228 *start = track->start_dts + track->start_cts;
3802 1228 *end = track->end_pts;
3803 1228 return;
3804 }
3805 70 *start = 0;
3806 70 *end = track->track_duration;
3807 }
3808
3809 636 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3810 {
3811 int64_t start, end;
3812 636 get_pts_range(mov, track, &start, &end);
3813 636 return end - start;
3814 }
3815
3816 // Calculate the actual duration of the track, after edits.
3817 // If it starts with a pts < 0, that is removed by the edit list.
3818 // If it starts with a pts > 0, the edit list adds a delay before that.
3819 // Thus, with edit lists enabled, the post-edit output of the file is
3820 // starting with pts=0.
3821 662 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3822 {
3823 int64_t start, end;
3824 662 get_pts_range(mov, track, &start, &end);
3825
2/2
✓ Branch 0 taken 584 times.
✓ Branch 1 taken 78 times.
662 if (mov->use_editlist != 0)
3826 584 start = 0;
3827 662 return end - start;
3828 }
3829
3830 940 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3831 {
3832
4/4
✓ Branch 0 taken 694 times.
✓ Branch 1 taken 246 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 676 times.
940 if (track && track->mode == MODE_ISM)
3833 18 return 1;
3834
2/2
✓ Branch 0 taken 918 times.
✓ Branch 1 taken 4 times.
922 if (duration < INT32_MAX)
3835 918 return 0;
3836 4 return 1;
3837 }
3838
3839 347 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3840 MOVTrack *track)
3841 {
3842 347 int64_t duration = calc_samples_pts_duration(mov, track);
3843 347 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3844
3845
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 334 times.
347 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3846 347 ffio_wfourcc(pb, "mdhd");
3847 347 avio_w8(pb, version);
3848 347 avio_wb24(pb, 0); /* flags */
3849
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 334 times.
347 if (version == 1) {
3850 13 avio_wb64(pb, track->time);
3851 13 avio_wb64(pb, track->time);
3852 } else {
3853 334 avio_wb32(pb, track->time); /* creation time */
3854 334 avio_wb32(pb, track->time); /* modification time */
3855 }
3856 347 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3857
4/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 89 times.
347 if (!track->entry && mov->mode == MODE_ISM)
3858
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3859
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 249 times.
338 else if (!track->entry)
3860
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 85 times.
89 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3861 else
3862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3863 347 avio_wb16(pb, track->language); /* language */
3864 347 avio_wb16(pb, 0); /* reserved (quality) */
3865
3866
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 334 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
347 if (version != 0 && track->mode == MODE_MOV) {
3867 av_log(NULL, AV_LOG_ERROR,
3868 "FATAL error, file duration too long for timebase, this file will not be\n"
3869 "playable with QuickTime. Choose a different timebase with "
3870 "-video_track_timescale or a different container format\n");
3871 }
3872
3873 347 return 32;
3874 }
3875
3876 347 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3877 MOVMuxContext *mov, MOVTrack *track)
3878 {
3879 347 int64_t pos = avio_tell(pb);
3880 int ret;
3881
3882 347 avio_wb32(pb, 0); /* size */
3883 347 ffio_wfourcc(pb, "mdia");
3884 347 mov_write_mdhd_tag(pb, mov, track);
3885 347 mov_write_hdlr_tag(s, pb, track);
3886
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 347 times.
347 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3887 return ret;
3888 347 return update_size(pb, pos);
3889 }
3890
3891 /* transformation matrix
3892 |a b u|
3893 |c d v|
3894 |tx ty w| */
3895 592 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3896 int16_t d, int16_t tx, int16_t ty)
3897 {
3898 592 avio_wb32(pb, a << 16); /* 16.16 format */
3899 592 avio_wb32(pb, b << 16); /* 16.16 format */
3900 592 avio_wb32(pb, 0); /* u in 2.30 format */
3901 592 avio_wb32(pb, c << 16); /* 16.16 format */
3902 592 avio_wb32(pb, d << 16); /* 16.16 format */
3903 592 avio_wb32(pb, 0); /* v in 2.30 format */
3904 592 avio_wb32(pb, tx << 16); /* 16.16 format */
3905 592 avio_wb32(pb, ty << 16); /* 16.16 format */
3906 592 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3907 592 }
3908
3909 347 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3910 MOVTrack *track, AVStream *st)
3911 {
3912 694 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3913 347 mov->movie_timescale, track->timescale,
3914 AV_ROUND_UP);
3915 int version;
3916 347 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3917 347 int group = 0;
3918
3919 347 uint32_t *display_matrix = NULL;
3920 int i;
3921
3922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 347 times.
347 if (mov->mode == MODE_AVIF)
3923 if (!mov->avif_loop_count)
3924 duration = INT64_MAX;
3925 else
3926 duration *= mov->avif_loop_count;
3927
3928
2/2
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 13 times.
347 if (st) {
3929 const AVPacketSideData *sd;
3930
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 332 times.
334 if (mov->per_stream_grouping)
3931 2 group = st->index;
3932 else
3933 332 group = st->codecpar->codec_type;
3934
3935 334 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3936 334 st->codecpar->nb_coded_side_data,
3937 AV_PKT_DATA_DISPLAYMATRIX);
3938
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 333 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
334 if (sd && sd->size == 9 * sizeof(*display_matrix))
3939 1 display_matrix = (uint32_t *)sd->data;
3940 }
3941
3942
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 25 times.
347 if (track->flags & MOV_TRACK_ENABLED)
3943 322 flags |= MOV_TKHD_FLAG_ENABLED;
3944
3945 347 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3946
3947
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 338 times.
347 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3948 347 ffio_wfourcc(pb, "tkhd");
3949 347 avio_w8(pb, version);
3950 347 avio_wb24(pb, flags);
3951
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 338 times.
347 if (version == 1) {
3952 9 avio_wb64(pb, track->time);
3953 9 avio_wb64(pb, track->time);
3954 } else {
3955 338 avio_wb32(pb, track->time); /* creation time */
3956 338 avio_wb32(pb, track->time); /* modification time */
3957 }
3958 347 avio_wb32(pb, track->track_id); /* track-id */
3959 347 avio_wb32(pb, 0); /* reserved */
3960
4/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 89 times.
347 if (!track->entry && mov->mode == MODE_ISM)
3961
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3962
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 249 times.
338 else if (!track->entry)
3963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3964 else
3965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3966
3967 347 avio_wb32(pb, 0); /* reserved */
3968 347 avio_wb32(pb, 0); /* reserved */
3969 347 avio_wb16(pb, 0); /* layer */
3970 347 avio_wb16(pb, group); /* alternate group) */
3971 /* Volume, only for audio */
3972
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 235 times.
347 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3973 112 avio_wb16(pb, 0x0100);
3974 else
3975 235 avio_wb16(pb, 0);
3976 347 avio_wb16(pb, 0); /* reserved */
3977
3978 /* Matrix structure */
3979
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 346 times.
347 if (display_matrix) {
3980
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3981 9 avio_wb32(pb, display_matrix[i]);
3982 } else {
3983 346 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3984 }
3985 /* Track width and height, for visual only */
3986
4/4
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 213 times.
347 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3987
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 116 times.
339 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3988 int64_t track_width_1616;
3989
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
218 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
3990 140 track_width_1616 = track->par->width * 0x10000ULL;
3991 } else {
3992 78 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3993 78 track->par->width * 0x10000LL,
3994 78 st->sample_aspect_ratio.den);
3995
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 70 times.
78 if (!track_width_1616 ||
3996
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 track->height != track->par->height ||
3997 track_width_1616 > UINT32_MAX)
3998 70 track_width_1616 = track->par->width * 0x10000ULL;
3999 }
4000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 if (track_width_1616 > UINT32_MAX) {
4001 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4002 track_width_1616 = 0;
4003 }
4004 218 avio_wb32(pb, track_width_1616);
4005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 if (track->height > 0xFFFF) {
4006 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4007 avio_wb32(pb, 0);
4008 } else
4009 218 avio_wb32(pb, track->height * 0x10000U);
4010 } else {
4011 129 avio_wb32(pb, 0);
4012 129 avio_wb32(pb, 0);
4013 }
4014 347 return 0x5c;
4015 }
4016
4017 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4018 {
4019 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4020 1 track->par->sample_aspect_ratio.den);
4021
4022 1 int64_t pos = avio_tell(pb);
4023
4024 1 avio_wb32(pb, 0); /* size */
4025 1 ffio_wfourcc(pb, "tapt");
4026
4027 1 avio_wb32(pb, 20);
4028 1 ffio_wfourcc(pb, "clef");
4029 1 avio_wb32(pb, 0);
4030 1 avio_wb32(pb, width << 16);
4031 1 avio_wb32(pb, track->par->height << 16);
4032
4033 1 avio_wb32(pb, 20);
4034 1 ffio_wfourcc(pb, "prof");
4035 1 avio_wb32(pb, 0);
4036 1 avio_wb32(pb, width << 16);
4037 1 avio_wb32(pb, track->par->height << 16);
4038
4039 1 avio_wb32(pb, 20);
4040 1 ffio_wfourcc(pb, "enof");
4041 1 avio_wb32(pb, 0);
4042 1 avio_wb32(pb, track->par->width << 16);
4043 1 avio_wb32(pb, track->par->height << 16);
4044
4045 1 return update_size(pb, pos);
4046 }
4047
4048 // This box is written in the following cases:
4049 // * Seems important for the psp playback. Without it the movie seems to hang.
4050 // * Used for specifying the looping behavior of animated AVIF (as specified
4051 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4052 289 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4053 MOVTrack *track)
4054 {
4055 578 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
4056 289 mov->movie_timescale, track->timescale,
4057 AV_ROUND_UP);
4058 289 int version = duration < INT32_MAX ? 0 : 1;
4059 int entry_size, entry_count, size;
4060 289 int64_t delay, start_ct = track->start_cts;
4061 289 int64_t start_dts = track->start_dts;
4062 289 int flags = 0;
4063
4064
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 56 times.
289 if (track->entry) {
4065
2/6
✓ Branch 0 taken 233 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 233 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
233 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4066
4067 av_log(mov->fc, AV_LOG_DEBUG,
4068 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4069 track->cluster[0].dts, track->cluster[0].cts,
4070 start_dts, start_ct, track->track_id);
4071 start_dts = track->cluster[0].dts;
4072 start_ct = track->cluster[0].cts;
4073 }
4074 }
4075
4076 289 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4077 289 track->timescale, AV_ROUND_DOWN);
4078
4079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 if (mov->mode == MODE_AVIF) {
4080 delay = 0;
4081 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4082 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4083 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4084 // edit list is repeated.
4085 flags = mov->avif_loop_count != 1;
4086 start_ct = 0;
4087 }
4088
4089 289 version |= delay < INT32_MAX ? 0 : 1;
4090
4091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 entry_size = (version == 1) ? 20 : 12;
4092
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 287 times.
289 entry_count = 1 + (delay > 0);
4093 289 size = 24 + entry_count * entry_size;
4094
4095 /* write the atom data */
4096 289 avio_wb32(pb, size);
4097 289 ffio_wfourcc(pb, "edts");
4098 289 avio_wb32(pb, size - 8);
4099 289 ffio_wfourcc(pb, "elst");
4100 289 avio_w8(pb, version);
4101 289 avio_wb24(pb, flags); /* flags */
4102
4103 289 avio_wb32(pb, entry_count);
4104
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 287 times.
289 if (delay > 0) { /* add an empty edit to delay presentation */
4105 /* In the positive delay case, the delay includes the cts
4106 * offset, and the second edit list entry below trims out
4107 * the same amount from the actual content. This makes sure
4108 * that the offset last sample is included in the edit
4109 * list duration as well. */
4110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
4111 avio_wb64(pb, delay);
4112 avio_wb64(pb, -1);
4113 } else {
4114 2 avio_wb32(pb, delay);
4115 2 avio_wb32(pb, -1);
4116 }
4117 2 avio_wb32(pb, 0x00010000);
4118
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 } else if (mov->mode != MODE_AVIF) {
4119 /* Avoid accidentally ending up with start_ct = -1 which has got a
4120 * special meaning. Normally start_ct should end up positive or zero
4121 * here, but use FFMIN in case dts is a small positive integer
4122 * rounded to 0 when represented in movie timescale units. */
4123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4124 287 start_ct = -FFMIN(start_dts, 0);
4125
4126 #if CONFIG_IAMFENC
4127
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
287 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4128 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4129 #endif
4130 /* Note, this delay is calculated from the pts of the first sample,
4131 * ensuring that we don't reduce the duration for cases with
4132 * dts<0 pts=0. */
4133 287 duration += delay;
4134 }
4135
4136 /* For fragmented files, we don't know the full length yet. Setting
4137 * duration to 0 allows us to only specify the offset, including
4138 * the rest of the content (from all future fragments) without specifying
4139 * an explicit duration.
4140 *
4141 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4142 * don't reset duration to zero.
4143 */
4144
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 229 times.
289 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4145
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))
4146 60 duration = 0;
4147
4148 /* duration */
4149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 if (version == 1) {
4150 avio_wb64(pb, duration);
4151 avio_wb64(pb, start_ct);
4152 } else {
4153 289 avio_wb32(pb, duration);
4154 289 avio_wb32(pb, start_ct);
4155 }
4156 289 avio_wb32(pb, 0x00010000);
4157 289 return size;
4158 }
4159
4160 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4161 {
4162 14 avio_wb32(pb, 20); // size
4163 14 ffio_wfourcc(pb, "tref");
4164 14 avio_wb32(pb, 12); // size (subatom)
4165 14 avio_wl32(pb, track->tref_tag);
4166 14 avio_wb32(pb, track->tref_id);
4167 14 return 20;
4168 }
4169
4170 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4171 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4172 {
4173 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4174 2 ffio_wfourcc(pb, "uuid");
4175 2 ffio_wfourcc(pb, "USMT");
4176 2 avio_wb32(pb, 0x21d24fce);
4177 2 avio_wb32(pb, 0xbb88695c);
4178 2 avio_wb32(pb, 0xfac9c740);
4179 2 avio_wb32(pb, 0x1c); // another size here!
4180 2 ffio_wfourcc(pb, "MTDT");
4181 2 avio_wb32(pb, 0x00010012);
4182 2 avio_wb32(pb, 0x0a);
4183 2 avio_wb32(pb, 0x55c40000);
4184 2 avio_wb32(pb, 0x1);
4185 2 avio_wb32(pb, 0x0);
4186 2 return 0x34;
4187 }
4188
4189 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4190 {
4191 2 AVFormatContext *ctx = track->rtp_ctx;
4192 2 char buf[1000] = "";
4193 int len;
4194
4195 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4196 NULL, NULL, 0, 0, ctx);
4197 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4198 2 len = strlen(buf);
4199
4200 2 avio_wb32(pb, len + 24);
4201 2 ffio_wfourcc(pb, "udta");
4202 2 avio_wb32(pb, len + 16);
4203 2 ffio_wfourcc(pb, "hnti");
4204 2 avio_wb32(pb, len + 8);
4205 2 ffio_wfourcc(pb, "sdp ");
4206 2 avio_write(pb, buf, len);
4207 2 return len + 24;
4208 }
4209
4210 324 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4211 const char *tag, const char *str)
4212 {
4213 324 int64_t pos = avio_tell(pb);
4214 324 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4215
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 323 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
324 if (!t || !utf8len(t->value))
4216 323 return 0;
4217
4218 1 avio_wb32(pb, 0); /* size */
4219 1 ffio_wfourcc(pb, tag); /* type */
4220 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4221 1 return update_size(pb, pos);
4222 }
4223
4224 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4225 const char *value)
4226 {
4227 2 int64_t pos = avio_tell(pb);
4228
4229 /* Box|FullBox basics */
4230 2 avio_wb32(pb, 0); /* size placeholder */
4231 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4232 2 avio_w8(pb, 0); /* version = 0 */
4233 2 avio_wb24(pb, 0); /* flags = 0 */
4234
4235 /* Required null-terminated scheme URI */
4236 2 avio_write(pb, (const unsigned char *)scheme_uri,
4237 2 strlen(scheme_uri));
4238 2 avio_w8(pb, 0);
4239
4240 /* Optional value string */
4241
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])
4242 2 avio_write(pb, (const unsigned char *)value,
4243 2 strlen(value));
4244
4245 2 avio_w8(pb, 0);
4246
4247 2 return update_size(pb, pos);
4248 }
4249
4250 141 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4251 {
4252 141 int ret = AVERROR_BUG;
4253
4254
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++) {
4255 141 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4256
4257
2/2
✓ Branch 0 taken 705 times.
✓ Branch 1 taken 141 times.
846 for (int j = 0; map.value_maps[j].disposition; j++) {
4258 705 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4259
2/2
✓ Branch 0 taken 703 times.
✓ Branch 1 taken 2 times.
705 if (!(st->disposition & value_map.disposition))
4260 703 continue;
4261
4262
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)
4263 return ret;
4264 }
4265 }
4266
4267 141 return 0;
4268 }
4269
4270 347 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4271 AVStream *st)
4272 {
4273 AVIOContext *pb_buf;
4274 int ret, size;
4275 uint8_t *buf;
4276
4277
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 334 times.
347 if (!st)
4278 13 return 0;
4279
4280 334 ret = avio_open_dyn_buf(&pb_buf);
4281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 334 times.
334 if (ret < 0)
4282 return ret;
4283
4284
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 10 times.
334 if (mov->mode & (MODE_MP4|MODE_MOV))
4285 324 mov_write_track_metadata(pb_buf, st, "name", "title");
4286
4287
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 193 times.
334 if (mov->mode & MODE_MP4) {
4288
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 141 times.
141 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4289 return ret;
4290 }
4291
4292
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 331 times.
334 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4293 3 avio_wb32(pb, size + 8);
4294 3 ffio_wfourcc(pb, "udta");
4295 3 avio_write(pb, buf, size);
4296 }
4297 334 ffio_free_dyn_buf(&pb_buf);
4298
4299 334 return 0;
4300 }
4301
4302 347 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4303 MOVTrack *track, AVStream *st)
4304 {
4305 347 int64_t pos = avio_tell(pb);
4306 347 int entry_backup = track->entry;
4307 347 int chunk_backup = track->chunkCount;
4308 int ret;
4309
4310 /* If we want to have an empty moov, but some samples already have been
4311 * buffered (delay_moov), pretend that no samples have been written yet. */
4312
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 249 times.
347 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4313 98 track->chunkCount = track->entry = 0;
4314
4315 347 avio_wb32(pb, 0); /* size */
4316 347 ffio_wfourcc(pb, "trak");
4317 347 mov_write_tkhd_tag(pb, mov, track, st);
4318
4319 av_assert2(mov->use_editlist >= 0);
4320
4321
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 32 times.
347 if (track->start_dts != AV_NOPTS_VALUE) {
4322
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 26 times.
315 if (mov->use_editlist)
4323 289 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4324
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))
4325 av_log(mov->fc, AV_LOG_WARNING,
4326 "Not writing any edit list even though one would have been required\n");
4327 }
4328
4329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 347 times.
347 if (mov->is_animated_avif)
4330 mov_write_edts_tag(pb, mov, track);
4331
4332
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 333 times.
347 if (track->tref_tag)
4333 14 mov_write_tref_tag(pb, track);
4334
4335
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 347 times.
347 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4336 return ret;
4337
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 345 times.
347 if (track->mode == MODE_PSP)
4338 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4339
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 345 times.
347 if (track->tag == MKTAG('r','t','p',' '))
4340 2 mov_write_udta_sdp(pb, track);
4341
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 158 times.
347 if (track->mode == MODE_MOV) {
4342
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 49 times.
189 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4343 140 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4344
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
140 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4345 1 mov_write_tapt_tag(pb, track);
4346 }
4347 }
4348
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 189 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
189 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4349 mov_write_tapt_tag(pb, track);
4350 }
4351 }
4352 347 mov_write_track_udta_tag(pb, mov, st);
4353 347 track->entry = entry_backup;
4354 347 track->chunkCount = chunk_backup;
4355 347 return update_size(pb, pos);
4356 }
4357
4358 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4359 {
4360 int i, has_audio = 0, has_video = 0;
4361 int64_t pos = avio_tell(pb);
4362 int audio_profile = mov->iods_audio_profile;
4363 int video_profile = mov->iods_video_profile;
4364 for (i = 0; i < mov->nb_tracks; i++) {
4365 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4366 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4367 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4368 }
4369 }
4370 if (audio_profile < 0)
4371 audio_profile = 0xFF - has_audio;
4372 if (video_profile < 0)
4373 video_profile = 0xFF - has_video;
4374 avio_wb32(pb, 0x0); /* size */
4375 ffio_wfourcc(pb, "iods");
4376 avio_wb32(pb, 0); /* version & flags */
4377 put_descr(pb, 0x10, 7);
4378 avio_wb16(pb, 0x004f);
4379 avio_w8(pb, 0xff);
4380 avio_w8(pb, 0xff);
4381 avio_w8(pb, audio_profile);
4382 avio_w8(pb, video_profile);
4383 avio_w8(pb, 0xff);
4384 return update_size(pb, pos);
4385 }
4386
4387 114 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4388 {
4389 114 avio_wb32(pb, 0x20); /* size */
4390 114 ffio_wfourcc(pb, "trex");
4391 114 avio_wb32(pb, 0); /* version & flags */
4392 114 avio_wb32(pb, track->track_id); /* track ID */
4393 114 avio_wb32(pb, 1); /* default sample description index */
4394 114 avio_wb32(pb, 0); /* default sample duration */
4395 114 avio_wb32(pb, 0); /* default sample size */
4396 114 avio_wb32(pb, 0); /* default sample flags */
4397 114 return 0;
4398 }
4399
4400 60 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4401 {
4402 60 int64_t pos = avio_tell(pb);
4403 int i;
4404 60 avio_wb32(pb, 0x0); /* size */
4405 60 ffio_wfourcc(pb, "mvex");
4406
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 60 times.
174 for (i = 0; i < mov->nb_tracks; i++)
4407 114 mov_write_trex_tag(pb, &mov->tracks[i]);
4408 60 return update_size(pb, pos);
4409 }
4410
4411 246 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4412 {
4413 246 int max_track_id = 1, i;
4414 246 int64_t max_track_len = 0;
4415 int version;
4416 int timescale;
4417
4418
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 246 times.
595 for (i = 0; i < mov->nb_tracks; i++) {
4419
3/4
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
349 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4420 630 int64_t max_track_len_temp = av_rescale_rnd(
4421 315 calc_pts_duration(mov, &mov->tracks[i]),
4422 315 mov->movie_timescale,
4423 315 mov->tracks[i].timescale,
4424 AV_ROUND_UP);
4425
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 70 times.
315 if (max_track_len < max_track_len_temp)
4426 245 max_track_len = max_track_len_temp;
4427
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 230 times.
315 if (max_track_id < mov->tracks[i].track_id)
4428 85 max_track_id = mov->tracks[i].track_id;
4429 }
4430 }
4431 /* If using delay_moov, make sure the output is the same as if no
4432 * samples had been written yet. */
4433
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 194 times.
246 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4434 52 max_track_len = 0;
4435 52 max_track_id = 1;
4436 }
4437
4438 246 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4440
4441 246 ffio_wfourcc(pb, "mvhd");
4442 246 avio_w8(pb, version);
4443 246 avio_wb24(pb, 0); /* flags */
4444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 if (version == 1) {
4445 avio_wb64(pb, mov->time);
4446 avio_wb64(pb, mov->time);
4447 } else {
4448 246 avio_wb32(pb, mov->time); /* creation time */
4449 246 avio_wb32(pb, mov->time); /* modification time */
4450 }
4451
4452 246 timescale = mov->movie_timescale;
4453
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
246 if (mov->mode == MODE_AVIF && !timescale)
4454 timescale = mov->tracks[0].timescale;
4455
4456 246 avio_wb32(pb, timescale);
4457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4458
4459 246 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4460 246 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4461 246 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4462
4463 /* Matrix structure */
4464 246 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4465
4466 246 avio_wb32(pb, 0); /* reserved (preview time) */
4467 246 avio_wb32(pb, 0); /* reserved (preview duration) */
4468 246 avio_wb32(pb, 0); /* reserved (poster time) */
4469 246 avio_wb32(pb, 0); /* reserved (selection time) */
4470 246 avio_wb32(pb, 0); /* reserved (selection duration) */
4471 246 avio_wb32(pb, 0); /* reserved (current time) */
4472 246 avio_wb32(pb, max_track_id + 1); /* Next track id */
4473 246 return 0x6c;
4474 }
4475
4476 90 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4477 AVFormatContext *s)
4478 {
4479 90 avio_wb32(pb, 33); /* size */
4480 90 ffio_wfourcc(pb, "hdlr");
4481 90 avio_wb32(pb, 0);
4482 90 avio_wb32(pb, 0);
4483 90 ffio_wfourcc(pb, "mdir");
4484 90 ffio_wfourcc(pb, "appl");
4485 90 avio_wb32(pb, 0);
4486 90 avio_wb32(pb, 0);
4487 90 avio_w8(pb, 0);
4488 90 return 33;
4489 }
4490
4491 /* helper function to write a data tag with the specified string as data */
4492 57 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4493 {
4494 57 size_t data_len = strlen(data);
4495
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 34 times.
57 if (long_style) {
4496 23 int size = 16 + data_len;
4497 23 avio_wb32(pb, size); /* size */
4498 23 ffio_wfourcc(pb, "data");
4499 23 avio_wb32(pb, 1);
4500 23 avio_wb32(pb, 0);
4501 23 avio_write(pb, data, data_len);
4502 23 return size;
4503 } else {
4504 34 avio_wb16(pb, data_len); /* string length */
4505
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4506 26 lang = ff_mov_iso639_to_lang("und", 1);
4507 34 avio_wb16(pb, lang);
4508 34 avio_write(pb, data, data_len);
4509 34 return data_len + 4;
4510 }
4511 }
4512
4513 57 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4514 const char *value, int lang, int long_style)
4515 {
4516 57 int size = 0;
4517
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]) {
4518 57 int64_t pos = avio_tell(pb);
4519 57 avio_wb32(pb, 0); /* size */
4520 57 ffio_wfourcc(pb, name);
4521 57 mov_write_string_data_tag(pb, value, lang, long_style);
4522 57 size = update_size(pb, pos);
4523 }
4524 57 return size;
4525 }
4526
4527 3880 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4528 const char *tag, int *lang)
4529 {
4530 int l, len, len2;
4531 3880 AVDictionaryEntry *t, *t2 = NULL;
4532 char tag2[16];
4533
4534 3880 *lang = 0;
4535
4536
2/2
✓ Branch 1 taken 3827 times.
✓ Branch 2 taken 53 times.
3880 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4537 3827 return NULL;
4538
4539 53 len = strlen(t->key);
4540 53 snprintf(tag2, sizeof(tag2), "%s-", tag);
4541
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))) {
4542 8 len2 = strlen(t2->key);
4543
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)
4544
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4545 8 *lang = l;
4546 8 return t;
4547 }
4548 }
4549 45 return t;
4550 }
4551
4552 3790 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4553 const char *name, const char *tag,
4554 int long_style)
4555 {
4556 int lang;
4557 3790 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4558
2/2
✓ Branch 0 taken 3737 times.
✓ Branch 1 taken 53 times.
3790 if (!t)
4559 3737 return 0;
4560 53 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4561 }
4562
4563 /* iTunes bpm number */
4564 90 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4565 {
4566 90 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 int size = 0, tmpo = t ? atoi(t->value) : 0;
4568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (tmpo) {
4569 size = 26;
4570 avio_wb32(pb, size);
4571 ffio_wfourcc(pb, "tmpo");
4572 avio_wb32(pb, size-8); /* size */
4573 ffio_wfourcc(pb, "data");
4574 avio_wb32(pb, 0x15); //type specifier
4575 avio_wb32(pb, 0);
4576 avio_wb16(pb, tmpo); // data
4577 }
4578 90 return size;
4579 }
4580
4581 /* 3GPP TS 26.244 */
4582 90 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4583 {
4584 int lang;
4585 90 int64_t pos = avio_tell(pb);
4586 double latitude, longitude, altitude;
4587 int32_t latitude_fix, longitude_fix, altitude_fix;
4588 90 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4589 90 const char *ptr, *place = "";
4590 char *end;
4591 static const char *astronomical_body = "earth";
4592
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 if (!t)
4593 90 return 0;
4594
4595 ptr = t->value;
4596 latitude = strtod(ptr, &end);
4597 if (end == ptr) {
4598 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4599 return 0;
4600 }
4601 ptr = end;
4602 longitude = strtod(ptr, &end);
4603 if (end == ptr) {
4604 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4605 return 0;
4606 }
4607 ptr = end;
4608 altitude = strtod(ptr, &end);
4609 /* If no altitude was present, the default 0 should be fine */
4610 if (*end == '/')
4611 place = end + 1;
4612
4613 latitude_fix = (int32_t) ((1 << 16) * latitude);
4614 longitude_fix = (int32_t) ((1 << 16) * longitude);
4615 altitude_fix = (int32_t) ((1 << 16) * altitude);
4616
4617 avio_wb32(pb, 0); /* size */
4618 ffio_wfourcc(pb, "loci"); /* type */
4619 avio_wb32(pb, 0); /* version + flags */
4620 avio_wb16(pb, lang);
4621 avio_write(pb, place, strlen(place) + 1);
4622 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4623 avio_wb32(pb, longitude_fix);
4624 avio_wb32(pb, latitude_fix);
4625 avio_wb32(pb, altitude_fix);
4626 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4627 avio_w8(pb, 0); /* additional notes, null terminated string */
4628
4629 return update_size(pb, pos);
4630 }
4631
4632 /* iTunes track or disc number */
4633 180 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4634 AVFormatContext *s, int disc)
4635 {
4636
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 90 times.
180 AVDictionaryEntry *t = av_dict_get(s->metadata,
4637 disc ? "disc" : "track",
4638 NULL, 0);
4639
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 int size = 0, track = t ? atoi(t->value) : 0;
4640
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (track) {
4641 2 int tracks = 0;
4642 2 char *slash = strchr(t->value, '/');
4643
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4644 2 tracks = atoi(slash + 1);
4645 2 avio_wb32(pb, 32); /* size */
4646
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4647 2 avio_wb32(pb, 24); /* size */
4648 2 ffio_wfourcc(pb, "data");
4649 2 avio_wb32(pb, 0); // 8 bytes empty
4650 2 avio_wb32(pb, 0);
4651 2 avio_wb16(pb, 0); // empty
4652 2 avio_wb16(pb, track); // track / disc number
4653 2 avio_wb16(pb, tracks); // total track / disc number
4654 2 avio_wb16(pb, 0); // empty
4655 2 size = 32;
4656 }
4657 180 return size;
4658 }
4659
4660 540 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4661 const char *name, const char *tag,
4662 int len)
4663 {
4664 540 AVDictionaryEntry *t = NULL;
4665 uint8_t num;
4666 540 int size = 24 + len;
4667
4668
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)
4669 return -1;
4670
4671
2/2
✓ Branch 1 taken 538 times.
✓ Branch 2 taken 2 times.
540 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4672 538 return 0;
4673 2 num = atoi(t->value);
4674
4675 2 avio_wb32(pb, size);
4676 2 ffio_wfourcc(pb, name);
4677 2 avio_wb32(pb, size - 8);
4678 2 ffio_wfourcc(pb, "data");
4679 2 avio_wb32(pb, 0x15);
4680 2 avio_wb32(pb, 0);
4681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4682 2 else avio_w8 (pb, num);
4683
4684 2 return size;
4685 }
4686
4687 90 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4688 {
4689 90 MOVMuxContext *mov = s->priv_data;
4690 90 int64_t pos = 0;
4691
4692
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 90 times.
241 for (int i = 0; i < mov->nb_streams; i++) {
4693 151 MOVTrack *trk = &mov->tracks[i];
4694
4695
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)
4696 149 continue;
4697
4698
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4699 1 pos = avio_tell(pb);
4700 1 avio_wb32(pb, 0);
4701 1 ffio_wfourcc(pb, "covr");
4702 }
4703 2 avio_wb32(pb, 16 + trk->cover_image->size);
4704 2 ffio_wfourcc(pb, "data");
4705 2 avio_wb32(pb, trk->tag);
4706 2 avio_wb32(pb , 0);
4707 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4708 }
4709
4710
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 89 times.
90 return pos ? update_size(pb, pos) : 0;
4711 }
4712
4713 /* iTunes meta data list */
4714 90 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4715 AVFormatContext *s)
4716 {
4717 90 int64_t pos = avio_tell(pb);
4718 90 avio_wb32(pb, 0); /* size */
4719 90 ffio_wfourcc(pb, "ilst");
4720 90 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4721 90 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4722 90 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4723 90 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4724 90 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4725 90 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4726
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4727
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 86 times.
90 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4728 4 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4729 }
4730 90 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4731 90 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4732 90 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4733 90 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4734 90 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4735 90 mov_write_string_metadata(s, pb, "desc", "description",1);
4736 90 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4737 90 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4738 90 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4739 90 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4740 90 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4741 90 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4742 90 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4743 90 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4744 90 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4745 90 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4746 90 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4747 90 mov_write_covr(pb, s);
4748 90 mov_write_trkn_tag(pb, mov, s, 0); // track number
4749 90 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4750 90 mov_write_tmpo_tag(pb, s);
4751 90 return update_size(pb, pos);
4752 }
4753
4754 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4755 AVFormatContext *s)
4756 {
4757 avio_wb32(pb, 33); /* size */
4758 ffio_wfourcc(pb, "hdlr");
4759 avio_wb32(pb, 0);
4760 avio_wb32(pb, 0);
4761 ffio_wfourcc(pb, "mdta");
4762 avio_wb32(pb, 0);
4763 avio_wb32(pb, 0);
4764 avio_wb32(pb, 0);
4765 avio_w8(pb, 0);
4766 return 33;
4767 }
4768
4769 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4770 AVFormatContext *s)
4771 {
4772 const AVDictionaryEntry *t = NULL;
4773 int64_t pos = avio_tell(pb);
4774 int64_t curpos, entry_pos;
4775 int count = 0;
4776
4777 avio_wb32(pb, 0); /* size */
4778 ffio_wfourcc(pb, "keys");
4779 avio_wb32(pb, 0);
4780 entry_pos = avio_tell(pb);
4781 avio_wb32(pb, 0); /* entry count */
4782
4783 while (t = av_dict_iterate(s->metadata, t)) {
4784 size_t key_len = strlen(t->key);
4785 avio_wb32(pb, key_len + 8);
4786 ffio_wfourcc(pb, "mdta");
4787 avio_write(pb, t->key, key_len);
4788 count += 1;
4789 }
4790 curpos = avio_tell(pb);
4791 avio_seek(pb, entry_pos, SEEK_SET);
4792 avio_wb32(pb, count); // rewrite entry count
4793 avio_seek(pb, curpos, SEEK_SET);
4794
4795 return update_size(pb, pos);
4796 }
4797
4798 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4799 AVFormatContext *s)
4800 {
4801 const AVDictionaryEntry *t = NULL;
4802 int64_t pos = avio_tell(pb);
4803 int count = 1; /* keys are 1-index based */
4804
4805 avio_wb32(pb, 0); /* size */
4806 ffio_wfourcc(pb, "ilst");
4807
4808 while (t = av_dict_iterate(s->metadata, t)) {
4809 int64_t entry_pos = avio_tell(pb);
4810 avio_wb32(pb, 0); /* size */
4811 avio_wb32(pb, count); /* key */
4812 mov_write_string_data_tag(pb, t->value, 0, 1);
4813 update_size(pb, entry_pos);
4814 count += 1;
4815 }
4816 return update_size(pb, pos);
4817 }
4818
4819 /* meta data tags */
4820 90 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4821 AVFormatContext *s)
4822 {
4823 90 int size = 0;
4824 90 int64_t pos = avio_tell(pb);
4825 90 avio_wb32(pb, 0); /* size */
4826 90 ffio_wfourcc(pb, "meta");
4827 90 avio_wb32(pb, 0);
4828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4829 mov_write_mdta_hdlr_tag(pb, mov, s);
4830 mov_write_mdta_keys_tag(pb, mov, s);
4831 mov_write_mdta_ilst_tag(pb, mov, s);
4832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 } else if (mov->mode == MODE_AVIF) {
4833 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4834 // We always write the primary item id as 1 since only one track is
4835 // supported for AVIF.
4836 mov_write_pitm_tag(pb, 1);
4837 mov_write_iloc_tag(pb, mov, s);
4838 mov_write_iinf_tag(pb, mov, s);
4839 if (mov->nb_streams > 1)
4840 mov_write_iref_tag(pb, mov, s);
4841 mov_write_iprp_tag(pb, mov, s);
4842 } else {
4843 /* iTunes metadata tag */
4844 90 mov_write_itunes_hdlr_tag(pb, mov, s);
4845 90 mov_write_ilst_tag(pb, mov, s);
4846 }
4847 90 size = update_size(pb, pos);
4848 90 return size;
4849 }
4850
4851 155 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4852 const char *name, const char *key)
4853 {
4854 int len;
4855 AVDictionaryEntry *t;
4856
4857
1/2
✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
155 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4858 155 return 0;
4859
4860 len = strlen(t->value);
4861 if (len > 0) {
4862 int size = len + 8;
4863 avio_wb32(pb, size);
4864 ffio_wfourcc(pb, name);
4865 avio_write(pb, t->value, len);
4866 return size;
4867 }
4868 return 0;
4869 }
4870
4871 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4872 {
4873 int val;
4874 while (*b) {
4875 GET_UTF8(val, *b++, return -1;)
4876 avio_wb16(pb, val);
4877 }
4878 avio_wb16(pb, 0x00);
4879 return 0;
4880 }
4881
4882 static uint16_t language_code(const char *str)
4883 {
4884 return (((str[0] - 0x60) & 0x1F) << 10) +
4885 (((str[1] - 0x60) & 0x1F) << 5) +
4886 (( str[2] - 0x60) & 0x1F);
4887 }
4888
4889 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4890 const char *tag, const char *str)
4891 {
4892 int64_t pos = avio_tell(pb);
4893 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4894 if (!t || !utf8len(t->value))
4895 return 0;
4896 avio_wb32(pb, 0); /* size */
4897 ffio_wfourcc(pb, tag); /* type */
4898 avio_wb32(pb, 0); /* version + flags */
4899 if (!strcmp(tag, "yrrc"))
4900 avio_wb16(pb, atoi(t->value));
4901 else {
4902 avio_wb16(pb, language_code("eng")); /* language */
4903 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4904 if (!strcmp(tag, "albm") &&
4905 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4906 avio_w8(pb, atoi(t->value));
4907 }
4908 return update_size(pb, pos);
4909 }
4910
4911 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4912 {
4913 1 int64_t pos = avio_tell(pb);
4914 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4915
4916 1 avio_wb32(pb, 0); // size
4917 1 ffio_wfourcc(pb, "chpl");
4918 1 avio_wb32(pb, 0x01000000); // version + flags
4919 1 avio_wb32(pb, 0); // unknown
4920 1 avio_w8(pb, nb_chapters);
4921
4922
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4923 4 AVChapter *c = s->chapters[i];
4924 AVDictionaryEntry *t;
4925 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4926
4927
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4928
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4929 4 avio_w8(pb, len);
4930 4 avio_write(pb, t->value, len);
4931 } else
4932 avio_w8(pb, 0);
4933 }
4934 1 return update_size(pb, pos);
4935 }
4936
4937 245 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4938 AVFormatContext *s)
4939 {
4940 AVIOContext *pb_buf;
4941 int ret, size;
4942 uint8_t *buf;
4943
4944 245 ret = avio_open_dyn_buf(&pb_buf);
4945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 if (ret < 0)
4946 return ret;
4947
4948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 if (mov->mode & MODE_3GP) {
4949 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4950 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4951 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4952 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4953 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4954 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4955 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4956 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4957 mov_write_loci_tag(s, pb_buf);
4958
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
245 } 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
4959 155 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4960 155 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4961 155 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4962 155 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4963 155 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4964 155 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4965 // currently ignored by mov.c
4966 155 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4967 // add support for libquicktime, this atom is also actually read by mov.c
4968 155 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4969 155 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4970 155 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4971 155 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4972 155 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4973 155 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4974 155 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4975 155 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4976 } else {
4977 /* iTunes meta data */
4978 90 mov_write_meta_tag(pb_buf, mov, s);
4979 90 mov_write_loci_tag(s, pb_buf);
4980 }
4981
4982
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
245 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
4983 1 mov_write_chpl_tag(pb_buf, s);
4984
4985
2/2
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 127 times.
245 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4986 118 avio_wb32(pb, size + 8);
4987 118 ffio_wfourcc(pb, "udta");
4988 118 avio_write(pb, buf, size);
4989 }
4990 245 ffio_free_dyn_buf(&pb_buf);
4991
4992 245 return 0;
4993 }
4994
4995 static void mov_write_psp_udta_tag(AVIOContext *pb,
4996 const char *str, const char *lang, int type)
4997 {
4998 int len = utf8len(str) + 1;
4999 if (len <= 0)
5000 return;
5001 avio_wb16(pb, len * 2 + 10); /* size */
5002 avio_wb32(pb, type); /* type */
5003 avio_wb16(pb, language_code(lang)); /* language */
5004 avio_wb16(pb, 0x01); /* ? */
5005 ascii_to_wc(pb, str);
5006 }
5007
5008 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5009 {
5010 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5011 int64_t pos, pos2;
5012
5013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5014 pos = avio_tell(pb);
5015 avio_wb32(pb, 0); /* size placeholder*/
5016 ffio_wfourcc(pb, "uuid");
5017 ffio_wfourcc(pb, "USMT");
5018 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5019 avio_wb32(pb, 0xbb88695c);
5020 avio_wb32(pb, 0xfac9c740);
5021
5022 pos2 = avio_tell(pb);
5023 avio_wb32(pb, 0); /* size placeholder*/
5024 ffio_wfourcc(pb, "MTDT");
5025 avio_wb16(pb, 4);
5026
5027 // ?
5028 avio_wb16(pb, 0x0C); /* size */
5029 avio_wb32(pb, 0x0B); /* type */
5030 avio_wb16(pb, language_code("und")); /* language */
5031 avio_wb16(pb, 0x0); /* ? */
5032 avio_wb16(pb, 0x021C); /* data */
5033
5034 if (!(s->flags & AVFMT_FLAG_BITEXACT))
5035 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5036 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5037 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5038
5039 update_size(pb, pos2);
5040 return update_size(pb, pos);
5041 }
5042
5043 1 return 0;
5044 }
5045
5046 336 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5047 {
5048 AVEncryptionInitInfo *info;
5049 336 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5050 336 st->codecpar->nb_coded_side_data,
5051 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5052
1/2
✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
336 if (!sd)
5053 336 return 0;
5054
5055 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5056 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5057 int64_t pos;
5058
5059 if (!copy->data_size && !copy->num_key_ids)
5060 continue;
5061
5062 pos = avio_tell(pb);
5063 avio_wb32(pb, 0); /* size placeholder */
5064 ffio_wfourcc(pb, "pssh");
5065 avio_w8(pb, 1); /* version */
5066 avio_wb24(pb, 0);
5067 for (int i = 0; i < copy->system_id_size; i++)
5068 avio_w8(pb, copy->system_id[i]);
5069 avio_wb32(pb, copy->num_key_ids);
5070 for (int i = 0; i < copy->num_key_ids; i++)
5071 for (int j = 0; j < copy->key_id_size; j++)
5072 avio_w8(pb, copy->key_ids[i][j]);
5073 avio_wb32(pb, copy->data_size);
5074 avio_write(pb, copy->data, copy->data_size);
5075 update_size(pb, pos);
5076 }
5077
5078 av_encryption_init_info_free(info);
5079
5080 return 0;
5081 }
5082
5083 315 static void build_chunks(MOVTrack *trk)
5084 {
5085 int i;
5086 315 MOVIentry *chunk = &trk->cluster[0];
5087 315 uint64_t chunkSize = chunk->size;
5088 315 chunk->chunkNum = 1;
5089
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 259 times.
315 if (trk->chunkCount)
5090 56 return;
5091 259 trk->chunkCount = 1;
5092
2/2
✓ Branch 0 taken 14887 times.
✓ Branch 1 taken 259 times.
15146 for (i = 1; i<trk->entry; i++){
5093
2/2
✓ Branch 0 taken 12984 times.
✓ Branch 1 taken 1903 times.
14887 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5094
2/2
✓ Branch 0 taken 12983 times.
✓ Branch 1 taken 1 times.
12984 chunk->stsd_index == trk->cluster[i].stsd_index &&
5095
2/2
✓ Branch 0 taken 12338 times.
✓ Branch 1 taken 645 times.
12983 chunkSize + trk->cluster[i].size < (1<<20)){
5096 12338 chunkSize += trk->cluster[i].size;
5097 12338 chunk->samples_in_chunk += trk->cluster[i].entries;
5098 } else {
5099 2549 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5100 2549 chunk=&trk->cluster[i];
5101 2549 chunkSize = chunk->size;
5102 2549 trk->chunkCount++;
5103 }
5104 }
5105 }
5106
5107 /**
5108 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5109 * the stream ids are used as track ids.
5110 *
5111 * This assumes mov->tracks and s->streams are in the same order and
5112 * there are no gaps in either of them (so mov->tracks[n] refers to
5113 * s->streams[n]).
5114 *
5115 * As an exception, there can be more entries in
5116 * s->streams than in mov->tracks, in which case new track ids are
5117 * generated (starting after the largest found stream id).
5118 */
5119 246 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5120 {
5121 int i;
5122
5123
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 216 times.
246 if (mov->track_ids_ok)
5124 30 return 0;
5125
5126
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->use_stream_ids_as_track_ids) {
5127 1 int next_generated_track_id = 0;
5128
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5129 2 AVStream *st = mov->tracks[i].st;
5130
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5131 2 next_generated_track_id = st->id;
5132 }
5133
5134
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5135
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))
5136 continue;
5137
5138
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;
5139 }
5140 } else {
5141 215 int last_track_id = 0;
5142
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 215 times.
500 for (i = 0; i < mov->nb_tracks; i++) {
5143
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 253 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 30 times.
285 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5144 2 continue;
5145
5146 283 last_track_id =
5147 283 mov->tracks[i].track_id = (mov->tracks[i].st
5148 280 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5149
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 3 times.
283 : FFMAX(i, last_track_id)) + 1;
5150 }
5151 }
5152
5153 216 mov->track_ids_ok = 1;
5154
5155 216 return 0;
5156 }
5157
5158 246 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5159 AVFormatContext *s)
5160 {
5161 int i;
5162 246 int64_t pos = avio_tell(pb);
5163 246 avio_wb32(pb, 0); /* size placeholder*/
5164 246 ffio_wfourcc(pb, "moov");
5165
5166 246 mov_setup_track_ids(mov, s);
5167
5168
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 246 times.
595 for (i = 0; i < mov->nb_tracks; i++) {
5169
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 315 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 32 times.
349 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5170 2 continue;
5171
5172 347 mov->tracks[i].time = mov->time;
5173
5174
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 32 times.
347 if (mov->tracks[i].entry)
5175 315 build_chunks(&mov->tracks[i]);
5176 }
5177
5178
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 245 times.
246 if (mov->chapter_track)
5179
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5180 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5181 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5182 }
5183
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 246 times.
595 for (i = 0; i < mov->nb_tracks; i++) {
5184 349 MOVTrack *track = &mov->tracks[i];
5185
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 347 times.
349 if (track->tag == MKTAG('r','t','p',' ')) {
5186 2 track->tref_tag = MKTAG('h','i','n','t');
5187 2 track->tref_id = mov->tracks[track->src_track].track_id;
5188
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 235 times.
347 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5189 112 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5190 112 track->st->codecpar->nb_coded_side_data,
5191 AV_PKT_DATA_FALLBACK_TRACK );
5192
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)) {
5193 int *fallback = (int *)sd->data;
5194 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5195 track->tref_tag = MKTAG('f','a','l','l');
5196 track->tref_id = mov->tracks[*fallback].track_id;
5197 }
5198 }
5199 }
5200 }
5201
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 246 times.
595 for (i = 0; i < mov->nb_tracks; i++) {
5202
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 336 times.
349 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5203 13 int src_trk = mov->tracks[i].src_track;
5204 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5205 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5206 //src_trk may have a different timescale than the tmcd track
5207 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5208 13 mov->tracks[i].timescale,
5209 13 mov->tracks[src_trk].timescale);
5210 }
5211 }
5212
5213 246 mov_write_mvhd_tag(pb, mov);
5214
4/6
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 91 times.
246 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5215 mov_write_iods_tag(pb, mov);
5216
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 246 times.
595 for (i = 0; i < mov->nb_tracks; i++) {
5217
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 315 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 32 times.
349 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5219
2/2
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 13 times.
347 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 347 times.
347 if (ret < 0)
5221 return ret;
5222 }
5223 }
5224 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5225 * (mov->moov_written != 0)
5226 */
5227
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 184 times.
246 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5228
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))
5229 60 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5230
5231
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 245 times.
246 if (mov->mode == MODE_PSP)
5232 1 mov_write_uuidusmt_tag(pb, s);
5233
1/2
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
245 else if (mov->mode != MODE_AVIF)
5234 245 mov_write_udta_tag(pb, mov, s);
5235
2/2
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 246 times.
582 for (i = 0; i < mov->nb_streams; i++)
5236 336 mov_write_pssh_tag(pb, mov->tracks[i].st);
5237
5238 246 return update_size(pb, pos);
5239 }
5240
5241 static void param_write_int(AVIOContext *pb, const char *name, int value)
5242 {
5243 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5244 }
5245
5246 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5247 {
5248 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5249 }
5250
5251 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5252 {
5253 char buf[150];
5254 len = FFMIN(sizeof(buf) / 2 - 1, len);
5255 ff_data_to_hex(buf, value, len, 0);
5256 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5257 }
5258
5259 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5260 {
5261 int64_t pos = avio_tell(pb);
5262 int i;
5263
5264 static const AVUUID uuid = {
5265 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5266 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5267 };
5268
5269 avio_wb32(pb, 0);
5270 ffio_wfourcc(pb, "uuid");
5271 avio_write(pb, uuid, AV_UUID_LEN);
5272 avio_wb32(pb, 0);
5273
5274 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5275 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5276 avio_printf(pb, "<head>\n");
5277 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5278 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5279 LIBAVFORMAT_IDENT);
5280 avio_printf(pb, "</head>\n");
5281 avio_printf(pb, "<body>\n");
5282 avio_printf(pb, "<switch>\n");
5283
5284 mov_setup_track_ids(mov, s);
5285
5286 for (i = 0; i < mov->nb_tracks; i++) {
5287 MOVTrack *track = &mov->tracks[i];
5288 struct mpeg4_bit_rate_values bit_rates =
5289 calculate_mpeg4_bit_rates(track);
5290 const char *type;
5291 int track_id = track->track_id;
5292 char track_name_buf[32] = { 0 };
5293
5294 AVStream *st = track->st;
5295 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5296
5297 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5298 type = "video";
5299 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5300 type = "audio";
5301 } else {
5302 continue;
5303 }
5304
5305 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5306 bit_rates.avg_bit_rate);
5307 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5308 param_write_int(pb, "trackID", track_id);
5309 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5310
5311 /* Build track name piece by piece: */
5312 /* 1. track type */
5313 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5314 /* 2. track language, if available */
5315 if (lang)
5316 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5317 "_%s", lang->value);
5318 /* 3. special type suffix */
5319 /* "_cc" = closed captions, "_ad" = audio_description */
5320 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5321 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5322 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5323 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5324
5325 param_write_string(pb, "trackName", track_name_buf);
5326
5327 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5328 if (track->par->codec_id == AV_CODEC_ID_H264) {
5329 uint8_t *ptr;
5330 int size = track->extradata_size[track->last_stsd_index];
5331 if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5332 &size)) {
5333 param_write_hex(pb, "CodecPrivateData",
5334 ptr ? ptr : track->extradata[track->last_stsd_index],
5335 size);
5336 av_free(ptr);
5337 }
5338 param_write_string(pb, "FourCC", "H264");
5339 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5340 param_write_string(pb, "FourCC", "WVC1");
5341 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5342 track->extradata_size[track->last_stsd_index]);
5343 }
5344 param_write_int(pb, "MaxWidth", track->par->width);
5345 param_write_int(pb, "MaxHeight", track->par->height);
5346 param_write_int(pb, "DisplayWidth", track->par->width);
5347 param_write_int(pb, "DisplayHeight", track->par->height);
5348 } else {
5349 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5350 switch (track->par->profile) {
5351 case AV_PROFILE_AAC_HE_V2:
5352 param_write_string(pb, "FourCC", "AACP");
5353 break;
5354 case AV_PROFILE_AAC_HE:
5355 param_write_string(pb, "FourCC", "AACH");
5356 break;
5357 default:
5358 param_write_string(pb, "FourCC", "AACL");
5359 }
5360 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5361 param_write_string(pb, "FourCC", "WMAP");
5362 }
5363 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5364 track->extradata_size[track->last_stsd_index]);
5365 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5366 track->par->codec_id));
5367 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5368 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5369 0 : track->par->sample_rate);
5370 param_write_int(pb, "BitsPerSample", 16);
5371 param_write_int(pb, "PacketSize", track->par->block_align ?
5372 track->par->block_align : 4);
5373 }
5374 avio_printf(pb, "</%s>\n", type);
5375 }
5376 avio_printf(pb, "</switch>\n");
5377 avio_printf(pb, "</body>\n");
5378 avio_printf(pb, "</smil>\n");
5379
5380 return update_size(pb, pos);
5381 }
5382
5383 226 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5384 {
5385 226 avio_wb32(pb, 16);
5386 226 ffio_wfourcc(pb, "mfhd");
5387 226 avio_wb32(pb, 0);
5388 226 avio_wb32(pb, mov->fragments);
5389 226 return 0;
5390 }
5391
5392 13522 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5393 {
5394
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 :
5395 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5396 }
5397
5398 346 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5399 MOVTrack *track, int64_t moof_offset)
5400 {
5401 346 int64_t pos = avio_tell(pb);
5402 346 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5403 MOV_TFHD_BASE_DATA_OFFSET;
5404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (!track->entry) {
5405 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5406 } else {
5407 346 flags |= MOV_TFHD_DEFAULT_FLAGS;
5408 }
5409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5410 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5411
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 214 times.
346 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5412 132 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5413 132 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5414 }
5415 /* CMAF requires all values to be explicit in tfhd atoms */
5416
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 286 times.
346 if (mov->flags & FF_MOV_FLAG_CMAF)
5417 60 flags |= MOV_TFHD_STSD_ID;
5418
5419 /* Don't set a default sample size, the silverlight player refuses
5420 * to play files with that set. Don't set a default sample duration,
5421 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5422 * file format says it MUST NOT be set. */
5423
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 264 times.
346 if (track->mode == MODE_ISM)
5424 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5425 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5426
5427 346 avio_wb32(pb, 0); /* size placeholder */
5428 346 ffio_wfourcc(pb, "tfhd");
5429 346 avio_w8(pb, 0); /* version */
5430 346 avio_wb24(pb, flags);
5431
5432 346 avio_wb32(pb, track->track_id); /* track-id */
5433
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 214 times.
346 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5434 132 avio_wb64(pb, moof_offset);
5435
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 286 times.
346 if (flags & MOV_TFHD_STSD_ID) {
5436 60 avio_wb32(pb, 1);
5437 }
5438
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 82 times.
346 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5439 264 track->default_duration = get_cluster_duration(track, 0);
5440 264 avio_wb32(pb, track->default_duration);
5441 }
5442
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 82 times.
346 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5443
1/2
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
264 track->default_size = track->entry ? track->cluster[0].size : 1;
5444 264 avio_wb32(pb, track->default_size);
5445 } else
5446 82 track->default_size = -1;
5447
5448
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
346 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5449 /* Set the default flags based on the second sample, if available.
5450 * If the first sample is different, that can be signaled via a separate field. */
5451
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 64 times.
346 if (track->entry > 1)
5452 282 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5453 else
5454 64 track->default_sample_flags =
5455 64 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5456
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) :
5457 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5458 346 avio_wb32(pb, track->default_sample_flags);
5459 }
5460
5461 346 return update_size(pb, pos);
5462 }
5463
5464 348 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5465 MOVTrack *track, int moof_size,
5466 int first, int end)
5467 {
5468 348 int64_t pos = avio_tell(pb);
5469 348 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5470 int i;
5471
5472
2/2
✓ Branch 0 taken 12712 times.
✓ Branch 1 taken 348 times.
13060 for (i = first; i < end; i++) {
5473
2/2
✓ Branch 1 taken 1822 times.
✓ Branch 2 taken 10890 times.
12712 if (get_cluster_duration(track, i) != track->default_duration)
5474 1822 flags |= MOV_TRUN_SAMPLE_DURATION;
5475
2/2
✓ Branch 0 taken 2940 times.
✓ Branch 1 taken 9772 times.
12712 if (track->cluster[i].size != track->default_size)
5476 2940 flags |= MOV_TRUN_SAMPLE_SIZE;
5477
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)
5478 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5479 }
5480
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 &&
5481
2/2
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 176 times.
340 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5482 164 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5483
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 254 times.
348 if (track->flags & MOV_TRACK_CTTS)
5484 94 flags |= MOV_TRUN_SAMPLE_CTS;
5485
5486 348 avio_wb32(pb, 0); /* size placeholder */
5487 348 ffio_wfourcc(pb, "trun");
5488
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 190 times.
348 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5489 158 avio_w8(pb, 1); /* version */
5490 else
5491 190 avio_w8(pb, 0); /* version */
5492 348 avio_wb24(pb, flags);
5493
5494 348 avio_wb32(pb, end - first); /* sample count */
5495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 348 times.
348 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5496 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5497 !mov->first_trun)
5498 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5499 else
5500 348 avio_wb32(pb, moof_size + 8 + track->data_offset +
5501 348 track->cluster[first].pos); /* data offset */
5502
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 184 times.
348 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5503 164 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5504
5505
2/2
✓ Branch 0 taken 12712 times.
✓ Branch 1 taken 348 times.
13060 for (i = first; i < end; i++) {
5506
2/2
✓ Branch 0 taken 2010 times.
✓ Branch 1 taken 10702 times.
12712 if (flags & MOV_TRUN_SAMPLE_DURATION)
5507 2010 avio_wb32(pb, get_cluster_duration(track, i));
5508
2/2
✓ Branch 0 taken 3616 times.
✓ Branch 1 taken 9096 times.
12712 if (flags & MOV_TRUN_SAMPLE_SIZE)
5509 3616 avio_wb32(pb, track->cluster[i].size);
5510
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 12340 times.
12712 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5511 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5512
2/2
✓ Branch 0 taken 3156 times.
✓ Branch 1 taken 9556 times.
12712 if (flags & MOV_TRUN_SAMPLE_CTS)
5513 3156 avio_wb32(pb, track->cluster[i].cts);
5514 }
5515
5516 348 mov->first_trun = 0;
5517 348 return update_size(pb, pos);
5518 }
5519
5520 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5521 {
5522 82 int64_t pos = avio_tell(pb);
5523 static const uint8_t uuid[] = {
5524 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5525 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5526 };
5527
5528 82 avio_wb32(pb, 0); /* size placeholder */
5529 82 ffio_wfourcc(pb, "uuid");
5530 82 avio_write(pb, uuid, AV_UUID_LEN);
5531 82 avio_w8(pb, 1);
5532 82 avio_wb24(pb, 0);
5533 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5534 82 avio_wb64(pb, track->end_pts -
5535 82 (track->cluster[0].dts + track->cluster[0].cts));
5536
5537 82 return update_size(pb, pos);
5538 }
5539
5540 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5541 MOVTrack *track, int entry)
5542 {
5543 int n = track->nb_frag_info - 1 - entry, i;
5544 int size = 8 + 16 + 4 + 1 + 16*n;
5545 static const uint8_t uuid[] = {
5546 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5547 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5548 };
5549
5550 if (entry < 0)
5551 return 0;
5552
5553 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5554 avio_wb32(pb, size);
5555 ffio_wfourcc(pb, "uuid");
5556 avio_write(pb, uuid, AV_UUID_LEN);
5557 avio_w8(pb, 1);
5558 avio_wb24(pb, 0);
5559 avio_w8(pb, n);
5560 for (i = 0; i < n; i++) {
5561 int index = entry + 1 + i;
5562 avio_wb64(pb, track->frag_info[index].time);
5563 avio_wb64(pb, track->frag_info[index].duration);
5564 }
5565 if (n < mov->ism_lookahead) {
5566 int free_size = 16 * (mov->ism_lookahead - n);
5567 avio_wb32(pb, free_size);
5568 ffio_wfourcc(pb, "free");
5569 ffio_fill(pb, 0, free_size - 8);
5570 }
5571
5572 return 0;
5573 }
5574
5575 173 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5576 MOVTrack *track)
5577 {
5578 173 int64_t pos = avio_tell(pb);
5579 int i;
5580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 for (i = 0; i < mov->ism_lookahead; i++) {
5581 /* Update the tfrf tag for the last ism_lookahead fragments,
5582 * nb_frag_info - 1 is the next fragment to be written. */
5583 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5584 }
5585 173 avio_seek(pb, pos, SEEK_SET);
5586 173 return 0;
5587 }
5588
5589 113 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5590 int size)
5591 {
5592 int i;
5593
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 113 times.
329 for (i = 0; i < mov->nb_tracks; i++) {
5594 216 MOVTrack *track = &mov->tracks[i];
5595 MOVFragmentInfo *info;
5596
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)
5597 43 continue;
5598 173 track->nb_frag_info++;
5599
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 103 times.
173 if (track->nb_frag_info >= track->frag_info_capacity) {
5600 70 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5601
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
70 if (av_reallocp_array(&track->frag_info,
5602 new_capacity,
5603 sizeof(*track->frag_info)))
5604 return AVERROR(ENOMEM);
5605 70 track->frag_info_capacity = new_capacity;
5606 }
5607 173 info = &track->frag_info[track->nb_frag_info - 1];
5608 173 info->offset = avio_tell(pb);
5609 173 info->size = size;
5610 // Try to recreate the original pts for the first packet
5611 // from the fields we have stored
5612 173 info->time = track->cluster[0].dts + track->cluster[0].cts;
5613 173 info->duration = track->end_pts -
5614 173 (track->cluster[0].dts + track->cluster[0].cts);
5615 // If the pts is less than zero, we will have trimmed
5616 // away parts of the media track using an edit list,
5617 // and the corresponding start presentation time is zero.
5618
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 165 times.
173 if (info->time < 0) {
5619 8 info->duration += info->time;
5620 8 info->time = 0;
5621 }
5622 173 info->tfrf_offset = 0;
5623 173 mov_write_tfrf_tags(pb, mov, track);
5624 }
5625 113 return 0;
5626 }
5627
5628 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5629 {
5630 int i;
5631 for (i = 0; i < mov->nb_tracks; i++) {
5632 MOVTrack *track = &mov->tracks[i];
5633 if ((tracks >= 0 && i != tracks) || !track->entry)
5634 continue;
5635 if (track->nb_frag_info > max) {
5636 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5637 track->nb_frag_info = max;
5638 }
5639 }
5640 }
5641
5642 264 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5643 {
5644 264 int64_t pos = avio_tell(pb);
5645
5646 264 avio_wb32(pb, 0); /* size */
5647 264 ffio_wfourcc(pb, "tfdt");
5648 264 avio_w8(pb, 1); /* version */
5649 264 avio_wb24(pb, 0);
5650 264 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5651 264 return update_size(pb, pos);
5652 }
5653
5654 346 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5655 MOVTrack *track, int64_t moof_offset,
5656 int moof_size)
5657 {
5658 346 int64_t pos = avio_tell(pb);
5659 346 int i, start = 0;
5660 346 avio_wb32(pb, 0); /* size placeholder */
5661 346 ffio_wfourcc(pb, "traf");
5662
5663 346 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5664
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 82 times.
346 if (mov->mode != MODE_ISM)
5665 264 mov_write_tfdt_tag(pb, track);
5666
2/2
✓ Branch 0 taken 12366 times.
✓ Branch 1 taken 346 times.
12712 for (i = 1; i < track->entry; i++) {
5667
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) {
5668 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5669 2 start = i;
5670 }
5671 }
5672 346 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5673
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 264 times.
346 if (mov->mode == MODE_ISM) {
5674 82 mov_write_tfxd_tag(pb, track);
5675
5676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5677 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5678
5679 if (track->nb_frag_info > 0) {
5680 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5681 if (!info->tfrf_offset)
5682 info->tfrf_offset = avio_tell(pb);
5683 }
5684 avio_wb32(pb, 8 + size);
5685 ffio_wfourcc(pb, "free");
5686 ffio_fill(pb, 0, size);
5687 }
5688 }
5689
5690
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))
5691 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5692
5693 346 return update_size(pb, pos);
5694 }
5695
5696 226 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5697 int tracks, int moof_size)
5698 {
5699 226 int64_t pos = avio_tell(pb);
5700 int i;
5701
5702 226 avio_wb32(pb, 0); /* size placeholder */
5703 226 ffio_wfourcc(pb, "moof");
5704 226 mov->first_trun = 1;
5705
5706 226 mov_write_mfhd_tag(pb, mov);
5707
2/2
✓ Branch 0 taken 432 times.
✓ Branch 1 taken 226 times.
658 for (i = 0; i < mov->nb_tracks; i++) {
5708 432 MOVTrack *track = &mov->tracks[i];
5709
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)
5710 76 continue;
5711
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 346 times.
356 if (!track->entry)
5712 10 continue;
5713
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))
5714 mov_write_pssh_tag(pb, track->st);
5715 346 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5716 }
5717
5718 226 return update_size(pb, pos);
5719 }
5720
5721 72 static int mov_write_sidx_tag(AVIOContext *pb,
5722 MOVTrack *track, int ref_size, int total_sidx_size)
5723 {
5724 72 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5725 int64_t presentation_time, duration, offset;
5726 unsigned starts_with_SAP;
5727 int i, entries;
5728
5729
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 if (track->entry) {
5730 72 entries = 1;
5731 72 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
5732 72 duration = track->end_pts -
5733 72 (track->cluster[0].dts + track->cluster[0].cts);
5734 72 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5735
5736 // pts<0 should be cut away using edts
5737
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 66 times.
72 if (presentation_time < 0) {
5738 6 duration += presentation_time;
5739 6 presentation_time = 0;
5740 }
5741 } else {
5742 entries = track->nb_frag_info;
5743 if (entries <= 0)
5744 return 0;
5745 presentation_time = track->frag_info[0].time;
5746 }
5747
5748 72 avio_wb32(pb, 0); /* size */
5749 72 ffio_wfourcc(pb, "sidx");
5750 72 avio_w8(pb, 1); /* version */
5751 72 avio_wb24(pb, 0);
5752 72 avio_wb32(pb, track->track_id); /* reference_ID */
5753 72 avio_wb32(pb, track->timescale); /* timescale */
5754 72 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5755 72 offset_pos = avio_tell(pb);
5756 72 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5757 72 avio_wb16(pb, 0); /* reserved */
5758
5759 72 avio_wb16(pb, entries); /* reference_count */
5760
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 for (i = 0; i < entries; i++) {
5761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (!track->entry) {
5762 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5763 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5764 }
5765 duration = track->frag_info[i].duration;
5766 ref_size = track->frag_info[i].size;
5767 starts_with_SAP = 1;
5768 }
5769 72 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5770 72 avio_wb32(pb, duration); /* subsegment_duration */
5771 72 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5772 }
5773
5774 72 end_pos = avio_tell(pb);
5775 72 offset = pos + total_sidx_size - end_pos;
5776 72 avio_seek(pb, offset_pos, SEEK_SET);
5777 72 avio_wb64(pb, offset);
5778 72 avio_seek(pb, end_pos, SEEK_SET);
5779 72 return update_size(pb, pos);
5780 }
5781
5782 21 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5783 int tracks, int ref_size)
5784 {
5785 int i, round, ret;
5786 AVIOContext *avio_buf;
5787 21 int total_size = 0;
5788
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 21 times.
63 for (round = 0; round < 2; round++) {
5789 // First run one round to calculate the total size of all
5790 // sidx atoms.
5791 // This would be much simpler if we'd only write one sidx
5792 // atom, for the first track in the moof.
5793
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
42 if (round == 0) {
5794
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5795 return ret;
5796 } else {
5797 21 avio_buf = pb;
5798 }
5799
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 42 times.
114 for (i = 0; i < mov->nb_tracks; i++) {
5800 72 MOVTrack *track = &mov->tracks[i];
5801
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)
5802 continue;
5803 // When writing a sidx for the full file, entry is 0, but
5804 // we want to include all tracks. ref_size is 0 in this case,
5805 // since we read it from frag_info instead.
5806
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)
5807 continue;
5808 72 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5809 total_size);
5810 }
5811
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
42 if (round == 0)
5812 21 total_size = ffio_close_null_buf(avio_buf);
5813 }
5814 21 return 0;
5815 }
5816
5817 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5818 {
5819 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5820 MOVTrack *first_track;
5821 int flags = 24;
5822
5823 /* PRFT should be associated with at most one track. So, choosing only the
5824 * first track. */
5825 if (tracks > 0)
5826 return 0;
5827 first_track = &(mov->tracks[0]);
5828
5829 if (!first_track->entry) {
5830 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5831 return 0;
5832 }
5833
5834 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5835 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5836 return 0;
5837 }
5838
5839 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5840 if (first_track->cluster[0].prft.wallclock) {
5841 /* Round the NTP time to whole milliseconds. */
5842 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5843 NTP_OFFSET_US);
5844 flags = first_track->cluster[0].prft.flags;
5845 } else
5846 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5847 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5848 pts_us = av_rescale_q(first_track->cluster[0].pts,
5849 first_track->st->time_base, AV_TIME_BASE_Q);
5850 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5851 } else {
5852 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5853 mov->write_prft);
5854 return 0;
5855 }
5856
5857 avio_wb32(pb, 0); // Size place holder
5858 ffio_wfourcc(pb, "prft"); // Type
5859 avio_w8(pb, 1); // Version
5860 avio_wb24(pb, flags); // Flags
5861 avio_wb32(pb, first_track->track_id); // reference track ID
5862 avio_wb64(pb, ntp_ts); // NTP time stamp
5863 avio_wb64(pb, first_track->cluster[0].pts); //media time
5864 return update_size(pb, pos);
5865 }
5866
5867 113 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5868 int64_t mdat_size)
5869 {
5870 AVIOContext *avio_buf;
5871 int ret, moof_size;
5872
5873
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
113 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5874 return ret;
5875 113 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5876 113 moof_size = ffio_close_null_buf(avio_buf);
5877
5878
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 92 times.
113 if (mov->flags & FF_MOV_FLAG_DASH &&
5879
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5880 21 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5881
5882
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)
5883 mov_write_prft_tag(pb, mov, tracks);
5884
5885
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5886
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5887 mov->ism_lookahead) {
5888
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)
5889 return ret;
5890
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5892 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5893 }
5894 }
5895
5896 113 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5897 }
5898
5899 66 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5900 {
5901 66 int64_t pos = avio_tell(pb);
5902 int i;
5903
5904 66 avio_wb32(pb, 0); /* size placeholder */
5905 66 ffio_wfourcc(pb, "tfra");
5906 66 avio_w8(pb, 1); /* version */
5907 66 avio_wb24(pb, 0);
5908
5909 66 avio_wb32(pb, track->track_id);
5910 66 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5911 66 avio_wb32(pb, track->nb_frag_info);
5912
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 66 times.
233 for (i = 0; i < track->nb_frag_info; i++) {
5913 167 avio_wb64(pb, track->frag_info[i].time);
5914 167 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5915 167 avio_w8(pb, 1); /* traf number */
5916 167 avio_w8(pb, 1); /* trun number */
5917 167 avio_w8(pb, 1); /* sample number */
5918 }
5919
5920 66 return update_size(pb, pos);
5921 }
5922
5923 36 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5924 {
5925 AVIOContext *mfra_pb;
5926 int i, ret, sz;
5927 uint8_t *buf;
5928
5929 36 ret = avio_open_dyn_buf(&mfra_pb);
5930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (ret < 0)
5931 return ret;
5932
5933 36 avio_wb32(mfra_pb, 0); /* size placeholder */
5934 36 ffio_wfourcc(mfra_pb, "mfra");
5935 /* An empty mfra atom is enough to indicate to the publishing point that
5936 * the stream has ended. */
5937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (mov->flags & FF_MOV_FLAG_ISML)
5938 goto done_mfra;
5939
5940
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 36 times.
104 for (i = 0; i < mov->nb_tracks; i++) {
5941 68 MOVTrack *track = &mov->tracks[i];
5942
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 2 times.
68 if (track->nb_frag_info)
5943 66 mov_write_tfra_tag(mfra_pb, track);
5944 }
5945
5946 36 avio_wb32(mfra_pb, 16);
5947 36 ffio_wfourcc(mfra_pb, "mfro");
5948 36 avio_wb32(mfra_pb, 0); /* version + flags */
5949 36 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5950
5951 36 done_mfra:
5952
5953 36 sz = update_size(mfra_pb, 0);
5954 36 ret = avio_get_dyn_buf(mfra_pb, &buf);
5955 36 avio_write(pb, buf, ret);
5956 36 ffio_free_dyn_buf(&mfra_pb);
5957
5958 36 return sz;
5959 }
5960
5961 178 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5962 {
5963 178 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5964
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 32 times.
178 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5965
5966 178 mov->mdat_pos = avio_tell(pb);
5967 178 avio_wb32(pb, 0); /* size placeholder*/
5968 178 ffio_wfourcc(pb, "mdat");
5969 178 return 0;
5970 }
5971
5972 432 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5973 int has_h264, int has_video, int write_minor)
5974 {
5975 432 MOVMuxContext *mov = s->priv_data;
5976 432 int minor = 0x200;
5977
5978
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 432 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
432 if (mov->major_brand && strlen(mov->major_brand) >= 4)
5979 ffio_wfourcc(pb, mov->major_brand);
5980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 432 times.
432 else if (mov->mode == MODE_3GP) {
5981 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5982 minor = has_h264 ? 0x100 : 0x200;
5983
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 432 times.
432 } else if (mov->mode == MODE_AVIF) {
5984 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5985 minor = 0;
5986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 432 times.
432 } else if (mov->mode & MODE_3G2) {
5987 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5988 minor = has_h264 ? 0x20000 : 0x10000;
5989
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 430 times.
432 } else if (mov->mode == MODE_PSP)
5990 2 ffio_wfourcc(pb, "MSNV");
5991
4/4
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 306 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 60 times.
430 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
5992
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 56 times.
64 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5993 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5994
4/4
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 306 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 92 times.
422 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5995 24 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5996
3/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
398 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5997 ffio_wfourcc(pb, "iso4");
5998
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 306 times.
398 else if (mov->mode == MODE_MP4)
5999 92 ffio_wfourcc(pb, "isom");
6000
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 304 times.
306 else if (mov->mode == MODE_IPOD)
6001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6002
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 294 times.
304 else if (mov->mode == MODE_ISM)
6003 10 ffio_wfourcc(pb, "isml");
6004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
294 else if (mov->mode == MODE_F4V)
6005 ffio_wfourcc(pb, "f4v ");
6006 else
6007 294 ffio_wfourcc(pb, "qt ");
6008
6009
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 216 times.
432 if (write_minor)
6010 216 avio_wb32(pb, minor);
6011 432 }
6012
6013 216 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6014 {
6015 216 MOVMuxContext *mov = s->priv_data;
6016 216 int64_t pos = avio_tell(pb);
6017 216 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6018 216 int has_iamf = 0;
6019
6020 #if CONFIG_IAMFENC
6021
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 211 times.
216 for (int i = 0; i < s->nb_stream_groups; i++) {
6022 5 const AVStreamGroup *stg = s->stream_groups[i];
6023
6024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6025 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6026 5 has_iamf = 1;
6027 5 break;
6028 }
6029 }
6030 #endif
6031
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 216 times.
494 for (int i = 0; i < mov->nb_streams; i++) {
6032 278 AVStream *st = mov->tracks[i].st;
6033
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 276 times.
278 if (is_cover_image(st))
6034 2 continue;
6035
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 91 times.
276 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6036 185 has_video = 1;
6037
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 241 times.
276 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6038 35 has_h264 = 1;
6039
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 275 times.
276 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6040 1 has_av1 = 1;
6041
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 4 times.
276 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6042
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 1 times.
272 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6043
2/4
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 271 times.
542 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6044 271 av_packet_side_data_get(st->codecpar->coded_side_data,
6045 271 st->codecpar->nb_coded_side_data,
6046 AV_PKT_DATA_DOVI_CONF))
6047 5 has_dolby = 1;
6048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
276 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6049 has_id3 = 1;
6050 }
6051
6052 216 avio_wb32(pb, 0); /* size */
6053 216 ffio_wfourcc(pb, "ftyp");
6054
6055 // Write major brand
6056 216 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6057 // Write the major brand as the first compatible brand as well
6058 216 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6059
6060 // Write compatible brands, ensuring that we don't write the major brand as a
6061 // compatible brand a second time.
6062
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 211 times.
216 if (mov->mode == MODE_ISM) {
6063 5 ffio_wfourcc(pb, "piff");
6064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 } else if (mov->mode == MODE_AVIF) {
6065 const AVPixFmtDescriptor *pix_fmt_desc =
6066 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6067 const int depth = pix_fmt_desc->comp[0].depth;
6068 if (mov->is_animated_avif) {
6069 // For animated AVIF, major brand is "avis". Add "avif" as a
6070 // compatible brand.
6071 ffio_wfourcc(pb, "avif");
6072 ffio_wfourcc(pb, "msf1");
6073 ffio_wfourcc(pb, "iso8");
6074 }
6075 ffio_wfourcc(pb, "mif1");
6076 ffio_wfourcc(pb, "miaf");
6077 if (depth == 8 || depth == 10) {
6078 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6079 // computing that is based on chroma subsampling type. 420 chroma
6080 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6081 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6082 // 444 chroma subsampling.
6083 ffio_wfourcc(pb, "MA1A");
6084 } else {
6085 // 420 chroma subsampling.
6086 ffio_wfourcc(pb, "MA1B");
6087 }
6088 }
6089
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 147 times.
211 } else if (mov->mode != MODE_MOV) {
6090 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6091 // brand, if not already the major brand. This is compatible with users that
6092 // don't understand tfdt.
6093
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 2 times.
64 if (mov->mode == MODE_MP4) {
6094
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 60 times.
62 if (mov->flags & FF_MOV_FLAG_CMAF)
6095 2 ffio_wfourcc(pb, "cmfc");
6096
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 4 times.
62 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6097 28 ffio_wfourcc(pb, "iso6");
6098
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (has_av1)
6099 1 ffio_wfourcc(pb, "av01");
6100
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59 times.
62 if (has_dolby)
6101 3 ffio_wfourcc(pb, "dby1");
6102
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 57 times.
62 if (has_iamf)
6103 5 ffio_wfourcc(pb, "iamf");
6104 } else {
6105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6106 ffio_wfourcc(pb, "iso6");
6107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6108 ffio_wfourcc(pb, "iso5");
6109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6110 ffio_wfourcc(pb, "iso4");
6111 }
6112 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6113
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 14 times.
64 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6114 // write isom for mp4 only if it it's not the major brand already.
6115
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 46 times.
50 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6116 4 ffio_wfourcc(pb, "isom");
6117 50 ffio_wfourcc(pb, "iso2");
6118
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 29 times.
50 if (has_h264)
6119 21 ffio_wfourcc(pb, "avc1");
6120 }
6121 }
6122
6123
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 154 times.
216 if (mov->mode == MODE_MP4)
6124 62 ffio_wfourcc(pb, "mp41");
6125
6126
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
216 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6127 ffio_wfourcc(pb, "dash");
6128
6129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (has_id3)
6130 ffio_wfourcc(pb, "aid3");
6131
6132 216 return update_size(pb, pos);
6133 }
6134
6135 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6136 {
6137 1 AVStream *video_st = s->streams[0];
6138 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6139 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6140 1 int audio_rate = audio_par->sample_rate;
6141 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6142
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 :
6143 0;
6144 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6145 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6146
6147
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) {
6148 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6149 return AVERROR(EINVAL);
6150 }
6151
6152 1 avio_wb32(pb, 0x94); /* size */
6153 1 ffio_wfourcc(pb, "uuid");
6154 1 ffio_wfourcc(pb, "PROF");
6155
6156 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6157 1 avio_wb32(pb, 0xbb88695c);
6158 1 avio_wb32(pb, 0xfac9c740);
6159
6160 1 avio_wb32(pb, 0x0); /* ? */
6161 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6162
6163 1 avio_wb32(pb, 0x14); /* size */
6164 1 ffio_wfourcc(pb, "FPRF");
6165 1 avio_wb32(pb, 0x0); /* ? */
6166 1 avio_wb32(pb, 0x0); /* ? */
6167 1 avio_wb32(pb, 0x0); /* ? */
6168
6169 1 avio_wb32(pb, 0x2c); /* size */
6170 1 ffio_wfourcc(pb, "APRF"); /* audio */
6171 1 avio_wb32(pb, 0x0);
6172 1 avio_wb32(pb, 0x2); /* TrackID */
6173 1 ffio_wfourcc(pb, "mp4a");
6174 1 avio_wb32(pb, 0x20f);
6175 1 avio_wb32(pb, 0x0);
6176 1 avio_wb32(pb, audio_kbitrate);
6177 1 avio_wb32(pb, audio_kbitrate);
6178 1 avio_wb32(pb, audio_rate);
6179 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6180
6181 1 avio_wb32(pb, 0x34); /* size */
6182 1 ffio_wfourcc(pb, "VPRF"); /* video */
6183 1 avio_wb32(pb, 0x0);
6184 1 avio_wb32(pb, 0x1); /* TrackID */
6185
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6186 1 ffio_wfourcc(pb, "avc1");
6187 1 avio_wb16(pb, 0x014D);
6188 1 avio_wb16(pb, 0x0015);
6189 } else {
6190 ffio_wfourcc(pb, "mp4v");
6191 avio_wb16(pb, 0x0000);
6192 avio_wb16(pb, 0x0103);
6193 }
6194 1 avio_wb32(pb, 0x0);
6195 1 avio_wb32(pb, video_kbitrate);
6196 1 avio_wb32(pb, video_kbitrate);
6197 1 avio_wb32(pb, frame_rate);
6198 1 avio_wb32(pb, frame_rate);
6199 1 avio_wb16(pb, video_par->width);
6200 1 avio_wb16(pb, video_par->height);
6201 1 avio_wb32(pb, 0x010001); /* ? */
6202
6203 1 return 0;
6204 }
6205
6206 216 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6207 {
6208 216 MOVMuxContext *mov = s->priv_data;
6209 int i;
6210
6211 216 mov_write_ftyp_tag(pb,s);
6212
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->mode == MODE_PSP) {
6213 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6214
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6215 2 AVStream *st = mov->tracks[i].st;
6216
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6217 continue;
6218
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6219 1 video_streams_nb++;
6220
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6221 1 audio_streams_nb++;
6222 else
6223 other_streams_nb++;
6224 }
6225
6226
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) {
6227 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6228 return AVERROR(EINVAL);
6229 }
6230 1 return mov_write_uuidprof_tag(pb, s);
6231 }
6232 215 return 0;
6233 }
6234
6235 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6236 {
6237 8 uint32_t c = -1;
6238 8 int i, closed_gop = 0;
6239
6240
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6241 368 c = (c << 8) + pkt->data[i];
6242
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6243 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6244
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6245 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6246
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
6247 8 *flags = MOV_SYNC_SAMPLE;
6248 else
6249 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6250 8 break;
6251 }
6252 }
6253 8 return 0;
6254 }
6255
6256 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6257 {
6258 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6259 int seq = 0, entry = 0;
6260 int key = pkt->flags & AV_PKT_FLAG_KEY;
6261 start = find_next_marker(pkt->data, end);
6262 for (next = start; next < end; start = next) {
6263 next = find_next_marker(start + 4, end);
6264 switch (AV_RB32(start)) {
6265 case VC1_CODE_SEQHDR:
6266 seq = 1;
6267 break;
6268 case VC1_CODE_ENTRYPOINT:
6269 entry = 1;
6270 break;
6271 case VC1_CODE_SLICE:
6272 trk->vc1_info.slices = 1;
6273 break;
6274 }
6275 }
6276 if (!trk->entry && trk->vc1_info.first_packet_seen)
6277 trk->vc1_info.first_frag_written = 1;
6278 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6279 /* First packet in first fragment */
6280 trk->vc1_info.first_packet_seq = seq;
6281 trk->vc1_info.first_packet_entry = entry;
6282 trk->vc1_info.first_packet_seen = 1;
6283 } else if ((seq && !trk->vc1_info.packet_seq) ||
6284 (entry && !trk->vc1_info.packet_entry)) {
6285 int i;
6286 for (i = 0; i < trk->entry; i++)
6287 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6288 trk->has_keyframes = 0;
6289 if (seq)
6290 trk->vc1_info.packet_seq = 1;
6291 if (entry)
6292 trk->vc1_info.packet_entry = 1;
6293 if (!trk->vc1_info.first_frag_written) {
6294 /* First fragment */
6295 if ((!seq || trk->vc1_info.first_packet_seq) &&
6296 (!entry || trk->vc1_info.first_packet_entry)) {
6297 /* First packet had the same headers as this one, readd the
6298 * sync sample flag. */
6299 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6300 trk->has_keyframes = 1;
6301 }
6302 }
6303 }
6304 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6305 key = seq && entry;
6306 else if (trk->vc1_info.packet_seq)
6307 key = seq;
6308 else if (trk->vc1_info.packet_entry)
6309 key = entry;
6310 if (key) {
6311 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6312 trk->has_keyframes++;
6313 }
6314 }
6315
6316 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6317 {
6318 int length;
6319
6320 if (pkt->size < 8)
6321 return;
6322
6323 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6324 if (length < 8 || length > pkt->size)
6325 return;
6326
6327 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6328 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6329 trk->has_keyframes++;
6330 }
6331
6332 return;
6333 }
6334
6335 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6336 {
6337 89 MOVMuxContext *mov = s->priv_data;
6338 int ret, buf_size;
6339 uint8_t *buf;
6340 int i, offset;
6341
6342
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!track->mdat_buf)
6343 1 return 0;
6344
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 86 times.
88 if (!mov->mdat_buf) {
6345
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6346 return ret;
6347 }
6348 88 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6349
6350 88 offset = avio_tell(mov->mdat_buf);
6351 88 avio_write(mov->mdat_buf, buf, buf_size);
6352 88 ffio_free_dyn_buf(&track->mdat_buf);
6353
6354
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 88 times.
176 for (i = track->entries_flushed; i < track->entry; i++)
6355 88 track->cluster[i].pos += offset;
6356 88 track->entries_flushed = track->entry;
6357 88 return 0;
6358 }
6359
6360 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6361 {
6362 28 MOVMuxContext *mov = s->priv_data;
6363 28 AVPacket *squashed_packet = mov->pkt;
6364 28 int ret = AVERROR_BUG;
6365
6366
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6367 28 case AV_CODEC_ID_TTML: {
6368 28 int had_packets = !!track->squashed_packet_queue.head;
6369
6370
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) {
6371 goto finish_squash;
6372 }
6373
6374 // We have generated a padding packet (no actual input packets in
6375 // queue) and its duration is zero. Skipping writing it.
6376
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) {
6377 goto finish_squash;
6378 }
6379
6380 28 track->end_reliable = 1;
6381 28 break;
6382 }
6383 default:
6384 ret = AVERROR(EINVAL);
6385 goto finish_squash;
6386 }
6387
6388 28 squashed_packet->stream_index = track->st->index;
6389
6390 28 ret = mov_write_single_packet(s, squashed_packet);
6391
6392 28 finish_squash:
6393 28 av_packet_unref(squashed_packet);
6394
6395 28 return ret;
6396 }
6397
6398 353 static int mov_write_squashed_packets(AVFormatContext *s)
6399 {
6400 353 MOVMuxContext *mov = s->priv_data;
6401
6402
2/2
✓ Branch 0 taken 529 times.
✓ Branch 1 taken 353 times.
882 for (int i = 0; i < mov->nb_streams; i++) {
6403 529 MOVTrack *track = &mov->tracks[i];
6404 529 int ret = AVERROR_BUG;
6405
6406
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 499 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
529 if (track->squash_fragment_samples_to_one && !track->entry) {
6407
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6408 av_log(s, AV_LOG_ERROR,
6409 "Failed to write squashed packet for %s stream with "
6410 "index %d and track id %d. Error: %s\n",
6411 avcodec_get_name(track->st->codecpar->codec_id),
6412 track->st->index, track->track_id,
6413 av_err2str(ret));
6414 return ret;
6415 }
6416 }
6417 }
6418
6419 353 return 0;
6420 }
6421
6422 181 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6423 int64_t ref_pos)
6424 {
6425 int i;
6426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 if (!track->entry)
6427 return 0;
6428
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 173 times.
181 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6429
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6430 124 track->cluster[i].pos += ref_pos + track->data_offset;
6431
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6432 // First flush. Chunking for this fragment may already have been
6433 // done, either if we didn't use empty_moov, or if we did use
6434 // delay_moov. In either case, reset chunking here.
6435
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6436 63 track->cluster[i].chunkNum = 0;
6437 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6438 }
6439 }
6440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6441 8 track->entry_written + track->entry,
6442 sizeof(*track->cluster)))
6443 return AVERROR(ENOMEM);
6444 8 memcpy(&track->cluster_written[track->entry_written],
6445 8 track->cluster, track->entry * sizeof(*track->cluster));
6446 8 track->entry_written += track->entry;
6447 }
6448 181 track->entry = 0;
6449 181 track->entries_flushed = 0;
6450 181 track->end_reliable = 0;
6451 181 return 0;
6452 }
6453
6454 137 static int mov_flush_fragment(AVFormatContext *s, int force)
6455 {
6456 137 MOVMuxContext *mov = s->priv_data;
6457 137 int i, first_track = -1;
6458 137 int64_t mdat_size = 0, mdat_start = 0;
6459 int ret;
6460 137 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6461
6462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
137 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6463 return 0;
6464
6465 // Check if we have any tracks that require squashing.
6466 // In that case, we'll have to write the packet here.
6467
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
137 if ((ret = mov_write_squashed_packets(s)) < 0)
6468 return ret;
6469
6470 // Try to fill in the duration of the last packet in each stream
6471 // from queued packets in the interleave queues. If the flushing
6472 // of fragments was triggered automatically by an AVPacket, we
6473 // already have reliable info for the end of that track, but other
6474 // tracks may need to be filled in.
6475
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 137 times.
388 for (i = 0; i < mov->nb_streams; i++) {
6476 251 MOVTrack *track = &mov->tracks[i];
6477
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 89 times.
251 if (!track->end_reliable) {
6478 162 const AVPacket *pkt = ff_interleaved_peek(s, i);
6479
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 156 times.
162 if (pkt) {
6480 int64_t offset, dts, pts;
6481 6 ff_get_muxer_ts_offset(s, i, &offset);
6482 6 pts = pkt->pts + offset;
6483 6 dts = pkt->dts + offset;
6484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6485 dts += track->dts_shift;
6486 6 track->track_duration = dts - track->start_dts;
6487
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6488 6 track->end_pts = pts;
6489 else
6490 track->end_pts = dts;
6491 }
6492 }
6493 }
6494
6495
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 137 times.
394 for (i = 0; i < mov->nb_tracks; i++) {
6496 257 MOVTrack *track = &mov->tracks[i];
6497
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 183 times.
257 if (track->entry <= 1)
6498 74 continue;
6499 // Sample durations are calculated as the diff of dts values,
6500 // but for the last sample in a fragment, we don't know the dts
6501 // of the first sample in the next fragment, so we have to rely
6502 // on what was set as duration in the AVPacket. Not all callers
6503 // set this though, so we might want to replace it with an
6504 // estimate if it currently is zero.
6505
2/2
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 2 times.
183 if (get_cluster_duration(track, track->entry - 1) != 0)
6506 181 continue;
6507 // Use the duration (i.e. dts diff) of the second last sample for
6508 // the last one. This is a wild guess (and fatal if it turns out
6509 // to be too long), but probably the best we can do - having a zero
6510 // duration is bad as well.
6511 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6512 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6513
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6514 2 av_log(s, AV_LOG_WARNING,
6515 "Estimating the duration of the last packet in a "
6516 "fragment, consider setting the duration field in "
6517 "AVPacket instead.\n");
6518 2 mov->missing_duration_warned = 1;
6519 }
6520 }
6521
6522
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 113 times.
137 if (!mov->moov_written) {
6523 24 int64_t pos = avio_tell(s->pb);
6524 uint8_t *buf;
6525 int buf_size, moov_size;
6526
6527
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 20 times.
66 for (i = 0; i < mov->nb_tracks; i++)
6528
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))
6529 4 break;
6530 /* Don't write the initial moov unless all tracks have data */
6531
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)
6532 2 return 0;
6533
6534 22 moov_size = get_moov_size(s);
6535
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 22 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6536 42 mov->tracks[i].data_offset = pos + moov_size + 8;
6537
6538 22 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6539
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6540
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6541 18 mov_write_identification(s->pb, s);
6542
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6543 return ret;
6544
6545
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6547 mov->reserved_header_pos = avio_tell(s->pb);
6548 18 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6549 18 mov->moov_written = 1;
6550 18 return 0;
6551 }
6552
6553 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6554 4 avio_wb32(s->pb, buf_size + 8);
6555 4 ffio_wfourcc(s->pb, "mdat");
6556 4 avio_write(s->pb, buf, buf_size);
6557 4 ffio_free_dyn_buf(&mov->mdat_buf);
6558
6559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6560 mov->reserved_header_pos = avio_tell(s->pb);
6561
6562 4 mov->moov_written = 1;
6563 4 mov->mdat_size = 0;
6564
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6565 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6566 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6567 4 return 0;
6568 }
6569
6570
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 111 times.
113 if (mov->frag_interleave) {
6571
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6572 4 MOVTrack *track = &mov->tracks[i];
6573 int ret;
6574
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6575 return ret;
6576 }
6577
6578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6579 return 0;
6580 2 mdat_size = avio_tell(mov->mdat_buf);
6581 }
6582
6583
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 113 times.
324 for (i = 0; i < mov->nb_tracks; i++) {
6584 211 MOVTrack *track = &mov->tracks[i];
6585
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)
6586 49 track->data_offset = 0;
6587 else
6588 162 track->data_offset = mdat_size;
6589
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 110 times.
211 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6590 101 has_video = 1;
6591
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (first_video_track) {
6592
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 13 times.
101 if (track->entry)
6593 88 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6594 101 first_video_track = 0;
6595 }
6596 }
6597
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 173 times.
211 if (!track->entry)
6598 38 continue;
6599
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 if (track->mdat_buf)
6600 170 mdat_size += avio_tell(track->mdat_buf);
6601
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 77 times.
173 if (first_track < 0)
6602 96 first_track = i;
6603 }
6604
6605
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 96 times.
113 if (!mdat_size)
6606 17 return 0;
6607
6608
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4 times.
96 avio_write_marker(s->pb,
6609 96 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6610
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);
6611
6612
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 96 times.
277 for (i = first_track; i < mov->nb_tracks; i++) {
6613 181 MOVTrack *track = &mov->tracks[i];
6614 181 int buf_size, write_moof = 1, moof_tracks = -1;
6615 uint8_t *buf;
6616
6617
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 173 times.
181 if (!track->entry)
6618 9 continue;
6619
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 132 times.
173 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6620 41 mdat_size = avio_tell(track->mdat_buf);
6621 41 moof_tracks = i;
6622 } else {
6623 132 write_moof = i == first_track;
6624 }
6625
6626
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 60 times.
173 if (write_moof) {
6627 113 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6628
6629 113 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6630 113 mov->fragments++;
6631
6632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 if (track->cenc.aes_ctr)
6633 ff_mov_cenc_flush(&track->cenc);
6634
6635 113 avio_wb32(s->pb, mdat_size + 8);
6636 113 ffio_wfourcc(s->pb, "mdat");
6637 113 mdat_start = avio_tell(s->pb);
6638 }
6639
6640 173 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6641
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 if (!mov->frag_interleave) {
6642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (!track->mdat_buf)
6643 continue;
6644 170 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6645 170 track->mdat_buf = NULL;
6646 } else {
6647
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (!mov->mdat_buf)
6648 1 continue;
6649 2 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6650 2 mov->mdat_buf = NULL;
6651 }
6652
6653 172 avio_write(s->pb, buf, buf_size);
6654 172 av_free(buf);
6655 }
6656
6657 96 mov->mdat_size = 0;
6658
6659 96 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6660 96 return 0;
6661 }
6662
6663 91 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6664 {
6665 91 MOVMuxContext *mov = s->priv_data;
6666 91 int had_moov = mov->moov_written;
6667 91 int ret = mov_flush_fragment(s, force);
6668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 if (ret < 0)
6669 return ret;
6670 // If using delay_moov, the first flush only wrote the moov,
6671 // not the actual moof+mdat pair, thus flush once again.
6672
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)
6673 9 ret = mov_flush_fragment(s, force);
6674 91 return ret;
6675 }
6676
6677 38849 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6678 {
6679 int64_t ref;
6680 uint64_t duration;
6681
6682
2/2
✓ Branch 0 taken 38116 times.
✓ Branch 1 taken 733 times.
38849 if (trk->entry) {
6683 38116 ref = trk->cluster[trk->entry - 1].dts;
6684
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 546 times.
733 } else if ( trk->start_dts != AV_NOPTS_VALUE
6685
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 8 times.
187 && !trk->frag_discont) {
6686 179 ref = trk->start_dts + trk->track_duration;
6687 } else
6688 554 ref = pkt->dts; // Skip tests for the first packet
6689
6690
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 34794 times.
38849 if (trk->dts_shift != AV_NOPTS_VALUE) {
6691 /* With negative CTS offsets we have set an offset to the DTS,
6692 * reverse this for the check. */
6693 4055 ref -= trk->dts_shift;
6694 }
6695
6696 38849 duration = pkt->dts - ref;
6697
2/4
✓ Branch 0 taken 38849 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38849 times.
38849 if (pkt->dts < ref || duration >= INT_MAX) {
6698 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6699 duration, pkt->dts, pkt->stream_index);
6700
6701 pkt->dts = ref + 1;
6702 pkt->pts = AV_NOPTS_VALUE;
6703 }
6704
6705
2/4
✓ Branch 0 taken 38849 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38849 times.
38849 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6706 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6707 return AVERROR(EINVAL);
6708 }
6709 38849 return 0;
6710 }
6711
6712 19443 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6713 {
6714 19443 MOVMuxContext *mov = s->priv_data;
6715 19443 AVIOContext *pb = s->pb;
6716 MOVTrack *trk;
6717 AVCodecParameters *par;
6718 AVProducerReferenceTime *prft;
6719 19443 unsigned int samples_in_chunk = 0;
6720 19443 int size = pkt->size, ret = 0, offset = 0;
6721 size_t prft_size;
6722 19443 uint8_t *reformatted_data = NULL;
6723
6724
2/2
✓ Branch 0 taken 19397 times.
✓ Branch 1 taken 46 times.
19443 if (pkt->stream_index < s->nb_streams)
6725 19397 trk = s->streams[pkt->stream_index]->priv_data;
6726 else // Timecode or chapter
6727 46 trk = &mov->tracks[pkt->stream_index];
6728 19443 par = trk->par;
6729
6730 19443 ret = check_pkt(s, trk, pkt);
6731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19443 times.
19443 if (ret < 0)
6732 return ret;
6733
6734
2/2
✓ Branch 0 taken 18841 times.
✓ Branch 1 taken 602 times.
19443 if (pkt->pts != AV_NOPTS_VALUE &&
6735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18841 times.
18841 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
6736 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6737 return AVERROR_PATCHWELCOME;
6738 }
6739
6740
3/4
✓ Branch 0 taken 12849 times.
✓ Branch 1 taken 6594 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12849 times.
19443 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6741 int ret;
6742
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) {
6743
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) {
6744
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6745
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6746 return ret;
6747 }
6748 }
6749
6750
2/2
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 6098 times.
6356 if (!trk->mdat_buf) {
6751
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 258 times.
258 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6752 return ret;
6753 }
6754 6356 pb = trk->mdat_buf;
6755 } else {
6756
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6757
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6758 return ret;
6759 }
6760 238 pb = mov->mdat_buf;
6761 }
6762 }
6763
6764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19443 times.
19443 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6765 /* We must find out how many AMR blocks there are in one packet */
6766 static const uint16_t packed_size[16] =
6767 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6768 int len = 0;
6769
6770 while (len < size && samples_in_chunk < 100) {
6771 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6772 samples_in_chunk++;
6773 }
6774 if (samples_in_chunk > 1) {
6775 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6776 return -1;
6777 }
6778
1/2
✓ Branch 0 taken 19443 times.
✗ Branch 1 not taken.
19443 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19443 times.
19443 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6780 samples_in_chunk = trk->par->frame_size;
6781
2/2
✓ Branch 0 taken 1384 times.
✓ Branch 1 taken 18059 times.
19443 } else if (trk->sample_size)
6782 1384 samples_in_chunk = size / trk->sample_size;
6783 else
6784 18059 samples_in_chunk = 1;
6785
6786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19443 times.
19443 if (samples_in_chunk < 1) {
6787 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6788 return AVERROR_PATCHWELCOME;
6789 }
6790
6791 /* copy extradata if it exists */
6792
3/4
✓ Branch 0 taken 6642 times.
✓ Branch 1 taken 12801 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6642 times.
19443 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
6793 !TAG_IS_AVCI(trk->tag) &&
6794 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6795 trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
6796 if (!trk->extradata[0]) {
6797 ret = AVERROR(ENOMEM);
6798 goto err;
6799 }
6800 trk->extradata_size[0] = par->extradata_size;
6801 }
6802
6803
2/2
✓ Branch 0 taken 19328 times.
✓ Branch 1 taken 115 times.
19443 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6804
2/2
✓ Branch 0 taken 16736 times.
✓ Branch 1 taken 2592 times.
19328 par->codec_id == AV_CODEC_ID_H264 ||
6805
2/2
✓ Branch 0 taken 16581 times.
✓ Branch 1 taken 155 times.
16736 par->codec_id == AV_CODEC_ID_HEVC ||
6806
2/2
✓ Branch 0 taken 16571 times.
✓ Branch 1 taken 10 times.
16581 par->codec_id == AV_CODEC_ID_VVC ||
6807
1/2
✓ Branch 0 taken 16571 times.
✗ Branch 1 not taken.
16571 par->codec_id == AV_CODEC_ID_VP9 ||
6808
2/2
✓ Branch 0 taken 16271 times.
✓ Branch 1 taken 300 times.
16571 par->codec_id == AV_CODEC_ID_EVC ||
6809
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16271 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3148 times.
19443 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
6810
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)) {
6811 /* copy frame to create needed atoms */
6812 24 trk->extradata_size[0] = size;
6813 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
6815 ret = AVERROR(ENOMEM);
6816 goto err;
6817 }
6818 24 memcpy(trk->extradata[0], pkt->data, size);
6819 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6820 }
6821
6822 19443 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
6823
4/6
✓ Branch 0 taken 19443 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 19441 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
19443 if (pkt->size && sd && sd->size > 0) {
6824 int i;
6825
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < trk->stsd_count; i++) {
6826
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))
6827 1 break;
6828 }
6829
6830
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (i < trk->stsd_count)
6831 1 trk->last_stsd_index = i;
6832
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (trk->stsd_count <= INT_MAX - 1) {
6833 1 int new_count = trk->stsd_count + 1;
6834 1 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
6835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!extradata)
6836 return AVERROR(ENOMEM);
6837 1 trk->extradata = extradata;
6838
6839 1 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
6840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!extradata_size)
6841 return AVERROR(ENOMEM);
6842 1 trk->extradata_size = extradata_size;
6843
6844 1 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
6845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!trk->extradata[trk->stsd_count])
6846 return AVERROR(ENOMEM);
6847
6848 1 trk->extradata_size[trk->stsd_count] = sd->size;
6849 1 trk->last_stsd_index = trk->stsd_count;
6850 1 trk->stsd_count = new_count;
6851 } else
6852 return AVERROR(ENOMEM);
6853 }
6854
6855
3/4
✓ Branch 0 taken 5584 times.
✓ Branch 1 taken 13859 times.
✓ Branch 2 taken 5584 times.
✗ Branch 3 not taken.
19443 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5584 times.
5584 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6857 if (!trk->st->nb_frames) {
6858 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6859 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6860 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6861 return -1;
6862 }
6863 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6864 }
6865
3/4
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 16851 times.
✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
19443 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
6866
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)) {
6867 /* from x264 or from bytestream H.264 */
6868 /* NAL reformatting needed */
6869
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) {
6870 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6871 &size);
6872 if (ret < 0)
6873 return ret;
6874 avio_write(pb, reformatted_data, size);
6875 } else {
6876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6877 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6878 if (size < 0) {
6879 ret = size;
6880 goto err;
6881 }
6882 } else {
6883 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6884 }
6885 }
6886
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 18790 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
18945 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
6887
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
299 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
6888 /* extradata is Annex B, assume the bitstream is too and convert it */
6889 144 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6890
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
144 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6891 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6892 &size, filter_ps, NULL);
6893 if (ret < 0)
6894 return ret;
6895 avio_write(pb, reformatted_data, size);
6896 } else {
6897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6898 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6899 if (size < 0) {
6900 ret = size;
6901 goto err;
6902 }
6903 } else {
6904 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6905 }
6906 }
6907
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 18791 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
18801 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
6908
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
6909 /* extradata is Annex B, assume the bitstream is too and convert it */
6910
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) {
6911 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6912 &size, 0, NULL);
6913 if (ret < 0)
6914 return ret;
6915 avio_write(pb, reformatted_data, size);
6916 } else {
6917 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6918 }
6919
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18787 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
18791 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
6920
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) {
6921 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6922 &size, &offset);
6923 if (ret < 0)
6924 return ret;
6925 avio_write(pb, reformatted_data, size);
6926 } else {
6927 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6928
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]) {
6929 mov->avif_extent_length[pkt->stream_index] = size;
6930 }
6931 }
6932
6933
2/2
✓ Branch 0 taken 18400 times.
✓ Branch 1 taken 387 times.
18787 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6934
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 17748 times.
18400 par->codec_id == AV_CODEC_ID_EAC3) {
6935 1039 size = handle_eac3(mov, pkt, trk);
6936
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6937 return size;
6938
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6939 1 goto end;
6940 1038 avio_write(pb, pkt->data, size);
6941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17748 times.
17748 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6942 size = 8;
6943
6944 for (int i = 0; i < pkt->size; i += 3) {
6945 if (pkt->data[i] == 0xFC) {
6946 size += 2;
6947 }
6948 }
6949 avio_wb32(pb, size);
6950 ffio_wfourcc(pb, "cdat");
6951 for (int i = 0; i < pkt->size; i += 3) {
6952 if (pkt->data[i] == 0xFC) {
6953 avio_w8(pb, pkt->data[i + 1]);
6954 avio_w8(pb, pkt->data[i + 2]);
6955 }
6956 }
6957
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 17745 times.
17748 } else if (par->codec_id == AV_CODEC_ID_APV) {
6958 3 ff_isom_parse_apvc(trk->apv, pkt, s);
6959 3 avio_wb32(s->pb, pkt->size);
6960 3 size += 4;
6961
6962 3 avio_write(s->pb, pkt->data, pkt->size);
6963 } else {
6964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17745 times.
17745 if (trk->cenc.aes_ctr) {
6965 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
6966 int extradata_size = trk->extradata_size[trk->last_stsd_index];
6967 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
6968 int nal_size_length = (extradata[4] & 0x3) + 1;
6969 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6970 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
6971 int nal_size_length = (extradata[21] & 0x3) + 1;
6972 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6973 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6974 ret = AVERROR_PATCHWELCOME;
6975 } else if(par->codec_id == AV_CODEC_ID_AV1) {
6976 av_assert0(size == pkt->size);
6977 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
6978 if (ret > 0) {
6979 size = ret;
6980 ret = 0;
6981 }
6982 } else {
6983 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6984 }
6985
6986 if (ret) {
6987 goto err;
6988 }
6989 } else {
6990 17745 avio_write(pb, pkt->data, size);
6991 }
6992 }
6993
6994
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 19158 times.
19442 if (trk->entry >= trk->cluster_capacity) {
6995 284 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6996 284 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 284 times.
284 if (!cluster) {
6998 ret = AVERROR(ENOMEM);
6999 goto err;
7000 }
7001 284 trk->cluster = cluster;
7002 284 trk->cluster_capacity = new_capacity;
7003 }
7004
7005 19442 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7006 19442 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7007 19442 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7008 19442 trk->cluster[trk->entry].chunkNum = 0;
7009 19442 trk->cluster[trk->entry].size = size;
7010 19442 trk->cluster[trk->entry].entries = samples_in_chunk;
7011 19442 trk->cluster[trk->entry].dts = pkt->dts;
7012 19442 trk->cluster[trk->entry].pts = pkt->pts;
7013
2/2
✓ Branch 0 taken 19414 times.
✓ Branch 1 taken 28 times.
19442 if (!trk->squash_fragment_samples_to_one &&
7014
4/4
✓ Branch 0 taken 366 times.
✓ Branch 1 taken 19048 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 266 times.
19414 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7015
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 4 times.
100 if (!trk->frag_discont) {
7016 /* First packet of a new fragment. We already wrote the duration
7017 * of the last packet of the previous fragment based on track_duration,
7018 * which might not exactly match our dts. Therefore adjust the dts
7019 * of this packet to be what the previous packets duration implies. */
7020 96 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7021 /* We also may have written the pts and the corresponding duration
7022 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7023 * the next fragment. This means the cts of the first sample must
7024 * be the same in all fragments, unless end_pts was updated by
7025 * the packet causing the fragment to be written. */
7026
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 82 times.
96 if ((mov->flags & FF_MOV_FLAG_DASH &&
7027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7028
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 60 times.
82 mov->mode == MODE_ISM)
7029 36 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7030 } else {
7031 /* New fragment, but discontinuous from previous fragments.
7032 * Pretend the duration sum of the earlier fragments is
7033 * pkt->dts - trk->start_dts. */
7034 4 trk->end_pts = AV_NOPTS_VALUE;
7035 4 trk->frag_discont = 0;
7036 }
7037 }
7038
7039
6/6
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 19048 times.
✓ Branch 2 taken 270 times.
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 234 times.
19442 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7040
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 15 times.
36 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7041 /* Not using edit lists and shifting the first track to start from zero.
7042 * If the other streams start from a later timestamp, we won't be able
7043 * to signal the difference in starting time without an edit list.
7044 * Thus move the timestamp for this first sample to 0, increasing
7045 * its duration instead. */
7046 21 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7047 }
7048
2/2
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 19193 times.
19442 if (trk->start_dts == AV_NOPTS_VALUE) {
7049 249 trk->start_dts = pkt->dts;
7050
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 243 times.
249 if (trk->frag_discont) {
7051
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7052 /* Pretend the whole stream started at pts=0, with earlier fragments
7053 * already written. If the stream started at pts=0, the duration sum
7054 * of earlier fragments would have been pkt->pts. */
7055 4 trk->start_dts = pkt->dts - pkt->pts;
7056 } else {
7057 /* Pretend the whole stream started at dts=0, with earlier fragments
7058 * already written, with a duration summing up to pkt->dts. */
7059 2 trk->start_dts = 0;
7060 }
7061 6 trk->frag_discont = 0;
7062
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 31 times.
243 } else if (pkt->dts && mov->moov_written)
7063 2 av_log(s, AV_LOG_WARNING,
7064 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7065 "already has been written. Set the delay_moov flag to handle "
7066 "this case.\n",
7067 pkt->stream_index, pkt->dts);
7068 }
7069 19442 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7070 19442 trk->last_sample_is_subtitle_end = 0;
7071
7072
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 18840 times.
19442 if (pkt->pts == AV_NOPTS_VALUE) {
7073 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7074 602 pkt->pts = pkt->dts;
7075 }
7076
2/2
✓ Branch 0 taken 1214 times.
✓ Branch 1 taken 18228 times.
19442 if (pkt->dts != pkt->pts)
7077 1214 trk->flags |= MOV_TRACK_CTTS;
7078 19442 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7079 19442 trk->cluster[trk->entry].flags = 0;
7080
5/6
✓ Branch 0 taken 19172 times.
✓ Branch 1 taken 270 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 19123 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 49 times.
19442 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7081 270 trk->start_cts = pkt->pts - pkt->dts;
7082
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 19168 times.
19442 if (trk->end_pts == AV_NOPTS_VALUE)
7083 274 trk->end_pts = trk->cluster[trk->entry].dts +
7084 274 trk->cluster[trk->entry].cts + pkt->duration;
7085 else
7086 19168 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7087 trk->cluster[trk->entry].cts +
7088 pkt->duration);
7089
7090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19442 times.
19442 if (par->codec_id == AV_CODEC_ID_VC1) {
7091 mov_parse_vc1_frame(pkt, trk);
7092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19442 times.
19442 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7093 mov_parse_truehd_frame(pkt, trk);
7094
2/2
✓ Branch 0 taken 13650 times.
✓ Branch 1 taken 5792 times.
19442 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7095
4/4
✓ Branch 0 taken 6358 times.
✓ Branch 1 taken 7292 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6349 times.
13650 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7096
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7097 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7099 trk->flags |= MOV_TRACK_STPS;
7100 } else {
7101 13642 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7102 }
7103
1/2
✓ Branch 0 taken 13650 times.
✗ Branch 1 not taken.
13650 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7104 13650 trk->has_keyframes++;
7105 }
7106
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 19435 times.
19442 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7107 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7108 7 trk->has_disposable++;
7109 }
7110
7111 19442 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7112
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19442 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
19442 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7113 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7114 else
7115 19442 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7116
7117 19442 trk->entry++;
7118 19442 trk->sample_count += samples_in_chunk;
7119 19442 mov->mdat_size += size;
7120
7121
3/4
✓ Branch 0 taken 19360 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
19442 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7122 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7124 : NULL, size);
7125
7126 19443 end:
7127 19443 err:
7128
7129
1/2
✓ Branch 0 taken 19443 times.
✗ Branch 1 not taken.
19443 if (pkt->data != reformatted_data)
7130 19443 av_free(reformatted_data);
7131 19443 return ret;
7132 }
7133
7134 19406 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7135 {
7136 19406 MOVMuxContext *mov = s->priv_data;
7137 19406 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7138 19406 AVCodecParameters *par = trk->par;
7139 19406 int64_t frag_duration = 0;
7140 19406 int size = pkt->size;
7141
7142 19406 int ret = check_pkt(s, trk, pkt);
7143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19406 times.
19406 if (ret < 0)
7144 return ret;
7145
7146
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 19401 times.
19406 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7147
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7148 10 mov->tracks[i].frag_discont = 1;
7149 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7150 }
7151
7152
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 17394 times.
19406 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7153
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7154 15 trk->dts_shift = pkt->pts - pkt->dts;
7155 2012 pkt->dts += trk->dts_shift;
7156 }
7157
7158
1/2
✓ Branch 0 taken 19406 times.
✗ Branch 1 not taken.
19406 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7159
2/2
✓ Branch 0 taken 13820 times.
✓ Branch 1 taken 5586 times.
19406 trk->par->codec_id == AV_CODEC_ID_AAC ||
7160
2/2
✓ Branch 0 taken 13816 times.
✓ Branch 1 taken 4 times.
13820 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7161
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 13761 times.
13816 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7162 size_t side_size;
7163 5645 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7164 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7165
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])) {
7166 6 void *newextra = av_memdup(side, side_size);
7167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7168 return AVERROR(ENOMEM);
7169 6 av_free(trk->extradata[trk->last_stsd_index]);
7170 6 trk->extradata[trk->last_stsd_index] = newextra;
7171 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7172 }
7173 }
7174
7175
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 19397 times.
19406 if (!pkt->size) {
7176
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) {
7177 4 trk->start_dts = pkt->dts;
7178
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7179 4 trk->start_cts = pkt->pts - pkt->dts;
7180 else
7181 trk->start_cts = 0;
7182 }
7183
7184 9 return 0; /* Discard 0 sized packets */
7185 }
7186
7187
4/4
✓ Branch 0 taken 19063 times.
✓ Branch 1 taken 334 times.
✓ Branch 2 taken 19039 times.
✓ Branch 3 taken 24 times.
19397 if (trk->entry && pkt->stream_index < mov->nb_streams)
7188 19039 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7189 19039 s->streams[pkt->stream_index]->time_base,
7190 19039 AV_TIME_BASE_Q);
7191
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 19136 times.
19397 if ((mov->max_fragment_duration &&
7192
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7193
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19393 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
19393 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7194
2/2
✓ Branch 0 taken 4875 times.
✓ Branch 1 taken 14518 times.
19393 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7195
2/2
✓ Branch 0 taken 2301 times.
✓ Branch 1 taken 2574 times.
4875 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7196
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) ||
7197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19344 times.
19344 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7198
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (frag_duration >= mov->min_fragment_duration) {
7199
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (trk->entry) {
7200 // Set the duration of this track to line up with the next
7201 // sample in this track. This avoids relying on AVPacket
7202 // duration, but only helps for this particular track, not
7203 // for the other ones that are flushed at the same time.
7204 //
7205 // If we have trk->entry == 0, no fragment will be written
7206 // for this track, and we can't adjust the track end here.
7207 53 trk->track_duration = pkt->dts - trk->start_dts;
7208
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (pkt->pts != AV_NOPTS_VALUE)
7209 53 trk->end_pts = pkt->pts;
7210 else
7211 trk->end_pts = pkt->dts;
7212 53 trk->end_reliable = 1;
7213 }
7214 53 mov_auto_flush_fragment(s, 0);
7215 }
7216 }
7217
7218 19397 return ff_mov_write_packet(s, pkt);
7219 }
7220
7221 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7222 int stream_index,
7223 int64_t dts) {
7224 3 MOVMuxContext *mov = s->priv_data;
7225 3 AVPacket *end = mov->pkt;
7226 3 uint8_t data[2] = {0};
7227 int ret;
7228
7229 3 end->size = sizeof(data);
7230 3 end->data = data;
7231 3 end->pts = dts;
7232 3 end->dts = dts;
7233 3 end->duration = 0;
7234 3 end->stream_index = stream_index;
7235
7236 3 ret = mov_write_single_packet(s, end);
7237 3 av_packet_unref(end);
7238
7239 3 return ret;
7240 }
7241
7242 #if CONFIG_IAMFENC
7243 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7244 {
7245 uint8_t *data;
7246 int ret;
7247
7248
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7249 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7251 return ret;
7252 }
7253
7254 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7255 275 s->streams[pkt->stream_index]->id, pkt);
7256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7257 return ret;
7258
7259
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7260 220 return AVERROR(EAGAIN);
7261
7262 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7263 55 trk->iamf_buf = NULL;
7264
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7266 // Either all or none of the packets for a single
7267 // IA Sample may be empty.
7268 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7269 "stream #%d\n", pkt->stream_index);
7270 ret = AVERROR_INVALIDDATA;
7271 }
7272 5 av_free(data);
7273 5 return ret;
7274 }
7275
7276 50 av_buffer_unref(&pkt->buf);
7277 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7279 av_free(data);
7280 return AVERROR(ENOMEM);
7281 }
7282 50 pkt->data = data;
7283 50 pkt->size = ret;
7284 50 pkt->stream_index = trk->first_iamf_idx;
7285
7286 50 return avio_open_dyn_buf(&trk->iamf_buf);
7287 }
7288 #endif
7289
7290 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7291 {
7292 2 int64_t pos = avio_tell(pb);
7293 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7294 2 const char *value = "";
7295
7296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7297
7298 2 avio_write_marker(pb,
7299 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7300 AVIO_DATA_MARKER_BOUNDARY_POINT);
7301
7302 2 avio_wb32(pb, 0); /* size */
7303 2 ffio_wfourcc(pb, "emsg");
7304 2 avio_w8(pb, 1); /* version */
7305 2 avio_wb24(pb, 0);
7306 2 avio_wb32(pb, st->time_base.den); /* timescale */
7307 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7308 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7309 2 avio_wb32(pb, 0); /* id */
7310 /* null terminated UTF8 strings */
7311 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7312 2 avio_write(pb, value, strlen(value) + 1);
7313 2 avio_write(pb, pkt->data, pkt->size);
7314
7315 2 return update_size(pb, pos);
7316 }
7317
7318 19784 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7319 {
7320 19784 MOVMuxContext *mov = s->priv_data;
7321 MOVTrack *trk;
7322
7323
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 19747 times.
19784 if (!pkt) {
7324 37 mov_flush_fragment(s, 1);
7325 37 return 1;
7326 }
7327
7328
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19745 times.
19747 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7329 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7330 2 return 0;
7331 }
7332
7333 19745 trk = s->streams[pkt->stream_index]->priv_data;
7334
7335 #if CONFIG_IAMFENC
7336
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 19470 times.
19745 if (trk->iamf) {
7337 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7338
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7339
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7340 220 return 0;
7341 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7342 "for stream #%d\n", trk->st->index);
7343 return ret;
7344 }
7345 }
7346 #endif
7347
7348
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 19523 times.
19525 if (is_cover_image(trk->st)) {
7349 int ret;
7350
7351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7352 if (trk->st->nb_frames == 1)
7353 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7354 " ignoring.\n", pkt->stream_index);
7355 return 0;
7356 }
7357
7358
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7359 return ret;
7360
7361 2 return 0;
7362 } else {
7363 int i;
7364
7365
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 19514 times.
19523 if (!pkt->size)
7366 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7367
7368 /*
7369 * Subtitles require special handling.
7370 *
7371 * 1) For full compliance, every track must have a sample at
7372 * dts == 0, which is rarely true for subtitles. So, as soon
7373 * as we see any packet with dts > 0, write an empty subtitle
7374 * at dts == 0 for any subtitle track with no samples in it.
7375 *
7376 * 2) For each subtitle track, check if the current packet's
7377 * dts is past the duration of the last subtitle sample. If
7378 * so, we now need to write an end sample for that subtitle.
7379 *
7380 * This must be done conditionally to allow for subtitles that
7381 * immediately replace each other, in which case an end sample
7382 * is not needed, and is, in fact, actively harmful.
7383 *
7384 * 3) See mov_write_trailer for how the final end sample is
7385 * handled.
7386 */
7387
2/2
✓ Branch 0 taken 35592 times.
✓ Branch 1 taken 19514 times.
55106 for (i = 0; i < mov->nb_tracks; i++) {
7388 35592 MOVTrack *trk = &mov->tracks[i];
7389 int ret;
7390
7391
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 35589 times.
35592 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7392
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7393
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)) {
7394 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7396 2 trk->last_sample_is_subtitle_end = 1;
7397 }
7398 }
7399
7400
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 19366 times.
19514 if (trk->squash_fragment_samples_to_one) {
7401 /*
7402 * If the track has to have its samples squashed into one sample,
7403 * we just take it into the track's queue.
7404 * This will then be utilized as the samples get written in either
7405 * mov_flush_fragment or when the mux is finalized in
7406 * mov_write_trailer.
7407 */
7408 148 int ret = AVERROR_BUG;
7409
7410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7411 av_log(s, AV_LOG_ERROR,
7412 "Packets without a valid presentation timestamp are "
7413 "not supported with packet squashing!\n");
7414 return AVERROR(EINVAL);
7415 }
7416
7417 /* The following will reset pkt and is only allowed to be used
7418 * because we return immediately. afterwards. */
7419
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7420 pkt, NULL, 0)) < 0) {
7421 return ret;
7422 }
7423
7424 148 return 0;
7425 }
7426
7427
7428
4/4
✓ Branch 0 taken 7827 times.
✓ Branch 1 taken 11539 times.
✓ Branch 2 taken 3704 times.
✓ Branch 3 taken 4123 times.
19366 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7429 3704 AVPacket *opkt = pkt;
7430 int reshuffle_ret, ret;
7431
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3679 times.
3704 if (trk->is_unaligned_qt_rgb) {
7432
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;
7433 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7434 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7436 return reshuffle_ret;
7437 } else
7438 3679 reshuffle_ret = 0;
7439
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3466 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3704 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7440 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7442 goto fail;
7443
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7444 5 trk->pal_done++;
7445
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2874 times.
3699 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7446
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7448 ret = av_packet_make_writable(pkt);
7449 if (ret < 0)
7450 goto fail;
7451 for (i = 0; i < pkt->size; i++)
7452 pkt->data[i] = ~pkt->data[i];
7453 }
7454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3704 times.
3704 if (reshuffle_ret) {
7455 ret = mov_write_single_packet(s, pkt);
7456 fail:
7457 if (reshuffle_ret)
7458 av_packet_free(&pkt);
7459 return ret;
7460 }
7461 }
7462
7463 19366 return mov_write_single_packet(s, pkt);
7464 }
7465 }
7466
7467 // QuickTime chapters involve an additional text track with the chapter names
7468 // as samples, and a tref pointing from the other tracks to the chapter one.
7469 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7470 {
7471 static const uint8_t stub_header[] = {
7472 // TextSampleEntry
7473 0x00, 0x00, 0x00, 0x01, // displayFlags
7474 0x00, 0x00, // horizontal + vertical justification
7475 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7476 // BoxRecord
7477 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7478 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7479 // StyleRecord
7480 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7481 0x00, 0x01, // fontID
7482 0x00, 0x00, // fontStyleFlags + fontSize
7483 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7484 // FontTableBox
7485 0x00, 0x00, 0x00, 0x0D, // box size
7486 'f', 't', 'a', 'b', // box atom name
7487 0x00, 0x01, // entry count
7488 // FontRecord
7489 0x00, 0x01, // font ID
7490 0x00, // font name length
7491 };
7492 1 MOVMuxContext *mov = s->priv_data;
7493 1 MOVTrack *track = &mov->tracks[tracknum];
7494 1 AVPacket *pkt = mov->pkt;
7495 int i, len;
7496 int ret;
7497
7498 1 track->mode = mov->mode;
7499 1 track->tag = MKTAG('t','e','x','t');
7500 1 track->timescale = mov->movie_timescale;
7501 1 track->par = avcodec_parameters_alloc();
7502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7503 return AVERROR(ENOMEM);
7504 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7505 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7506
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7507 return ret;
7508 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7509
7510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7511 track->stsd_count = 1;
7512 track->extradata = av_calloc(1, sizeof(*track->extradata));
7513 track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7514 if (!track->extradata || !track->extradata_size)
7515 return AVERROR(ENOMEM);
7516 }
7517
7518 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7520 return AVERROR(ENOMEM);
7521 1 track->extradata_size[0] = sizeof(stub_header);
7522
7523 1 pkt->stream_index = tracknum;
7524 1 pkt->flags = AV_PKT_FLAG_KEY;
7525
7526
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7527 4 AVChapter *c = s->chapters[i];
7528 AVDictionaryEntry *t;
7529
7530 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7531 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7532 4 pkt->duration = end - pkt->dts;
7533
7534
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7535 static const char encd[12] = {
7536 0x00, 0x00, 0x00, 0x0C,
7537 'e', 'n', 'c', 'd',
7538 0x00, 0x00, 0x01, 0x00 };
7539 4 len = strlen(t->value);
7540 4 pkt->size = len + 2 + 12;
7541 4 pkt->data = av_malloc(pkt->size);
7542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7543 av_packet_unref(pkt);
7544 return AVERROR(ENOMEM);
7545 }
7546 4 AV_WB16(pkt->data, len);
7547 4 memcpy(pkt->data + 2, t->value, len);
7548 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7549 4 ff_mov_write_packet(s, pkt);
7550 4 av_freep(&pkt->data);
7551 }
7552 }
7553
7554 1 av_packet_unref(mov->pkt);
7555
7556 1 return 0;
7557 }
7558
7559
7560 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7561 {
7562 int ret;
7563
7564 /* compute the frame number */
7565 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7566 13 return ret;
7567 }
7568
7569 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7570 {
7571 6 MOVMuxContext *mov = s->priv_data;
7572 6 MOVTrack *track = &mov->tracks[index];
7573 6 AVStream *src_st = mov->tracks[src_index].st;
7574 uint8_t data[4];
7575 6 AVPacket *pkt = mov->pkt;
7576 6 AVRational rate = src_st->avg_frame_rate;
7577 int ret;
7578
7579 /* tmcd track based on video stream */
7580 6 track->mode = mov->mode;
7581 6 track->tag = MKTAG('t','m','c','d');
7582 6 track->src_track = src_index;
7583 6 track->timescale = mov->tracks[src_index].timescale;
7584
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7585 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7586
7587 /* set st to src_st for metadata access*/
7588 6 track->st = src_st;
7589
7590 /* encode context: tmcd data stream */
7591 6 track->par = avcodec_parameters_alloc();
7592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7593 return AVERROR(ENOMEM);
7594 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7595 6 track->par->codec_tag = track->tag;
7596 6 track->st->avg_frame_rate = rate;
7597
7598 /* the tmcd track just contains one packet with the frame number */
7599 6 pkt->data = data;
7600 6 pkt->stream_index = index;
7601 6 pkt->flags = AV_PKT_FLAG_KEY;
7602 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7603 6 pkt->size = 4;
7604 6 AV_WB32(pkt->data, tc.start);
7605 6 ret = ff_mov_write_packet(s, pkt);
7606 6 av_packet_unref(pkt);
7607 6 return ret;
7608 }
7609
7610 /*
7611 * st->disposition controls the "enabled" flag in the tkhd tag.
7612 * QuickTime will not play a track if it is not enabled. So make sure
7613 * that one track of each type (audio, video, subtitle) is enabled.
7614 *
7615 * Subtitles are special. For audio and video, setting "enabled" also
7616 * makes the track "default" (i.e. it is rendered when played). For
7617 * subtitles, an "enabled" subtitle is not rendered by default, but
7618 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7619 * empty!
7620 */
7621 216 static void enable_tracks(AVFormatContext *s)
7622 {
7623 216 MOVMuxContext *mov = s->priv_data;
7624 int i;
7625 int enabled[AVMEDIA_TYPE_NB];
7626 int first[AVMEDIA_TYPE_NB];
7627
7628
2/2
✓ Branch 0 taken 1080 times.
✓ Branch 1 taken 216 times.
1296 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7629 1080 enabled[i] = 0;
7630 1080 first[i] = -1;
7631 }
7632
7633
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 216 times.
494 for (i = 0; i < mov->nb_streams; i++) {
7634 278 AVStream *st = mov->tracks[i].st;
7635
7636
1/2
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
278 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7637
3/4
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 276 times.
556 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7638 278 is_cover_image(st))
7639 2 continue;
7640
7641
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 15 times.
276 if (first[st->codecpar->codec_type] < 0)
7642 261 first[st->codecpar->codec_type] = i;
7643
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 244 times.
276 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7644 32 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7645 32 enabled[st->codecpar->codec_type]++;
7646 }
7647 }
7648
7649
2/2
✓ Branch 0 taken 1080 times.
✓ Branch 1 taken 216 times.
1296 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7650
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 432 times.
1080 switch (i) {
7651 648 case AVMEDIA_TYPE_VIDEO:
7652 case AVMEDIA_TYPE_AUDIO:
7653 case AVMEDIA_TYPE_SUBTITLE:
7654
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 647 times.
648 if (enabled[i] > 1)
7655 1 mov->per_stream_grouping = 1;
7656
4/4
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 232 times.
✓ Branch 3 taken 389 times.
648 if (!enabled[i] && first[i] >= 0)
7657 232 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7658 648 break;
7659 }
7660 }
7661 216 }
7662
7663 216 static void mov_free(AVFormatContext *s)
7664 {
7665 216 MOVMuxContext *mov = s->priv_data;
7666
7667
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 216 times.
515 for (int i = 0; i < s->nb_streams; i++)
7668 299 s->streams[i]->priv_data = NULL;
7669
7670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (!mov->tracks)
7671 return;
7672
7673
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->chapter_track) {
7674 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7675 }
7676
7677
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 216 times.
503 for (int i = 0; i < mov->nb_tracks; i++) {
7678 287 MOVTrack *const track = &mov->tracks[i];
7679
7680
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 285 times.
287 if (track->tag == MKTAG('r','t','p',' '))
7681 2 ff_mov_close_hinting(track);
7682
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 276 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
285 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7683 6 av_freep(&track->par);
7684 287 av_freep(&track->cluster);
7685 287 av_freep(&track->cluster_written);
7686 287 av_freep(&track->frag_info);
7687 287 av_packet_free(&track->cover_image);
7688
7689
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
287 if (track->eac3_priv) {
7690 5 struct eac3_info *info = track->eac3_priv;
7691 5 av_packet_free(&info->pkt);
7692 5 av_freep(&track->eac3_priv);
7693 }
7694
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 287 times.
575 for (int j = 0; j < track->stsd_count; j++)
7695 288 av_freep(&track->extradata[j]);
7696 287 av_freep(&track->extradata);
7697 287 av_freep(&track->extradata_size);
7698
7699 287 ff_mov_cenc_free(&track->cenc);
7700 287 ffio_free_dyn_buf(&track->mdat_buf);
7701
7702 #if CONFIG_IAMFENC
7703 287 ffio_free_dyn_buf(&track->iamf_buf);
7704
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
287 if (track->iamf)
7705 5 ff_iamf_uninit_context(track->iamf);
7706 287 av_freep(&track->iamf);
7707 #endif
7708 287 ff_isom_close_apvc(&track->apv);
7709
7710 287 avpriv_packet_list_free(&track->squashed_packet_queue);
7711 }
7712
7713 216 av_freep(&mov->tracks);
7714 216 ffio_free_dyn_buf(&mov->mdat_buf);
7715 }
7716
7717 static uint32_t rgb_to_yuv(uint32_t rgb)
7718 {
7719 uint8_t r, g, b;
7720 int y, cb, cr;
7721
7722 r = (rgb >> 16) & 0xFF;
7723 g = (rgb >> 8) & 0xFF;
7724 b = (rgb ) & 0xFF;
7725
7726 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7727 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7728 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7729
7730 return (y << 16) | (cr << 8) | cb;
7731 }
7732
7733 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7734 AVStream *st)
7735 {
7736 int i, width = 720, height = 480;
7737 int have_palette = 0, have_size = 0;
7738 uint32_t palette[16];
7739 char *cur = track->extradata[track->last_stsd_index];
7740
7741 while (cur && *cur) {
7742 if (strncmp("palette:", cur, 8) == 0) {
7743 int i, count;
7744 count = sscanf(cur + 8,
7745 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7746 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7747 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7748 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7749 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7750 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7751 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7752 &palette[12], &palette[13], &palette[14], &palette[15]);
7753
7754 for (i = 0; i < count; i++) {
7755 palette[i] = rgb_to_yuv(palette[i]);
7756 }
7757 have_palette = 1;
7758 } else if (!strncmp("size:", cur, 5)) {
7759 sscanf(cur + 5, "%dx%d", &width, &height);
7760 have_size = 1;
7761 }
7762 if (have_palette && have_size)
7763 break;
7764 cur += strcspn(cur, "\n\r");
7765 cur += strspn(cur, "\n\r");
7766 }
7767 if (have_palette) {
7768 track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7769 if (!track->extradata[track->last_stsd_index])
7770 return AVERROR(ENOMEM);
7771 for (i = 0; i < 16; i++) {
7772 AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
7773 }
7774 memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7775 track->extradata_size[track->last_stsd_index] = 16 * 4;
7776 }
7777 st->codecpar->width = width;
7778 st->codecpar->height = track->height = height;
7779
7780 return 0;
7781 }
7782
7783 #if CONFIG_IAMFENC
7784 216 static int mov_init_iamf_track(AVFormatContext *s)
7785 {
7786 216 MOVMuxContext *mov = s->priv_data;
7787 MOVTrack *track;
7788 IAMFContext *iamf;
7789 216 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7790 216 int nb_audio_elements = 0, nb_mix_presentations = 0;
7791 int ret;
7792
7793
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 216 times.
226 for (int i = 0; i < s->nb_stream_groups; i++) {
7794 10 const AVStreamGroup *stg = s->stream_groups[i];
7795
7796
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7797 5 nb_audio_elements++;
7798
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7799 5 nb_mix_presentations++;
7800 }
7801
7802
3/4
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 211 times.
✗ Branch 3 not taken.
216 if (!nb_audio_elements && !nb_mix_presentations)
7803 211 return 0;
7804
7805
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) {
7806 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7807 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7808 return AVERROR(EINVAL);
7809 }
7810
7811 5 iamf = av_mallocz(sizeof(*iamf));
7812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7813 return AVERROR(ENOMEM);
7814
7815
7816
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7817 10 const AVStreamGroup *stg = s->stream_groups[i];
7818
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7819 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7820
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7821 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7822 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7823 }
7824
7825 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7826 5 break;
7827 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7828 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7829 5 break;
7830 default:
7831 av_assert0(0);
7832 }
7833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7834 return ret;
7835 }
7836
7837 5 track = &mov->tracks[first_iamf_idx];
7838 5 track->iamf = iamf;
7839 5 track->first_iamf_idx = first_iamf_idx;
7840 5 track->last_iamf_idx = last_iamf_idx;
7841 5 track->tag = MKTAG('i','a','m','f');
7842
7843
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7844 10 AVStreamGroup *stg = s->stream_groups[i];
7845
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7846 5 continue;
7847
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7848 25 stg->streams[j]->priv_data = track;
7849 }
7850
7851 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7853 return ret;
7854
7855 5 return 0;
7856 }
7857 #endif
7858
7859 216 static int mov_init(AVFormatContext *s)
7860 {
7861 216 MOVMuxContext *mov = s->priv_data;
7862 216 int has_iamf = 0;
7863 int i, ret;
7864
7865 216 mov->fc = s;
7866 216 mov->pkt = ffformatcontext(s)->pkt;
7867
7868 /* Default mode == MP4 */
7869 216 mov->mode = MODE_MP4;
7870
7871 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7874
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 69 times.
216 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7875
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 68 times.
69 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7876
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
68 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7877
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 62 times.
67 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7880 #undef IS_MODE
7881
7882
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 198 times.
216 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7883 18 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7884
7885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (mov->mode == MODE_AVIF)
7886 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7887
7888 /* Set the FRAGMENT flag if any of the fragmentation methods are
7889 * enabled. */
7890
3/4
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 214 times.
✗ Branch 3 not taken.
216 if (mov->max_fragment_duration || mov->max_fragment_size ||
7891
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 184 times.
214 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7892 FF_MOV_FLAG_FRAG_KEYFRAME |
7893 FF_MOV_FLAG_FRAG_CUSTOM |
7894 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7895 32 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7896
7897
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 214 times.
216 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
7898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
7899 av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
7900 return AVERROR(EINVAL);
7901 }
7902
7903 /* Set other implicit flags immediately */
7904
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 214 times.
216 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7905 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7906
7907
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 211 times.
216 if (mov->mode == MODE_ISM)
7908 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7909 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7910
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 204 times.
216 if (mov->flags & FF_MOV_FLAG_DASH)
7911 12 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7912 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7913
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 214 times.
216 if (mov->flags & FF_MOV_FLAG_CMAF)
7914 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7915 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7916
7917
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 2 times.
216 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
7918 32 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7919 32 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7920 }
7921
7922
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
216 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
7923 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7924 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7925 }
7926
7927
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 213 times.
216 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7928 3 mov->reserved_moov_size = -1;
7929 }
7930
7931
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 7 times.
216 if (mov->use_editlist < 0) {
7932 209 mov->use_editlist = 1;
7933
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 178 times.
209 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7934
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16 times.
31 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7935 // If we can avoid needing an edit list by shifting the
7936 // tracks, prefer that over (trying to) write edit lists
7937 // in fragmented output.
7938
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
15 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7940 14 mov->use_editlist = 0;
7941 }
7942 }
7943
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 182 times.
216 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7944
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)
7945 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7946
7947
4/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 196 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 1 times.
216 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
7948
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7949 11 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7950
7951 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7952 * if the latter is set that's enough and omit_tfhd_offset doesn't
7953 * add anything extra on top of that. */
7954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7955 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7956 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7957
7958
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->frag_interleave &&
7959
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)) {
7960 av_log(s, AV_LOG_ERROR,
7961 "Sample interleaving in fragments is mutually exclusive with "
7962 "omit_tfhd_offset and separate_moof\n");
7963 return AVERROR(EINVAL);
7964 }
7965
7966 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7967 * is enabled, we don't support non-seekable output at all. */
7968
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 188 times.
216 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7969
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 ||
7970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7971 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7972 return AVERROR(EINVAL);
7973 }
7974
7975 /* AVIF output must have at most two video streams (one for YUV and one for
7976 * alpha). */
7977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (mov->mode == MODE_AVIF) {
7978 if (s->nb_streams > 2) {
7979 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7980 return AVERROR(EINVAL);
7981 }
7982 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7983 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7984 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7985 return AVERROR(EINVAL);
7986 }
7987 if (s->nb_streams > 1) {
7988 const AVPixFmtDescriptor *pixdesc =
7989 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7990 if (pixdesc->nb_components != 1) {
7991 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7992 return AVERROR(EINVAL);
7993 }
7994 }
7995 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7996 }
7997
7998 #if CONFIG_IAMFENC
7999
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 216 times.
226 for (i = 0; i < s->nb_stream_groups; i++) {
8000 10 AVStreamGroup *stg = s->stream_groups[i];
8001
8002
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8003 5 continue;
8004
8005
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8006 25 AVStream *st = stg->streams[j];
8007
8008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8009 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8010 "IAMF Audio Element\n", j);
8011 return AVERROR(EINVAL);
8012 }
8013 25 st->priv_data = st;
8014 }
8015 5 has_iamf = 1;
8016
8017
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
8018 5 mov->nb_tracks++;
8019 }
8020 #endif
8021
8022
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 216 times.
515 for (i = 0; i < s->nb_streams; i++) {
8023 299 AVStream *st = s->streams[i];
8024
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 274 times.
299 if (st->priv_data)
8025 25 continue;
8026 // Don't produce a track in the output file for timed ID3 streams.
8027
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 273 times.
274 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8028 // Leave priv_data set to NULL for these AVStreams that don't
8029 // have a corresponding track.
8030 1 continue;
8031 }
8032 273 st->priv_data = st;
8033 273 mov->nb_tracks++;
8034 }
8035
8036 216 mov->nb_streams = mov->nb_tracks;
8037
8038
4/4
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 209 times.
216 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8039 1 mov->chapter_track = mov->nb_tracks++;
8040
8041
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8042
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8043
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8044 2 mov->nb_tracks++;
8045 }
8046
8047
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 if (mov->write_btrt < 0) {
8048 216 mov->write_btrt = mov->mode == MODE_MP4;
8049 }
8050
8051
6/6
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 147 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 62 times.
216 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8052
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8053 212 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8054 NULL, 0);
8055
8056 /* +1 tmcd track for each video stream with a timecode */
8057
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 212 times.
504 for (i = 0; i < s->nb_streams; i++) {
8058 292 AVStream *st = s->streams[i];
8059 292 AVDictionaryEntry *t = global_tcr;
8060
4/4
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 7 times.
292 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8061
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 177 times.
177 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8062 AVTimecode tc;
8063 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8064
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8065 7 mov->nb_meta_tmcd++;
8066 }
8067 }
8068
8069 /* check if there is already a tmcd track to remux */
8070
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 205 times.
212 if (mov->nb_meta_tmcd) {
8071
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8072 13 AVStream *st = s->streams[i];
8073
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8074 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8075 "so timecode metadata are now ignored\n");
8076 3 mov->nb_meta_tmcd = 0;
8077 }
8078 }
8079 }
8080
8081 212 mov->nb_tracks += mov->nb_meta_tmcd;
8082 }
8083
8084 // Reserve an extra stream for chapters for the case where chapters
8085 // are written in the trailer
8086 216 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (!mov->tracks)
8088 return AVERROR(ENOMEM);
8089
8090
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 216 times.
503 for (i = 0; i < mov->nb_tracks; i++) {
8091 287 MOVTrack *track = &mov->tracks[i];
8092
8093 287 track->stsd_count = 1;
8094 287 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8095 287 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8096
2/4
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 287 times.
287 if (!track->extradata || !track->extradata_size)
8097 return AVERROR(ENOMEM);
8098 }
8099
8100
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
216 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8101 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8102 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8103
8104 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8105 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8106 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8107 return AVERROR(EINVAL);
8108 }
8109
8110 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8111 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8112 mov->encryption_kid_len, CENC_KID_SIZE);
8113 return AVERROR(EINVAL);
8114 }
8115 } else {
8116 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8117 mov->encryption_scheme_str);
8118 return AVERROR(EINVAL);
8119 }
8120 }
8121
8122 #if CONFIG_IAMFENC
8123 216 ret = mov_init_iamf_track(s);
8124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (ret < 0)
8125 return ret;
8126 #endif
8127
8128
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 216 times.
515 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8129 299 AVStream *st = s->streams[j];
8130
8131
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 273 times.
299 if (st != st->priv_data) {
8132
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8133 5 i += has_iamf--;
8134 26 continue;
8135 }
8136 273 st->priv_data = &mov->tracks[i++];
8137 }
8138
8139
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 216 times.
515 for (i = 0; i < s->nb_streams; i++) {
8140 299 AVStream *st= s->streams[i];
8141 299 MOVTrack *track = st->priv_data;
8142 299 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8143
8144
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 298 times.
299 if (!track)
8145 1 continue;
8146
8147
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 20 times.
298 if (!track->st) {
8148 278 track->st = st;
8149 278 track->par = st->codecpar;
8150 }
8151
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 270 times.
298 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8152
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 143 times.
298 if (track->language < 0)
8153 155 track->language = 32767; // Unspecified Macintosh language code
8154 298 track->mode = mov->mode;
8155
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 25 times.
298 if (!track->tag)
8156 273 track->tag = mov_find_codec_tag(s, track);
8157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 298 times.
298 if (!track->tag) {
8158 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8159 "codec not currently supported in container\n",
8160 avcodec_get_name(st->codecpar->codec_id), i);
8161 return AVERROR(EINVAL);
8162 }
8163 /* If hinting of this track is enabled by a later hint track,
8164 * this is updated. */
8165 298 track->hint_track = -1;
8166 298 track->start_dts = AV_NOPTS_VALUE;
8167 298 track->start_cts = AV_NOPTS_VALUE;
8168 298 track->end_pts = AV_NOPTS_VALUE;
8169 298 track->dts_shift = AV_NOPTS_VALUE;
8170
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 111 times.
298 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8171
2/4
✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
187 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8172
2/4
✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
187 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8173
2/4
✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187 times.
187 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8174 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8175 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8176 return AVERROR(EINVAL);
8177 }
8178 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8179 }
8180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187 times.
187 if (mov->video_track_timescale) {
8181 track->timescale = mov->video_track_timescale;
8182 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8183 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8184 } else {
8185 187 track->timescale = st->time_base.den;
8186
2/2
✓ Branch 0 taken 1494 times.
✓ Branch 1 taken 187 times.
1681 while(track->timescale < 10000)
8187 1494 track->timescale *= 2;
8188 }
8189
2/4
✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187 times.
187 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8190 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8191 return AVERROR(EINVAL);
8192 }
8193
4/4
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 130 times.
187 if (track->mode == MODE_MOV && track->timescale > 100000)
8194 2 av_log(s, AV_LOG_WARNING,
8195 "WARNING codec timebase is very high. If duration is too long,\n"
8196 "file may not be playable by quicktime. Specify a shorter timebase\n"
8197 "or choose different container.\n");
8198
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 55 times.
187 if (track->mode == MODE_MOV &&
8199
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 115 times.
132 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8200
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8201 1 enum AVPixelFormat pix_fmt = track->par->format;
8202
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)
8203 pix_fmt = AV_PIX_FMT_MONOWHITE;
8204 1 track->is_unaligned_qt_rgb =
8205 pix_fmt == AV_PIX_FMT_RGB24 ||
8206 pix_fmt == AV_PIX_FMT_BGR24 ||
8207 pix_fmt == AV_PIX_FMT_PAL8 ||
8208 pix_fmt == AV_PIX_FMT_GRAY8 ||
8209
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 ||
8210 pix_fmt == AV_PIX_FMT_MONOBLACK;
8211 }
8212
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 187 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
187 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8213 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8214 return AVERROR(EINVAL);
8215
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 186 times.
187 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8216
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) {
8217 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8218 return AVERROR(EINVAL);
8219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187 times.
187 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8220 /* altref frames handling is not defined in the spec as of version v1.0,
8221 * so just forbid muxing VP8 streams altogether until a new version does */
8222 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8223 return AVERROR_PATCHWELCOME;
8224
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 186 times.
187 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8225 1 ret = ff_isom_init_apvc(&track->apv, s);
8226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8227 return ret;
8228 }
8229
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 185 times.
187 if (is_cover_image(st)) {
8230 2 track->cover_image = av_packet_alloc();
8231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8232 return AVERROR(ENOMEM);
8233 }
8234
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 9 times.
111 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8235 102 track->timescale = st->codecpar->sample_rate;
8236
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)) {
8237 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8238 6 track->audio_vbr = 1;
8239
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8240
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8242 if (!st->codecpar->block_align) {
8243 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8244 return AVERROR(EINVAL);
8245 }
8246 track->sample_size = st->codecpar->block_align;
8247
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 26 times.
96 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8248 70 track->audio_vbr = 1;
8249 }else{
8250 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8251 26 st->codecpar->ch_layout.nb_channels;
8252 }
8253
1/2
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
102 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8255 track->audio_vbr = 1;
8256 }
8257
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 32 times.
102 if (track->mode != MODE_MOV &&
8258
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) {
8259 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8260 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8261 i, track->par->sample_rate);
8262 return AVERROR(EINVAL);
8263 } else {
8264 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8265 i, track->par->sample_rate);
8266 }
8267 }
8268
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 25 times.
102 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8269
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 track->par->codec_id == AV_CODEC_ID_OPUS) {
8271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8272 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8273 return AVERROR(EINVAL);
8274 }
8275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8276 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8277 av_log(s, AV_LOG_ERROR,
8278 "%s in MP4 support is experimental, add "
8279 "'-strict %d' if you want to use it.\n",
8280 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8281 return AVERROR_EXPERIMENTAL;
8282 }
8283 }
8284
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8285 5 track->timescale = st->time_base.den;
8286
8287
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8288 /* 14496-30 requires us to use a single sample per fragment
8289 for TTML, for which we define a per-track flag.
8290
8291 We set the flag in case we are receiving TTML paragraphs
8292 from the input, in other words in case we are not doing
8293 stream copy. */
8294 4 track->squash_fragment_samples_to_one =
8295 4 ff_is_ttml_stream_paragraph_based(track->par);
8296
8297
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8298
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8300 av_log(s, AV_LOG_ERROR,
8301 "ISMV style TTML support with the 'dfxp' tag in "
8302 "non-ISMV formats is not officially supported. Add "
8303 "'-strict unofficial' if you want to use it.\n");
8304 return AVERROR_EXPERIMENTAL;
8305 }
8306 }
8307
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8308 4 track->timescale = st->time_base.den;
8309 } else {
8310 track->timescale = mov->movie_timescale;
8311 }
8312
1/2
✓ Branch 0 taken 298 times.
✗ Branch 1 not taken.
298 if (!track->height)
8313 298 track->height = st->codecpar->height;
8314 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8315 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8316 for video tracks, so if user-set, it isn't overwritten */
8317
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 291 times.
298 if (mov->mode == MODE_ISM &&
8318
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8319
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))) {
8320 7 track->timescale = 10000000;
8321 }
8322
8323 298 avpriv_set_pts_info(st, 64, 1, track->timescale);
8324
8325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 298 times.
298 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8326 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8327 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8328 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8329 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8330 if (ret)
8331 return ret;
8332 }
8333 }
8334
8335 216 enable_tracks(s);
8336 216 return 0;
8337 }
8338
8339 216 static int mov_write_header(AVFormatContext *s)
8340 {
8341 216 AVIOContext *pb = s->pb;
8342 216 MOVMuxContext *mov = s->priv_data;
8343 216 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8344
8345
4/4
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 209 times.
216 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8346 1 nb_tracks++;
8347
8348
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8349 1 hint_track = nb_tracks;
8350
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8351
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8352 2 nb_tracks++;
8353 }
8354 }
8355
8356
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 210 times.
216 if (mov->nb_meta_tmcd)
8357 6 tmcd_track = nb_tracks;
8358
8359
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 216 times.
494 for (int i = 0; i < mov->nb_streams; i++) {
8360 278 MOVTrack *track = &mov->tracks[i];
8361 278 AVStream *st = track->st;
8362
8363 /* copy extradata if it exists */
8364
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 157 times.
278 if (st->codecpar->extradata_size) {
8365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8366 mov_create_dvd_sub_decoder_specific_info(track, st);
8367
15/30
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 121 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 121 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 121 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 121 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 121 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 121 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 121 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 121 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 121 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 121 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 121 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 121 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 121 times.
✗ Branch 29 not taken.
121 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8368 121 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8369 242 track->extradata[track->last_stsd_index] =
8370 121 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 if (!track->extradata[track->last_stsd_index]) {
8372 return AVERROR(ENOMEM);
8373 }
8374 121 memcpy(track->extradata[track->last_stsd_index],
8375 121 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8376 121 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8377 0, AV_INPUT_BUFFER_PADDING_SIZE);
8378 }
8379 }
8380
8381
4/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 196 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 14 times.
360 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8382 82 av_channel_layout_compare(&track->par->ch_layout,
8383 82 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8384 264 continue;
8385
8386
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8387 33 AVStream *stj= mov->tracks[j].st;
8388 33 MOVTrack *trackj= &mov->tracks[j];
8389
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8390 14 continue;
8391
8392
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8393
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 ||
8394 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8395 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8396 )
8397 4 track->mono_as_fc = -1;
8398
8399
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 &&
8400 11 av_channel_layout_compare(&trackj->par->ch_layout,
8401 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8402
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
8403 )
8404 7 track->mono_as_fc++;
8405
8406
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 ||
8407 11 av_channel_layout_compare(&trackj->par->ch_layout,
8408 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8409 trackj->language != track->language ||
8410 trackj->tag != track->tag
8411 )
8412 19 continue;
8413 track->multichannel_as_mono++;
8414 }
8415 }
8416
8417
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 198 times.
216 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8419
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
198 if ((ret = mov_write_identification(pb, s)) < 0)
8420 return ret;
8421 }
8422
8423
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 213 times.
216 if (mov->reserved_moov_size){
8424 3 mov->reserved_header_pos = avio_tell(pb);
8425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8426 avio_skip(pb, mov->reserved_moov_size);
8427 }
8428
8429
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 178 times.
216 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8430 /* If no fragmentation options have been set, set a default. */
8431
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 31 times.
38 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8432 FF_MOV_FLAG_FRAG_CUSTOM |
8433 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8434
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)
8435 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8436
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
38 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8437 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8438
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8439 2 mov->mdat_pos = avio_tell(pb);
8440 }
8441
1/2
✓ Branch 0 taken 178 times.
✗ Branch 1 not taken.
178 } else if (mov->mode != MODE_AVIF) {
8442
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 175 times.
178 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8443 3 mov->reserved_header_pos = avio_tell(pb);
8444 178 mov_write_mdat_tag(pb, mov);
8445 }
8446
8447 216 ff_parse_creation_time_metadata(s, &mov->time, 1);
8448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (mov->time)
8449 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8450
8451
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->chapter_track)
8452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8453 return ret;
8454
8455
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 215 times.
216 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8456
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8457
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8458
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8459 return ret;
8460 2 hint_track++;
8461 }
8462 }
8463 }
8464
8465
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 210 times.
216 if (mov->nb_meta_tmcd) {
8466 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8467 "timecode", NULL, 0);
8468 /* Initialize the tmcd tracks */
8469
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8470 8 AVStream *st = mov->tracks[i].st;
8471 8 t = global_tcr;
8472
8473
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8474 AVTimecode tc;
8475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8476 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8478 continue;
8479
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8480 continue;
8481
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8482 return ret;
8483 6 tmcd_track++;
8484 }
8485 }
8486 }
8487
8488 216 avio_flush(pb);
8489
8490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
216 if (mov->flags & FF_MOV_FLAG_ISML)
8491 mov_write_isml_manifest(pb, mov, s);
8492
8493
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 182 times.
216 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8494
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18 times.
34 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8495
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8496 return ret;
8497 16 mov->moov_written = 1;
8498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8499 mov->reserved_header_pos = avio_tell(pb);
8500 }
8501
8502 216 return 0;
8503 }
8504
8505 28 static int get_moov_size(AVFormatContext *s)
8506 {
8507 int ret;
8508 AVIOContext *moov_buf;
8509 28 MOVMuxContext *mov = s->priv_data;
8510
8511
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8512 return ret;
8513
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8514 return ret;
8515 28 return ffio_close_null_buf(moov_buf);
8516 }
8517
8518 static int get_sidx_size(AVFormatContext *s)
8519 {
8520 int ret;
8521 AVIOContext *buf;
8522 MOVMuxContext *mov = s->priv_data;
8523
8524 if ((ret = ffio_open_null_buf(&buf)) < 0)
8525 return ret;
8526 mov_write_sidx_tags(buf, mov, -1, 0);
8527 return ffio_close_null_buf(buf);
8528 }
8529
8530 /*
8531 * This function gets the moov size if moved to the top of the file: the chunk
8532 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8533 * entries) when the moov is moved to the beginning, so the size of the moov
8534 * would change. It also updates the chunk offset tables.
8535 */
8536 3 static int compute_moov_size(AVFormatContext *s)
8537 {
8538 int i, moov_size, moov_size2;
8539 3 MOVMuxContext *mov = s->priv_data;
8540
8541 3 moov_size = get_moov_size(s);
8542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8543 return moov_size;
8544
8545
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8546 8 mov->tracks[i].data_offset += moov_size;
8547
8548 3 moov_size2 = get_moov_size(s);
8549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8550 return moov_size2;
8551
8552 /* if the size changed, we just switched from stco to co64 and need to
8553 * update the offsets */
8554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8555 for (i = 0; i < mov->nb_tracks; i++)
8556 mov->tracks[i].data_offset += moov_size2 - moov_size;
8557
8558 3 return moov_size2;
8559 }
8560
8561 static int compute_sidx_size(AVFormatContext *s)
8562 {
8563 int i, sidx_size;
8564 MOVMuxContext *mov = s->priv_data;
8565
8566 sidx_size = get_sidx_size(s);
8567 if (sidx_size < 0)
8568 return sidx_size;
8569
8570 for (i = 0; i < mov->nb_tracks; i++)
8571 mov->tracks[i].data_offset += sidx_size;
8572
8573 return sidx_size;
8574 }
8575
8576 3 static int shift_data(AVFormatContext *s)
8577 {
8578 int moov_size;
8579 3 MOVMuxContext *mov = s->priv_data;
8580
8581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8582 moov_size = compute_sidx_size(s);
8583 else
8584 3 moov_size = compute_moov_size(s);
8585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8586 return moov_size;
8587
8588 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8589 }
8590
8591 180 static void mov_write_mdat_size(AVFormatContext *s)
8592 {
8593 180 MOVMuxContext *mov = s->priv_data;
8594 180 AVIOContext *pb = s->pb;
8595
8596 /* Write size of mdat tag */
8597
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (mov->mdat_size + 8 <= UINT32_MAX) {
8598 180 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8599 180 avio_wb32(pb, mov->mdat_size + 8);
8600
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8601 2 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8602 } else {
8603 /* overwrite 'wide' placeholder atom */
8604 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8605 /* special value: real atom size will be 64 bit value after
8606 * tag field */
8607 avio_wb32(pb, 1);
8608 ffio_wfourcc(pb, "mdat");
8609 avio_wb64(pb, mov->mdat_size + 16);
8610 }
8611 180 }
8612
8613 216 static int mov_write_trailer(AVFormatContext *s)
8614 {
8615 216 MOVMuxContext *mov = s->priv_data;
8616 216 AVIOContext *pb = s->pb;
8617 216 int res = 0;
8618 int i;
8619 int64_t moov_pos;
8620
8621 /*
8622 * Before actually writing the trailer, make sure that there are no
8623 * dangling subtitles, that need a terminating sample.
8624 */
8625
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 216 times.
503 for (i = 0; i < mov->nb_tracks; i++) {
8626 287 MOVTrack *trk = &mov->tracks[i];
8627
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 286 times.
287 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8628
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8629 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8630 1 trk->last_sample_is_subtitle_end = 1;
8631 }
8632 }
8633
8634 // Check if we have any tracks that require squashing.
8635 // In that case, we'll have to write the packet here.
8636
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
216 if ((res = mov_write_squashed_packets(s)) < 0)
8637 return res;
8638
8639 // If there were no chapters when the header was written, but there
8640 // are chapters now, write them in the trailer. This only works
8641 // when we are not doing fragments.
8642
4/4
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 38 times.
216 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
8643
3/4
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 176 times.
177 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
8644 mov->chapter_track = mov->nb_tracks++;
8645 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8646 return res;
8647 }
8648 }
8649
8650
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 178 times.
216 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8651
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
38 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8652
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8653 2 mov_auto_flush_fragment(s, 1);
8654 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8655
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
8656 4 MOVTrack *track = &mov->tracks[i];
8657 4 track->data_offset = 0;
8658 4 av_free(track->cluster);
8659 4 track->cluster = track->cluster_written;
8660 4 track->entry = track->entry_written;
8661 4 track->cluster_written = NULL;
8662 4 track->entry_written = 0;
8663 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8664 }
8665 // Clear the empty_moov flag, as we do want the moov to include
8666 // all the samples at this point.
8667 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8668 }
8669
8670 180 moov_pos = avio_tell(pb);
8671
8672
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 2 times.
180 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
8673 178 mov_write_mdat_size(s);
8674
8675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
8676
8677
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 177 times.
180 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8678 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8679 3 res = shift_data(s);
8680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8681 return res;
8682 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8683
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8684 return res;
8685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
177 } else if (mov->reserved_moov_size > 0) {
8686 int64_t size;
8687 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8688 return res;
8689 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8690 if (size < 8){
8691 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8692 return AVERROR(EINVAL);
8693 }
8694 avio_wb32(pb, size);
8695 ffio_wfourcc(pb, "free");
8696 ffio_fill(pb, 0, size - 8);
8697 avio_seek(pb, moov_pos, SEEK_SET);
8698 } else {
8699
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 177 times.
177 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8700 return res;
8701 }
8702
8703
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8704 // With hybrid fragmentation, only write the mdat size (hiding
8705 // the original moov and all the fragments within the mdat)
8706 // after we've successfully written the complete moov, to avoid
8707 // risk for an unreadable file if writing the final moov fails.
8708 2 mov_write_mdat_size(s);
8709 }
8710
8711 180 res = 0;
8712 } else {
8713 36 mov_auto_flush_fragment(s, 1);
8714
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 36 times.
104 for (i = 0; i < mov->nb_tracks; i++)
8715 68 mov->tracks[i].data_offset = 0;
8716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8717 int64_t end;
8718 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8719 res = shift_data(s);
8720 if (res < 0)
8721 return res;
8722 end = avio_tell(pb);
8723 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8724 mov_write_sidx_tags(pb, mov, -1, 0);
8725 avio_seek(pb, end, SEEK_SET);
8726 }
8727
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8728 36 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8729 36 res = mov_write_mfra_tag(pb, mov);
8730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (res < 0)
8731 return res;
8732 }
8733 }
8734
8735 216 return res;
8736 }
8737
8738 236 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8739 const AVPacket *pkt)
8740 {
8741 236 int ret = 1;
8742
8743
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 227 times.
236 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8744
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)
8745 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8747 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8748 }
8749
8750 236 return ret;
8751 }
8752
8753 #if CONFIG_AVIF_MUXER
8754 static int avif_write_trailer(AVFormatContext *s)
8755 {
8756 AVIOContext *pb = s->pb;
8757 MOVMuxContext *mov = s->priv_data;
8758 int64_t pos_backup, extent_offsets[2];
8759 uint8_t *buf;
8760 int buf_size, moov_size;
8761
8762 if (mov->moov_written) return 0;
8763
8764 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8765 if (mov->is_animated_avif && mov->nb_streams > 1) {
8766 // For animated avif with alpha channel, we need to write a tref tag
8767 // with type "auxl".
8768 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8769 mov->tracks[1].tref_id = 1;
8770 }
8771 mov_write_identification(pb, s);
8772 mov_write_meta_tag(pb, mov, s);
8773
8774 moov_size = get_moov_size(s);
8775 for (int i = 0; i < mov->nb_tracks; i++)
8776 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8777
8778 if (mov->is_animated_avif) {
8779 int ret;
8780 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8781 return ret;
8782 }
8783
8784 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8785 avio_wb32(pb, buf_size + 8);
8786 ffio_wfourcc(pb, "mdat");
8787
8788 // The offset for the YUV planes is the starting position of mdat.
8789 extent_offsets[0] = avio_tell(pb);
8790 // The offset for alpha plane is YUV offset + YUV size.
8791 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8792
8793 avio_write(pb, buf, buf_size);
8794
8795 // write extent offsets.
8796 pos_backup = avio_tell(pb);
8797 for (int i = 0; i < mov->nb_streams; i++) {
8798 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8799 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8800 return AVERROR_INVALIDDATA;
8801 }
8802 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8803 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8804 }
8805 avio_seek(pb, pos_backup, SEEK_SET);
8806
8807 return 0;
8808 }
8809 #endif
8810
8811 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8812 static const AVCodecTag codec_3gp_tags[] = {
8813 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8814 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8815 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8816 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8817 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8818 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8819 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8820 { AV_CODEC_ID_NONE, 0 },
8821 };
8822 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8823 #endif
8824
8825 static const AVCodecTag codec_mp4_tags[] = {
8826 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8827 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8828 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8829 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8830 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8831 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8832 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8833 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8834 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8835 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
8836 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8837 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8838 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8839 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8840 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8841 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8842 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8843 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8844 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8845 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8846 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8847 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8848 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8849 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8850 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8851 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8852 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8853 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8854 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8855 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8856 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8857 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8858 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8859 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8860 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8861 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8862 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8863 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8864 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8865 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8866 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8867
8868 /* ISO/IEC 23003-5 integer formats */
8869 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8870 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8871 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8872 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8873 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8874 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8875 /* ISO/IEC 23003-5 floating-point formats */
8876 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8877 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8878 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8879 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8880
8881 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
8882
8883 { AV_CODEC_ID_NONE, 0 },
8884 };
8885 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8886 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8887 #endif
8888
8889 static const AVCodecTag codec_ism_tags[] = {
8890 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8891 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8892 { AV_CODEC_ID_NONE , 0 },
8893 };
8894
8895 static const AVCodecTag codec_ipod_tags[] = {
8896 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8897 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8898 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8899 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8900 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8901 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8902 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8903 { AV_CODEC_ID_NONE, 0 },
8904 };
8905
8906 static const AVCodecTag codec_f4v_tags[] = {
8907 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8908 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8909 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8910 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8911 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8912 { AV_CODEC_ID_NONE, 0 },
8913 };
8914
8915 #if CONFIG_AVIF_MUXER
8916
8917 static const AVOption avif_options[] = {
8918 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8919 { "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 },
8920 { NULL },
8921 };
8922 static const AVCodecTag codec_avif_tags[] = {
8923 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8924 { AV_CODEC_ID_NONE, 0 },
8925 };
8926 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8927
8928 static const AVClass mov_avif_muxer_class = {
8929 .class_name = "avif muxer",
8930 .item_name = av_default_item_name,
8931 .option = avif_options,
8932 .version = LIBAVUTIL_VERSION_INT,
8933 };
8934 #endif
8935
8936 #if CONFIG_MOV_MUXER
8937 const FFOutputFormat ff_mov_muxer = {
8938 .p.name = "mov",
8939 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8940 .p.extensions = "mov",
8941 .priv_data_size = sizeof(MOVMuxContext),
8942 .p.audio_codec = AV_CODEC_ID_AAC,
8943 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8944 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8945 .init = mov_init,
8946 .write_header = mov_write_header,
8947 .write_packet = mov_write_packet,
8948 .write_trailer = mov_write_trailer,
8949 .deinit = mov_free,
8950 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8951 .p.codec_tag = (const AVCodecTag* const []){
8952 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8953 },
8954 .check_bitstream = mov_check_bitstream,
8955 .p.priv_class = &mov_isobmff_muxer_class,
8956 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8957 };
8958 #endif
8959 #if CONFIG_TGP_MUXER
8960 const FFOutputFormat ff_tgp_muxer = {
8961 .p.name = "3gp",
8962 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8963 .p.extensions = "3gp",
8964 .priv_data_size = sizeof(MOVMuxContext),
8965 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8966 .p.video_codec = AV_CODEC_ID_H263,
8967 .init = mov_init,
8968 .write_header = mov_write_header,
8969 .write_packet = mov_write_packet,
8970 .write_trailer = mov_write_trailer,
8971 .deinit = mov_free,
8972 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8973 .p.codec_tag = codec_3gp_tags_list,
8974 .check_bitstream = mov_check_bitstream,
8975 .p.priv_class = &mov_isobmff_muxer_class,
8976 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8977 };
8978 #endif
8979 #if CONFIG_MP4_MUXER
8980 const FFOutputFormat ff_mp4_muxer = {
8981 .p.name = "mp4",
8982 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8983 .p.mime_type = "video/mp4",
8984 .p.extensions = "mp4",
8985 .priv_data_size = sizeof(MOVMuxContext),
8986 .p.audio_codec = AV_CODEC_ID_AAC,
8987 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8988 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8989 .init = mov_init,
8990 .write_header = mov_write_header,
8991 .write_packet = mov_write_packet,
8992 .write_trailer = mov_write_trailer,
8993 .deinit = mov_free,
8994 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8995 .p.codec_tag = mp4_codec_tags_list,
8996 .check_bitstream = mov_check_bitstream,
8997 .p.priv_class = &mov_isobmff_muxer_class,
8998 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8999 };
9000 #endif
9001 #if CONFIG_PSP_MUXER
9002 const FFOutputFormat ff_psp_muxer = {
9003 .p.name = "psp",
9004 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9005 .p.extensions = "mp4,psp",
9006 .priv_data_size = sizeof(MOVMuxContext),
9007 .p.audio_codec = AV_CODEC_ID_AAC,
9008 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9009 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9010 .init = mov_init,
9011 .write_header = mov_write_header,
9012 .write_packet = mov_write_packet,
9013 .write_trailer = mov_write_trailer,
9014 .deinit = mov_free,
9015 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9016 .p.codec_tag = mp4_codec_tags_list,
9017 .check_bitstream = mov_check_bitstream,
9018 .p.priv_class = &mov_isobmff_muxer_class,
9019 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9020 };
9021 #endif
9022 #if CONFIG_TG2_MUXER
9023 const FFOutputFormat ff_tg2_muxer = {
9024 .p.name = "3g2",
9025 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9026 .p.extensions = "3g2",
9027 .priv_data_size = sizeof(MOVMuxContext),
9028 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9029 .p.video_codec = AV_CODEC_ID_H263,
9030 .init = mov_init,
9031 .write_header = mov_write_header,
9032 .write_packet = mov_write_packet,
9033 .write_trailer = mov_write_trailer,
9034 .deinit = mov_free,
9035 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9036 .p.codec_tag = codec_3gp_tags_list,
9037 .check_bitstream = mov_check_bitstream,
9038 .p.priv_class = &mov_isobmff_muxer_class,
9039 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9040 };
9041 #endif
9042 #if CONFIG_IPOD_MUXER
9043 const FFOutputFormat ff_ipod_muxer = {
9044 .p.name = "ipod",
9045 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9046 .p.mime_type = "video/mp4",
9047 .p.extensions = "m4v,m4a,m4b",
9048 .priv_data_size = sizeof(MOVMuxContext),
9049 .p.audio_codec = AV_CODEC_ID_AAC,
9050 .p.video_codec = AV_CODEC_ID_H264,
9051 .init = mov_init,
9052 .write_header = mov_write_header,
9053 .write_packet = mov_write_packet,
9054 .write_trailer = mov_write_trailer,
9055 .deinit = mov_free,
9056 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9057 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9058 .check_bitstream = mov_check_bitstream,
9059 .p.priv_class = &mov_isobmff_muxer_class,
9060 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9061 };
9062 #endif
9063 #if CONFIG_ISMV_MUXER
9064 const FFOutputFormat ff_ismv_muxer = {
9065 .p.name = "ismv",
9066 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9067 .p.mime_type = "video/mp4",
9068 .p.extensions = "ismv,isma",
9069 .priv_data_size = sizeof(MOVMuxContext),
9070 .p.audio_codec = AV_CODEC_ID_AAC,
9071 .p.video_codec = AV_CODEC_ID_H264,
9072 .init = mov_init,
9073 .write_header = mov_write_header,
9074 .write_packet = mov_write_packet,
9075 .write_trailer = mov_write_trailer,
9076 .deinit = mov_free,
9077 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9078 .p.codec_tag = (const AVCodecTag* const []){
9079 codec_mp4_tags, codec_ism_tags, 0 },
9080 .check_bitstream = mov_check_bitstream,
9081 .p.priv_class = &mov_isobmff_muxer_class,
9082 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9083 };
9084 #endif
9085 #if CONFIG_F4V_MUXER
9086 const FFOutputFormat ff_f4v_muxer = {
9087 .p.name = "f4v",
9088 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9089 .p.mime_type = "application/f4v",
9090 .p.extensions = "f4v",
9091 .priv_data_size = sizeof(MOVMuxContext),
9092 .p.audio_codec = AV_CODEC_ID_AAC,
9093 .p.video_codec = AV_CODEC_ID_H264,
9094 .init = mov_init,
9095 .write_header = mov_write_header,
9096 .write_packet = mov_write_packet,
9097 .write_trailer = mov_write_trailer,
9098 .deinit = mov_free,
9099 .p.flags = AVFMT_GLOBALHEADER,
9100 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9101 .check_bitstream = mov_check_bitstream,
9102 .p.priv_class = &mov_isobmff_muxer_class,
9103 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9104 };
9105 #endif
9106 #if CONFIG_AVIF_MUXER
9107 const FFOutputFormat ff_avif_muxer = {
9108 .p.name = "avif",
9109 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9110 .p.mime_type = "image/avif",
9111 .p.extensions = "avif",
9112 .priv_data_size = sizeof(MOVMuxContext),
9113 .p.video_codec = AV_CODEC_ID_AV1,
9114 .init = mov_init,
9115 .write_header = mov_write_header,
9116 .write_packet = mov_write_packet,
9117 .write_trailer = avif_write_trailer,
9118 .deinit = mov_free,
9119 .p.flags = AVFMT_GLOBALHEADER,
9120 .p.codec_tag = codec_avif_tags_list,
9121 .p.priv_class = &mov_avif_muxer_class,
9122 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9123 };
9124 #endif
9125