FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2026-10-10 04:53:52
Exec Total Coverage
Lines: 4008 5875 68.2%
Functions: 190 243 78.2%
Branches: 2401 4057 59.2%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <math.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29
30 #include "movenc.h"
31 #include "avformat.h"
32 #include "avio_internal.h"
33 #include "dovi_isom.h"
34 #include "riff.h"
35 #include "avio.h"
36 #include "iamf_writer.h"
37 #include "isom.h"
38 #include "av1.h"
39 #include "avc.h"
40 #include "evc.h"
41 #include "apv.h"
42 #include "lcevc.h"
43 #include "libavcodec/ac3_parser_internal.h"
44 #include "libavcodec/dnxhddata.h"
45 #include "libavcodec/flac.h"
46 #include "libavcodec/mpegaudiodata.h"
47 #include "libavcodec/get_bits.h"
48
49 #include "libavcodec/internal.h"
50 #include "libavcodec/put_bits.h"
51 #include "libavcodec/vc1_common.h"
52 #include "libavcodec/raw.h"
53 #include "internal.h"
54 #include "libavutil/avstring.h"
55 #include "libavutil/channel_layout.h"
56 #include "libavutil/csp.h"
57 #include "libavutil/intfloat.h"
58 #include "libavutil/mathematics.h"
59 #include "libavutil/mem.h"
60 #include "libavutil/opt.h"
61 #include "libavutil/dict.h"
62 #include "libavutil/pixdesc.h"
63 #include "libavutil/stereo3d.h"
64 #include "libavutil/timecode.h"
65 #include "libavutil/dovi_meta.h"
66 #include "libavutil/uuid.h"
67 #include "hevc.h"
68 #include "rtpenc.h"
69 #include "nal.h"
70 #include "mov_chan.h"
71 #include "movenc_ttml.h"
72 #include "mux.h"
73 #include "rawutils.h"
74 #include "ttmlenc.h"
75 #include "version.h"
76 #include "vpcc.h"
77 #include "vvc.h"
78
79 static const AVOption options[] = {
80 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
82 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
84 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
85 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
87 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
88 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
89 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
90 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
91 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
92 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
104 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
105 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
106 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
107 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
116 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
117 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
118 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
119 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
120 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
121 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
122 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
125 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
126 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
127 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
128 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
129 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
130 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
131 { NULL },
132 };
133
134 static const AVClass mov_isobmff_muxer_class = {
135 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
136 .item_name = av_default_item_name,
137 .option = options,
138 .version = LIBAVUTIL_VERSION_INT,
139 };
140
141 static int get_moov_size(AVFormatContext *s);
142 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
143
144 31 static int utf8len(const uint8_t *b)
145 {
146 31 int len = 0;
147 int val;
148
2/2
✓ Branch 0 taken 581 times.
✓ Branch 1 taken 31 times.
612 while (*b) {
149
3/8
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 581 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 581 times.
581 GET_UTF8(val, *b++, return -1;)
150 581 len++;
151 }
152 31 return len;
153 }
154
155 //FIXME support 64 bit variant with wide placeholders
156 11874 static int64_t update_size(AVIOContext *pb, int64_t pos)
157 {
158 11874 int64_t curpos = avio_tell(pb);
159 11874 avio_seek(pb, pos, SEEK_SET);
160 11874 avio_wb32(pb, curpos - pos); /* rewrite size */
161 11874 avio_seek(pb, curpos, SEEK_SET);
162
163 11874 return curpos - pos;
164 }
165
166 586 static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version)
167 {
168 586 int64_t curpos = avio_tell(pb);
169 586 avio_seek(pb, pos, SEEK_SET);
170 586 avio_wb32(pb, curpos - pos); /* rewrite size */
171 586 avio_skip(pb, 4);
172 586 avio_w8(pb, version); /* rewrite version */
173 586 avio_seek(pb, curpos, SEEK_SET);
174
175 586 return curpos - pos;
176 }
177
178 586 static int co64_required(const MOVTrack *track)
179 {
180
3/4
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 308 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 278 times.
586 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
181 ✗ return 1;
182 586 return 0;
183 }
184
185 28662 static int is_cover_image(const AVStream *st)
186 {
187 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
188 * is encoded as sparse video track */
189
3/4
✓ Branch 0 taken 28662 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 28650 times.
28662 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
190 }
191
192 6 static int rtp_hinting_needed(const AVStream *st)
193 {
194 /* Add hint tracks for each real audio and video stream */
195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
196 ✗ return 0;
197
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
198
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
199 }
200
201 /* Chunk offset atom */
202 586 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
203 {
204 int i;
205 586 int mode64 = co64_required(track); // use 32 bit size variant if possible
206 586 int64_t pos = avio_tell(pb);
207 586 avio_wb32(pb, 0); /* size */
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
586 if (mode64)
209 ✗ ffio_wfourcc(pb, "co64");
210 else
211 586 ffio_wfourcc(pb, "stco");
212 586 avio_wb32(pb, 0); /* version & flags */
213 586 avio_wb32(pb, track->chunkCount); /* entry count */
214
2/2
✓ Branch 0 taken 18147 times.
✓ Branch 1 taken 586 times.
18733 for (i = 0; i < track->entry; i++) {
215
2/2
✓ Branch 0 taken 15174 times.
✓ Branch 1 taken 2973 times.
18147 if (!track->cluster[i].chunkNum)
216 15174 continue;
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2973 times.
2973 if (mode64 == 1)
218 ✗ avio_wb64(pb, track->cluster[i].pos + track->data_offset);
219 else
220 2973 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
221 }
222 586 return update_size(pb, pos);
223 }
224
225 /* Sample size atom */
226 586 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
227 {
228 586 int equalChunks = 1;
229 586 int i, j, entries = 0, tst = -1, oldtst = -1;
230
231 586 int64_t pos = avio_tell(pb);
232 586 avio_wb32(pb, 0); /* size */
233 586 ffio_wfourcc(pb, "stsz");
234 586 avio_wb32(pb, 0); /* version & flags */
235
236
2/2
✓ Branch 0 taken 18147 times.
✓ Branch 1 taken 586 times.
18733 for (i = 0; i < track->entry; i++) {
237 18147 tst = track->cluster[i].size / track->cluster[i].entries;
238
4/4
✓ Branch 0 taken 17869 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 12728 times.
✓ Branch 3 taken 5141 times.
18147 if (oldtst != -1 && tst != oldtst)
239 12728 equalChunks = 0;
240 18147 oldtst = tst;
241 18147 entries += track->cluster[i].entries;
242 }
243
4/4
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 308 times.
706 if (equalChunks && track->entry) {
244
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
245 120 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
246 120 avio_wb32(pb, sSize); // sample size
247 120 avio_wb32(pb, entries); // sample count
248 } else {
249 466 avio_wb32(pb, 0); // sample size
250 466 avio_wb32(pb, entries); // sample count
251
2/2
✓ Branch 0 taken 14082 times.
✓ Branch 1 taken 466 times.
14548 for (i = 0; i < track->entry; i++) {
252
2/2
✓ Branch 0 taken 14082 times.
✓ Branch 1 taken 14082 times.
28164 for (j = 0; j < track->cluster[i].entries; j++) {
253 14082 avio_wb32(pb, track->cluster[i].size /
254 14082 track->cluster[i].entries);
255 }
256 }
257 }
258 586 return update_size(pb, pos);
259 }
260
261 /* Sample to chunk atom */
262 586 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
263 {
264 586 int index = 0, oldidx = -1, oldval = -1, i;
265 int64_t entryPos, curpos;
266
267 586 int64_t pos = avio_tell(pb);
268 586 avio_wb32(pb, 0); /* size */
269 586 ffio_wfourcc(pb, "stsc");
270 586 avio_wb32(pb, 0); // version & flags
271 586 entryPos = avio_tell(pb);
272 586 avio_wb32(pb, track->chunkCount); // entry count
273
2/2
✓ Branch 0 taken 18147 times.
✓ Branch 1 taken 586 times.
18733 for (i = 0; i < track->entry; i++) {
274
2/2
✓ Branch 0 taken 2133 times.
✓ Branch 1 taken 16014 times.
18147 if ((oldval != track->cluster[i].samples_in_chunk ||
275
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2131 times.
✓ Branch 2 taken 842 times.
✓ Branch 3 taken 15174 times.
18147 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
276 842 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
277 842 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
278 842 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
279 842 oldval = track->cluster[i].samples_in_chunk;
280 842 oldidx = track->cluster[i].stsd_index;
281 842 index++;
282 }
283 }
284 586 curpos = avio_tell(pb);
285 586 avio_seek(pb, entryPos, SEEK_SET);
286 586 avio_wb32(pb, index); // rewrite size
287 586 avio_seek(pb, curpos, SEEK_SET);
288
289 586 return update_size(pb, pos);
290 }
291
292 /* Sync sample atom */
293 69 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
294 {
295 int64_t curpos, entryPos;
296 69 int i, index = 0;
297 69 int64_t pos = avio_tell(pb);
298 69 avio_wb32(pb, 0); // size
299
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
300 69 avio_wb32(pb, 0); // version & flags
301 69 entryPos = avio_tell(pb);
302 69 avio_wb32(pb, track->entry); // entry count
303
2/2
✓ Branch 0 taken 3482 times.
✓ Branch 1 taken 69 times.
3551 for (i = 0; i < track->entry; i++) {
304
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 3256 times.
3482 if (track->cluster[i].flags & flag) {
305 226 avio_wb32(pb, i + 1);
306 226 index++;
307 }
308 }
309 69 curpos = avio_tell(pb);
310 69 avio_seek(pb, entryPos, SEEK_SET);
311 69 avio_wb32(pb, index); // rewrite size
312 69 avio_seek(pb, curpos, SEEK_SET);
313 69 return update_size(pb, pos);
314 }
315
316 /* Sample dependency atom */
317 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
318 {
319 int i;
320 uint8_t leading, dependent, reference, redundancy;
321 3 int64_t pos = avio_tell(pb);
322 3 avio_wb32(pb, 0); // size
323 3 ffio_wfourcc(pb, "sdtp");
324 3 avio_wb32(pb, 0); // version & flags
325
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
326 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
327 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
328
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
329 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
330 }
331
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
332 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
333 }
334 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
335 13 (reference << 2) | redundancy);
336 }
337 3 return update_size(pb, pos);
338 }
339
340 #if CONFIG_IAMFENC
341 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
342 {
343 AVIOContext *dyn_bc;
344 5 int64_t pos = avio_tell(pb);
345 5 uint8_t *dyn_buf = NULL;
346 int dyn_size;
347 5 int ret = avio_open_dyn_buf(&dyn_bc);
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
349 ✗ return ret;
350
351 5 avio_wb32(pb, 0);
352 5 ffio_wfourcc(pb, "iacb");
353 5 avio_w8(pb, 1); // configurationVersion
354
355 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0) {
357 ✗ ffio_free_dyn_buf(&dyn_bc);
358 ✗ return ret;
359 }
360
361 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
362 5 ffio_write_leb(pb, dyn_size);
363 5 avio_write(pb, dyn_buf, dyn_size);
364 5 av_free(dyn_buf);
365
366 5 return update_size(pb, pos);
367 }
368 #endif
369
370 ✗ static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
371 {
372 ✗ avio_wb32(pb, 0x11); /* size */
373 ✗ if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
374 ✗ else ffio_wfourcc(pb, "damr");
375 ✗ ffio_wfourcc(pb, "FFMP");
376 ✗ avio_w8(pb, 0); /* decoder version */
377
378 ✗ avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
379 ✗ avio_w8(pb, 0x00); /* Mode change period (no restriction) */
380 ✗ avio_w8(pb, 0x01); /* Frames per sample */
381 ✗ return 0x11;
382 }
383
384 struct eac3_info {
385 AVPacket *pkt;
386 uint8_t eof;
387 uint8_t ec3_done;
388 uint8_t num_blocks;
389
390 /* Layout of the EC3SpecificBox */
391 /* maximum bitrate */
392 uint16_t data_rate;
393 int8_t ac3_bit_rate_code;
394 /* number of independent substreams */
395 uint8_t num_ind_sub;
396 struct {
397 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
398 uint8_t fscod;
399 /* bit stream identification 5 bits */
400 uint8_t bsid;
401 /* one bit reserved */
402 /* audio service mixing (not supported yet) 1 bit */
403 /* bit stream mode 3 bits */
404 uint8_t bsmod;
405 /* audio coding mode 3 bits */
406 uint8_t acmod;
407 /* sub woofer on 1 bit */
408 uint8_t lfeon;
409 /* 3 bits reserved */
410 /* number of dependent substreams associated with this substream 4 bits */
411 uint8_t num_dep_sub;
412 /* channel locations of the dependent substream(s), if any, 9 bits */
413 uint16_t chan_loc;
414 /* if there is no dependent substream, then one bit reserved instead */
415 } substream[1]; /* TODO: support 8 independent substreams */
416 /* indicates the decoding complexity, 8 bits */
417 uint8_t complexity_index_type_a;
418 };
419
420 7 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
421 {
422 7 struct eac3_info *info = track->eac3_priv;
423 PutBitContext pbc;
424 uint8_t buf[3];
425
426
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!info || !info->ec3_done) {
427 ✗ av_log(s, AV_LOG_ERROR,
428 "Cannot write moov atom before AC3 packets."
429 " Set the delay_moov flag to fix this.\n");
430 ✗ return AVERROR(EINVAL);
431 }
432
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->substream[0].bsid > 8) {
434 ✗ av_log(s, AV_LOG_ERROR,
435 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
436 "ISOBMFF specification in ETSI TS 102 366!\n",
437 ✗ info->substream[0].bsid);
438 ✗ return AVERROR(EINVAL);
439 }
440
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->ac3_bit_rate_code < 0) {
442 ✗ av_log(s, AV_LOG_ERROR,
443 "No valid AC3 bit rate code for data rate of %d!\n",
444 ✗ info->data_rate);
445 ✗ return AVERROR(EINVAL);
446 }
447
448 7 avio_wb32(pb, 11);
449 7 ffio_wfourcc(pb, "dac3");
450
451 7 init_put_bits(&pbc, buf, sizeof(buf));
452 7 put_bits(&pbc, 2, info->substream[0].fscod);
453 7 put_bits(&pbc, 5, info->substream[0].bsid);
454 7 put_bits(&pbc, 3, info->substream[0].bsmod);
455 7 put_bits(&pbc, 3, info->substream[0].acmod);
456 7 put_bits(&pbc, 1, info->substream[0].lfeon);
457 7 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
458 7 put_bits(&pbc, 5, 0); // reserved
459
460 7 flush_put_bits(&pbc);
461 7 avio_write(pb, buf, sizeof(buf));
462
463 7 return 11;
464 }
465
466 1737 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
467 {
468 1737 AC3HeaderInfo *hdr = NULL;
469 struct eac3_info *info;
470 int num_blocks, ret;
471
472
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
1737 if (!track->eac3_priv) {
473
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
474 ✗ return AVERROR(ENOMEM);
475
476 10 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
477 }
478 1737 info = track->eac3_priv;
479
480
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
1737 if (!info->pkt && !(info->pkt = av_packet_alloc()))
481 ✗ return AVERROR(ENOMEM);
482
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (info->eof) {
484 av_assert1(!info->pkt->size);
485 ✗ ret = pkt->size;
486 ✗ goto end;
487 }
488
489
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1736 times.
1737 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
491 ✗ goto end;
492
493 /* drop the packets until we see a good one */
494
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
495 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
496 1 ret = 0;
497 } else
498 ✗ ret = AVERROR_INVALIDDATA;
499 1 goto end;
500 }
501
502 1736 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
503 1736 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
504 hdr->ac3_bit_rate_code);
505 1736 info->complexity_index_type_a = hdr->complexity_index_type_a;
506
507 1736 num_blocks = hdr->num_blocks;
508
509
2/2
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 14 times.
1736 if (!info->ec3_done) {
510 /* AC-3 substream must be the first one */
511
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
14 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
512 ✗ ret = AVERROR(EINVAL);
513 ✗ goto end;
514 }
515
516 /* this should always be the case, given that our AC-3 parser
517 * concatenates dependent frames to their independent parent */
518
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
519
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
520 /* substream ids must be incremental */
521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid > info->num_ind_sub + 1) {
522 ✗ ret = AVERROR(EINVAL);
523 ✗ goto end;
524 }
525
526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid == info->num_ind_sub + 1) {
527 //info->num_ind_sub++;
528 ✗ avpriv_request_sample(mov->fc, "Multiple independent substreams");
529 ✗ ret = AVERROR_PATCHWELCOME;
530 ✗ goto end;
531
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 } else if (hdr->substreamid < info->num_ind_sub ||
532
3/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 10 times.
14 hdr->substreamid == 0 && info->substream[0].bsid) {
533 4 info->ec3_done = 1;
534 4 goto concatenate;
535 }
536 } else {
537 ✗ if (hdr->substreamid != 0) {
538 ✗ avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
539 ✗ ret = AVERROR_PATCHWELCOME;
540 ✗ goto end;
541 }
542 }
543
544 /* fill the info needed for the "dec3" atom */
545 10 info->substream[hdr->substreamid].fscod = hdr->sr_code;
546 10 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
547 10 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
548 10 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
549 10 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
550
551
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (track->par->codec_id == AV_CODEC_ID_AC3) {
552 // with AC-3 we only require the information of a single packet,
553 // so we can finish as soon as the basic values of the bit stream
554 // have been set to the track's informational structure.
555 6 info->ec3_done = 1;
556 6 goto concatenate;
557 }
558
559 /* Parse dependent substream(s), if any */
560
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (pkt->size != hdr->frame_size) {
561 1 int cumul_size = hdr->frame_size;
562 1 int parent = hdr->substreamid;
563
564
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (cumul_size != pkt->size) {
565 1 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
567 ✗ goto end;
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
569 ✗ ret = AVERROR(EINVAL);
570 ✗ goto end;
571 }
572 1 info->substream[parent].num_dep_sub++;
573 1 ret /= 8;
574
575 /* get the dependent stream channel map, if exists */
576
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (hdr->channel_map_present) {
577 /* chanmap is a 16-bit field read MSB-first, so flag index
578 * i sits at bit (15 - i), matching the indexing of
579 * ff_eac3_custom_channel_map_locations. chan_loc bits 0-7
580 * carry flag indices 5-12, i.e. chanmap bit (10 - j).
581 * The mapping is not contiguous at the top: index 13
582 * (Lts/Rts) has no chan_loc bit and is skipped, and
583 * chan_loc bit 8 carries LFE2, which is index 14 and so
584 * chanmap bit 1. */
585
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for (int j = 0; j < 8; j++) {
586
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if ((hdr->channel_map >> (10 - j)) & 1)
587 1 info->substream[parent].chan_loc |= 1 << j;
588 }
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((hdr->channel_map >> 1) & 1)
590 ✗ info->substream[parent].chan_loc |= 1 << 8;
591 } else {
592 ✗ info->substream[parent].chan_loc |= hdr->channel_mode;
593 }
594 1 cumul_size += hdr->frame_size;
595 }
596 }
597 }
598
599 1726 concatenate:
600
2/4
✓ Branch 0 taken 1736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1736 times.
✗ Branch 3 not taken.
1736 if (!info->num_blocks && num_blocks == 6) {
601 1736 ret = pkt->size;
602 1736 goto end;
603 }
604 ✗ else if (info->num_blocks + num_blocks > 6) {
605 ✗ ret = AVERROR_INVALIDDATA;
606 ✗ goto end;
607 }
608
609 ✗ if (!info->num_blocks) {
610 ✗ ret = av_packet_ref(info->pkt, pkt);
611 ✗ if (!ret)
612 ✗ info->num_blocks = num_blocks;
613 ✗ goto end;
614 } else {
615 const AVPacketSideData *sd;
616 ✗ int64_t duration = pkt->duration;
617 ✗ if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
618 ✗ goto end;
619 ✗ sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
620 ✗ if (sd && sd->size >= 10) {
621 ✗ uint8_t *buf = av_packet_new_side_data(info->pkt, AV_PKT_DATA_SKIP_SAMPLES, sd->size);
622 ✗ if (buf)
623 ✗ memcpy(buf, sd->data, sd->size);
624 ✗ if (track->par->frame_size)
625 ✗ duration = FFMAX(av_rescale_q(track->par->frame_size, (AVRational){ 1, track->par->sample_rate },
626 track->st->time_base), duration);
627 }
628 ✗ memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
629 ✗ info->num_blocks += num_blocks;
630 ✗ info->pkt->duration += duration;
631 ✗ if (info->num_blocks != 6)
632 ✗ goto end;
633 ✗ av_packet_unref(pkt);
634 ✗ av_packet_move_ref(pkt, info->pkt);
635 ✗ info->num_blocks = 0;
636 }
637 ✗ ret = pkt->size;
638
639 1737 end:
640 1737 av_free(hdr);
641
642 1737 return ret;
643 }
644
645 4 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
646 {
647 PutBitContext pbc;
648 uint8_t *buf;
649 struct eac3_info *info;
650 int size, i;
651
652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->eac3_priv) {
653 ✗ av_log(s, AV_LOG_ERROR,
654 "Cannot write moov atom before EAC3 packets parsed.\n");
655 ✗ return AVERROR(EINVAL);
656 }
657
658 4 info = track->eac3_priv;
659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
660 4 buf = av_malloc(size);
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!buf) {
662 ✗ return AVERROR(ENOMEM);
663 }
664
665 4 init_put_bits(&pbc, buf, size);
666 4 put_bits(&pbc, 13, info->data_rate);
667 4 put_bits(&pbc, 3, info->num_ind_sub);
668
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i <= info->num_ind_sub; i++) {
669 4 put_bits(&pbc, 2, info->substream[i].fscod);
670 4 put_bits(&pbc, 5, info->substream[i].bsid);
671 4 put_bits(&pbc, 1, 0); /* reserved */
672 4 put_bits(&pbc, 1, 0); /* asvc */
673 4 put_bits(&pbc, 3, info->substream[i].bsmod);
674 4 put_bits(&pbc, 3, info->substream[i].acmod);
675 4 put_bits(&pbc, 1, info->substream[i].lfeon);
676 4 put_bits(&pbc, 3, 0); /* reserved */
677 4 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
678
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (!info->substream[i].num_dep_sub) {
679 3 put_bits(&pbc, 1, 0); /* reserved */
680 } else {
681 1 put_bits(&pbc, 9, info->substream[i].chan_loc);
682 }
683 }
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (info->complexity_index_type_a) {
685 ✗ put_bits(&pbc, 7, 0); /* reserved */
686 ✗ put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
687 ✗ put_bits(&pbc, 8, info->complexity_index_type_a);
688 }
689 4 flush_put_bits(&pbc);
690 4 size = put_bytes_output(&pbc);
691
692 4 avio_wb32(pb, size + 8);
693 4 ffio_wfourcc(pb, "dec3");
694 4 avio_write(pb, buf, size);
695
696 4 av_free(buf);
697
698 4 return size;
699 }
700
701 /**
702 * This function writes extradata "as is".
703 * Extradata must be formatted like a valid atom (with size and tag).
704 */
705 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
706 {
707 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
708 12 return track->extradata_size[track->last_stsd_index];
709 }
710
711 ✗ static int mov_write_enda_tag(AVIOContext *pb)
712 {
713 ✗ avio_wb32(pb, 10);
714 ✗ ffio_wfourcc(pb, "enda");
715 ✗ avio_wb16(pb, 1); /* little endian */
716 ✗ return 10;
717 }
718
719 2 static int mov_write_enda_tag_be(AVIOContext *pb)
720 {
721 2 avio_wb32(pb, 10);
722 2 ffio_wfourcc(pb, "enda");
723 2 avio_wb16(pb, 0); /* big endian */
724 2 return 10;
725 }
726
727 1017 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
728 {
729 1017 int i = 3;
730 1017 avio_w8(pb, tag);
731
2/2
✓ Branch 0 taken 3051 times.
✓ Branch 1 taken 1017 times.
4068 for (; i > 0; i--)
732 3051 avio_w8(pb, (size >> (7 * i)) | 0x80);
733 1017 avio_w8(pb, size & 0x7F);
734 1017 }
735
736 685 static unsigned compute_avg_bitrate(MOVTrack *track)
737 {
738 685 uint64_t size = 0;
739 int i;
740
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 631 times.
685 if (!track->track_duration)
741 54 return 0;
742
2/2
✓ Branch 0 taken 16905 times.
✓ Branch 1 taken 631 times.
17536 for (i = 0; i < track->entry; i++)
743 16905 size += track->cluster[i].size;
744 631 return size * 8 * track->timescale / track->track_duration;
745 }
746
747 struct mpeg4_bit_rate_values {
748 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
749 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
750 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
751 };
752
753 685 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
754 {
755 1370 const AVPacketSideData *sd = track->st ?
756 684 av_packet_side_data_get(track->st->codecpar->coded_side_data,
757 684 track->st->codecpar->nb_coded_side_data,
758
2/2
✓ Branch 0 taken 684 times.
✓ Branch 1 taken 1 times.
685 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
759
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 633 times.
685 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
760 685 struct mpeg4_bit_rate_values bit_rates = { 0 };
761
762 685 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
763
2/2
✓ Branch 0 taken 556 times.
✓ Branch 1 taken 129 times.
685 if (!bit_rates.avg_bit_rate) {
764 // if the average bit rate cannot be calculated at this point, such as
765 // in the case of fragmented MP4, utilize the following values as
766 // fall-back in priority order:
767 //
768 // 1. average bit rate property
769 // 2. bit rate (usually average over the whole clip)
770 // 3. maximum bit rate property
771
772
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 538 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
556 if (props && props->avg_bitrate) {
773 18 bit_rates.avg_bit_rate = props->avg_bitrate;
774
2/2
✓ Branch 0 taken 409 times.
✓ Branch 1 taken 129 times.
538 } else if (track->par->bit_rate) {
775 409 bit_rates.avg_bit_rate = track->par->bit_rate;
776
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
129 } else if (props && props->max_bitrate) {
777 ✗ bit_rates.avg_bit_rate = props->max_bitrate;
778 }
779 }
780
781 // (FIXME should be max rate in any 1 sec window)
782 685 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
783 bit_rates.avg_bit_rate);
784
785 // utilize values from properties if we have them available
786
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 633 times.
685 if (props) {
787 // no avg_bitrate signals that the track is VBR
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (!props->avg_bitrate)
789 ✗ bit_rates.avg_bit_rate = props->avg_bitrate;
790 52 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
791 props->max_bitrate);
792 52 bit_rates.buffer_size = props->buffer_size / 8;
793 }
794
795 685 return bit_rates;
796 }
797
798 306 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
799 {
800 306 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
801 306 int64_t pos = avio_tell(pb);
802 612 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
803
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 207 times.
306 5 + track->extradata_size[track->last_stsd_index] : 0;
804
805 306 avio_wb32(pb, 0); // size
806 306 ffio_wfourcc(pb, "esds");
807 306 avio_wb32(pb, 0); // Version
808
809 // ES descriptor
810 306 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
811 306 avio_wb16(pb, track->track_id);
812 306 avio_w8(pb, 0x00); // flags (= no flags)
813
814 // DecoderConfig descriptor
815 306 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
816
817 // Object type indication
818
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 200 times.
306 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
819
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 105 times.
106 track->par->codec_id == AV_CODEC_ID_MP3) &&
820
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 200 times.
201 track->par->sample_rate > 24000)
821 1 avio_w8(pb, 0x6B); // 11172-3
822 else
823 305 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
824
825 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
826 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306 times.
306 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
828 ✗ avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
829
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 37 times.
306 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
830 269 avio_w8(pb, 0x15); // flags (= Audiostream)
831 else
832 37 avio_w8(pb, 0x11); // flags (= Visualstream)
833
834 306 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
835 306 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
836 306 avio_wb32(pb, bit_rates.avg_bit_rate);
837
838
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 207 times.
306 if (track->extradata_size[track->last_stsd_index]) {
839 // DecoderSpecific info descriptor
840 99 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
841 99 avio_write(pb, track->extradata[track->last_stsd_index],
842 99 track->extradata_size[track->last_stsd_index]);
843 }
844
845 // SL descriptor
846 306 put_descr(pb, 0x06, 1);
847 306 avio_w8(pb, 0x02);
848 306 return update_size(pb, pos);
849 }
850
851 75 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
852 {
853
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 return codec_id == AV_CODEC_ID_PCM_S24LE ||
854
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 codec_id == AV_CODEC_ID_PCM_S32LE ||
855
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
150 codec_id == AV_CODEC_ID_PCM_F32LE ||
856 codec_id == AV_CODEC_ID_PCM_F64LE;
857 }
858
859 75 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
860 {
861
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
71 return codec_id == AV_CODEC_ID_PCM_S24BE ||
862
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 codec_id == AV_CODEC_ID_PCM_S32BE ||
863
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
146 codec_id == AV_CODEC_ID_PCM_F32BE ||
864 codec_id == AV_CODEC_ID_PCM_F64BE;
865 }
866
867 ✗ static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
868 {
869 int ret;
870 ✗ int64_t pos = avio_tell(pb);
871 ✗ avio_wb32(pb, 0);
872 ✗ avio_wl32(pb, track->tag); // store it byteswapped
873 ✗ track->par->codec_tag = av_bswap16(track->tag >> 16);
874 ✗ if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
875 ✗ return ret;
876 ✗ return update_size(pb, pos);
877 }
878
879 ✗ static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
880 {
881 int ret;
882 ✗ int64_t pos = avio_tell(pb);
883 ✗ avio_wb32(pb, 0);
884 ✗ ffio_wfourcc(pb, "wfex");
885 ✗ if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
886 ✗ return ret;
887 ✗ return update_size(pb, pos);
888 }
889
890 ✗ static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
891 {
892 ✗ int64_t pos = avio_tell(pb);
893 ✗ avio_wb32(pb, 0);
894 ✗ ffio_wfourcc(pb, "dfLa");
895 ✗ avio_w8(pb, 0); /* version */
896 ✗ avio_wb24(pb, 0); /* flags */
897
898 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
899 ✗ if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
900 ✗ return AVERROR_INVALIDDATA;
901
902 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
903 ✗ avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
904 ✗ avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
905 ✗ avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
906
907 ✗ return update_size(pb, pos);
908 }
909
910 ✗ static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
911 {
912 ✗ int64_t pos = avio_tell(pb);
913 int channels, channel_map;
914 ✗ avio_wb32(pb, 0);
915 ✗ ffio_wfourcc(pb, "dOps");
916 ✗ avio_w8(pb, 0); /* Version */
917 ✗ if (track->extradata_size[track->last_stsd_index] < 19) {
918 ✗ av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
919 ✗ return AVERROR_INVALIDDATA;
920 }
921 /* extradata contains an Ogg OpusHead, other than byte-ordering and
922 OpusHead's preceding magic/version, OpusSpecificBox is currently
923 identical. */
924 ✗ channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
925 ✗ channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
926
927 ✗ avio_w8(pb, channels); /* OuputChannelCount */
928 ✗ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
929 ✗ avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
930 ✗ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
931 ✗ avio_w8(pb, channel_map); /* ChannelMappingFamily */
932 /* Write the rest of the header out without byte-swapping. */
933 ✗ if (channel_map) {
934 ✗ if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
935 ✗ av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
936 ✗ return AVERROR_INVALIDDATA;
937 }
938 ✗ avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
939 }
940
941 ✗ return update_size(pb, pos);
942 }
943
944 ✗ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
945 {
946 ✗ int64_t pos = avio_tell(pb);
947 int length;
948 ✗ avio_wb32(pb, 0);
949 ✗ ffio_wfourcc(pb, "dmlp");
950
951 ✗ if (track->extradata_size[track->last_stsd_index] < 20) {
952 ✗ av_log(s, AV_LOG_ERROR,
953 "Cannot write moov atom before TrueHD packets."
954 " Set the delay_moov flag to fix this.\n");
955 ✗ return AVERROR(EINVAL);
956 }
957
958 ✗ length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
959 ✗ if (length < 20 || length > track->extradata_size[track->last_stsd_index])
960 ✗ return AVERROR_INVALIDDATA;
961
962 // Only TrueHD is supported
963 ✗ if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
964 ✗ return AVERROR_INVALIDDATA;
965
966 ✗ avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
967 ✗ avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
968 ✗ avio_wb32(pb, 0); /* reserved */
969
970 ✗ return update_size(pb, pos);
971 }
972
973 1 static int mov_write_mhac_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
974 {
975 1 int64_t pos = avio_tell(pb);
976 1 int layout = 0;
977
978
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->extradata_size[track->last_stsd_index] ||
979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->extradata_size[track->last_stsd_index] > UINT16_MAX) {
980 ✗ av_log(s, AV_LOG_ERROR,
981 "Invalid extradata size %d for MPEGH-H stream.\n",
982 ✗ track->extradata_size[track->last_stsd_index]);
983 ✗ return AVERROR(EINVAL);
984 }
985
986 1 avio_wb32(pb, 0);
987 1 ffio_wfourcc(pb, "mhaC");
988
989 1 avio_w8(pb, 1); // ConfigurationVersion
990 1 avio_w8(pb, track->par->profile * 5 + track->par->level);
991
992
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 for (size_t i = 0; i < FF_ARRAY_ELEMS(ff_mpa_cicp_channel_layout_masks); i++) {
993
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
17 if (ff_mpa_cicp_channel_layout_masks[i]) {
994 AVChannelLayout ch_layout;
995 15 av_channel_layout_from_mask(&ch_layout, ff_mpa_cicp_channel_layout_masks[i]);
996
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 14 times.
15 if (!av_channel_layout_compare(&track->par->ch_layout, &ch_layout)) {
997 1 layout = i;
998 1 break;
999 }
1000 }
1001 }
1002
1003 1 avio_w8(pb, layout);
1004 1 avio_wb16(pb, track->extradata_size[track->last_stsd_index]);
1005 1 avio_write(pb, track->extradata[track->last_stsd_index],
1006 1 track->extradata_size[track->last_stsd_index]);
1007
1008 1 return update_size(pb, pos);
1009 }
1010
1011 289 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1012 {
1013 289 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
1014 289 AVChannelLayout ch_layout = { 0 };
1015 int64_t pos;
1016 int ambisonic_order, ambi_channels, non_diegetic_channels;
1017 int i, ret;
1018
1019
1/2
✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
289 if (!str)
1020 289 return 0;
1021
1022 ✗ ret = av_channel_layout_from_string(&ch_layout, str->value);
1023 ✗ if (ret < 0) {
1024 ✗ if (ret == AVERROR(EINVAL)) {
1025 ✗ invalid:
1026 ✗ av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
1027 ✗ ret = 0;
1028 }
1029 ✗ av_channel_layout_uninit(&ch_layout);
1030 ✗ return ret;
1031 }
1032
1033 ✗ if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
1034 ✗ goto invalid;
1035
1036 ✗ ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
1037 ✗ if (ambisonic_order < 0)
1038 ✗ goto invalid;
1039
1040 ✗ ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
1041 ✗ non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
1042 ✗ if (non_diegetic_channels &&
1043 ✗ (non_diegetic_channels != 2 ||
1044 ✗ av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
1045 ✗ goto invalid;
1046
1047 ✗ av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
1048
1049 ✗ pos = avio_tell(pb);
1050
1051 ✗ avio_wb32(pb, 0); // Size
1052 ✗ ffio_wfourcc(pb, "SA3D");
1053 ✗ avio_w8(pb, 0); // version
1054 ✗ avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
1055 ✗ avio_wb32(pb, ambisonic_order); // ambisonic_order
1056 ✗ avio_w8(pb, 0); // ambisonic_channel_ordering
1057 ✗ avio_w8(pb, 0); // ambisonic_normalization
1058 ✗ avio_wb32(pb, ch_layout.nb_channels); // num_channels
1059 ✗ for (i = 0; i < ambi_channels; i++)
1060 ✗ avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
1061 ✗ for (; i < ch_layout.nb_channels; i++)
1062 ✗ avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
1063
1064 ✗ av_channel_layout_uninit(&ch_layout);
1065
1066 ✗ return update_size(pb, pos);
1067 }
1068
1069 39 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1070 {
1071 uint32_t layout_tag, bitmap, *channel_desc;
1072 39 int64_t pos = avio_tell(pb);
1073 int num_desc, ret;
1074
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (track->multichannel_as_mono)
1076 ✗ return 0;
1077
1078 39 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
1079 &bitmap, &channel_desc);
1080
1081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0) {
1082 ✗ if (ret == AVERROR(ENOSYS)) {
1083 ✗ av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
1084 "lack of channel information\n");
1085 ✗ ret = 0;
1086 }
1087
1088 ✗ return ret;
1089 }
1090
1091 /* no predefined tag found + ch_layout in AV_CHANNEL_ORDER_NATIVE
1092 * but bitstream channels not actually in native order */
1093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (layout_tag == MOV_CH_LAYOUT_UNKNOWN)
1094 ✗ return 0;
1095
1096
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
39 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1098 1 channel_desc = av_malloc(sizeof(*channel_desc));
1099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1100 ✗ return AVERROR(ENOMEM);
1101
1102 1 layout_tag = 0;
1103 1 bitmap = 0;
1104 1 *channel_desc = 3; // channel label "Center"
1105 }
1106
1107
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 36 times.
39 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1108
1109 39 avio_wb32(pb, 0); // Size
1110 39 ffio_wfourcc(pb, "chan"); // Type
1111 39 avio_w8(pb, 0); // Version
1112 39 avio_wb24(pb, 0); // Flags
1113 39 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1114 39 avio_wb32(pb, bitmap); // mChannelBitmap
1115 39 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1116
1117
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39 times.
42 for (int i = 0; i < num_desc; i++) {
1118 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1119 3 avio_wb32(pb, 0); // mChannelFlags
1120 3 avio_wl32(pb, 0); // mCoordinates[0]
1121 3 avio_wl32(pb, 0); // mCoordinates[1]
1122 3 avio_wl32(pb, 0); // mCoordinates[2]
1123 }
1124
1125 39 av_free(channel_desc);
1126
1127 39 return update_size(pb, pos);
1128 }
1129
1130 14 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1131 {
1132 14 int64_t pos = avio_tell(pb);
1133
1134 14 avio_wb32(pb, 0); /* size */
1135 14 ffio_wfourcc(pb, "wave");
1136
1137
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1138 14 avio_wb32(pb, 12); /* size */
1139 14 ffio_wfourcc(pb, "frma");
1140 14 avio_wl32(pb, track->tag);
1141 }
1142
1143
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1144 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1145 3 avio_wb32(pb, 12); /* size */
1146 3 ffio_wfourcc(pb, "mp4a");
1147 3 avio_wb32(pb, 0);
1148 3 mov_write_esds_tag(pb, track);
1149
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1150 ✗ mov_write_enda_tag(pb);
1151
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
11 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1152 2 mov_write_enda_tag_be(pb);
1153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1154 ✗ mov_write_amr_tag(pb, track);
1155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1156 ✗ mov_write_ac3_tag(s, pb, track);
1157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1158 ✗ mov_write_eac3_tag(s, pb, track);
1159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1160 ✗ track->par->codec_id == AV_CODEC_ID_QDM2) {
1161 9 mov_write_extradata_tag(pb, track);
1162 ✗ } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1163 ✗ track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1164 ✗ mov_write_ms_tag(s, pb, track);
1165 }
1166
1167 14 avio_wb32(pb, 8); /* size */
1168 14 avio_wb32(pb, 0); /* null tag */
1169
1170 14 return update_size(pb, pos);
1171 }
1172
1173 ✗ static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1174 {
1175 uint8_t *unescaped;
1176 ✗ const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1177 ✗ track->extradata_size[track->last_stsd_index];
1178 ✗ int unescaped_size, seq_found = 0;
1179 ✗ int level = 0, interlace = 0;
1180 ✗ int packet_seq = track->vc1_info.packet_seq;
1181 ✗ int packet_entry = track->vc1_info.packet_entry;
1182 ✗ int slices = track->vc1_info.slices;
1183 PutBitContext pbc;
1184
1185 ✗ if (track->start_dts == AV_NOPTS_VALUE) {
1186 /* No packets written yet, vc1_info isn't authoritative yet. */
1187 /* Assume inline sequence and entry headers. */
1188 ✗ packet_seq = packet_entry = 1;
1189 ✗ av_log(NULL, AV_LOG_WARNING,
1190 "moov atom written before any packets, unable to write correct "
1191 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1192 }
1193
1194 ✗ unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1195 ✗ if (!unescaped)
1196 ✗ return AVERROR(ENOMEM);
1197 ✗ start = find_next_marker(track->extradata[track->last_stsd_index], end);
1198 ✗ for (next = start; next < end; start = next) {
1199 GetBitContext gb;
1200 int size;
1201 ✗ next = find_next_marker(start + 4, end);
1202 ✗ size = next - start - 4;
1203 ✗ if (size <= 0)
1204 ✗ continue;
1205 ✗ unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1206 ✗ init_get_bits(&gb, unescaped, 8 * unescaped_size);
1207 ✗ if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1208 ✗ int profile = get_bits(&gb, 2);
1209 ✗ if (profile != PROFILE_ADVANCED) {
1210 ✗ av_free(unescaped);
1211 ✗ return AVERROR(ENOSYS);
1212 }
1213 ✗ seq_found = 1;
1214 ✗ level = get_bits(&gb, 3);
1215 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1216 * width, height */
1217 ✗ skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1218 ✗ skip_bits(&gb, 1); /* broadcast */
1219 ✗ interlace = get_bits1(&gb);
1220 ✗ skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1221 }
1222 }
1223 ✗ if (!seq_found) {
1224 ✗ av_free(unescaped);
1225 ✗ return AVERROR(ENOSYS);
1226 }
1227
1228 ✗ init_put_bits(&pbc, buf, 7);
1229 /* VC1DecSpecStruc */
1230 ✗ put_bits(&pbc, 4, 12); /* profile - advanced */
1231 ✗ put_bits(&pbc, 3, level);
1232 ✗ put_bits(&pbc, 1, 0); /* reserved */
1233 /* VC1AdvDecSpecStruc */
1234 ✗ put_bits(&pbc, 3, level);
1235 ✗ put_bits(&pbc, 1, 0); /* cbr */
1236 ✗ put_bits(&pbc, 6, 0); /* reserved */
1237 ✗ put_bits(&pbc, 1, !interlace); /* no interlace */
1238 ✗ put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1239 ✗ put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1240 ✗ put_bits(&pbc, 1, !slices); /* no slice code */
1241 ✗ put_bits(&pbc, 1, 0); /* no bframe */
1242 ✗ put_bits(&pbc, 1, 0); /* reserved */
1243
1244 /* framerate */
1245 ✗ if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1246 ✗ put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1247 else
1248 ✗ put_bits32(&pbc, 0xffffffff);
1249
1250 ✗ flush_put_bits(&pbc);
1251
1252 ✗ av_free(unescaped);
1253
1254 ✗ return 0;
1255 }
1256
1257 ✗ static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1258 {
1259 ✗ uint8_t buf[7] = { 0 };
1260 int ret;
1261
1262 ✗ if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1263 ✗ return ret;
1264
1265 ✗ avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1266 ✗ ffio_wfourcc(pb, "dvc1");
1267 ✗ avio_write(pb, buf, sizeof(buf));
1268 ✗ avio_write(pb, track->extradata[track->last_stsd_index],
1269 ✗ track->extradata_size[track->last_stsd_index]);
1270
1271 ✗ return 0;
1272 }
1273
1274 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1275 {
1276 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1277 4 ffio_wfourcc(pb, "glbl");
1278 4 avio_write(pb, track->extradata[track->last_stsd_index],
1279 4 track->extradata_size[track->last_stsd_index]);
1280 4 return 8 + track->extradata_size[track->last_stsd_index];
1281 }
1282
1283 /**
1284 * Compute flags for 'lpcm' tag.
1285 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1286 */
1287 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1288 {
1289
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) {
1290 ✗ case AV_CODEC_ID_PCM_F32BE:
1291 case AV_CODEC_ID_PCM_F64BE:
1292 ✗ return 11;
1293 ✗ case AV_CODEC_ID_PCM_F32LE:
1294 case AV_CODEC_ID_PCM_F64LE:
1295 ✗ return 9;
1296 ✗ case AV_CODEC_ID_PCM_U8:
1297 ✗ return 10;
1298 ✗ case AV_CODEC_ID_PCM_S16BE:
1299 case AV_CODEC_ID_PCM_S24BE:
1300 case AV_CODEC_ID_PCM_S32BE:
1301 ✗ return 14;
1302 ✗ case AV_CODEC_ID_PCM_S8:
1303 case AV_CODEC_ID_PCM_S16LE:
1304 case AV_CODEC_ID_PCM_S24LE:
1305 case AV_CODEC_ID_PCM_S32LE:
1306 ✗ return 12;
1307 8 default:
1308 8 return 0;
1309 }
1310 }
1311
1312 40112 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1313 {
1314 int64_t next_dts;
1315
1316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40112 times.
40112 if (cluster_idx >= track->entry)
1317 ✗ return 0;
1318
1319
2/2
✓ Branch 0 taken 1637 times.
✓ Branch 1 taken 38475 times.
40112 if (cluster_idx + 1 == track->entry)
1320 1637 next_dts = track->track_duration + track->start_dts;
1321 else
1322 38475 next_dts = track->cluster[cluster_idx + 1].dts;
1323
1324 40112 next_dts -= track->cluster[cluster_idx].dts;
1325
1326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40112 times.
40112 av_assert0(next_dts >= 0);
1327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40112 times.
40112 av_assert0(next_dts <= INT_MAX);
1328
1329 40112 return next_dts;
1330 }
1331
1332 4 static int get_samples_per_packet(MOVTrack *track)
1333 {
1334 int i, first_duration;
1335
1336 /* use 1 for raw PCM */
1337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1338 ✗ return 1;
1339
1340 /* check to see if duration is constant for all clusters */
1341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1342 ✗ return 0;
1343 4 first_duration = get_cluster_duration(track, 0);
1344
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1345
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1346 4 return 0;
1347 }
1348 ✗ return first_duration;
1349 }
1350
1351 379 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1352 {
1353 379 int64_t pos = avio_tell(pb);
1354 379 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1355
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 293 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
379 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1356
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 !bit_rates.buffer_size)
1357 // no useful data to be written, skip
1358 86 return 0;
1359
1360 293 avio_wb32(pb, 0); /* size */
1361 293 ffio_wfourcc(pb, "btrt");
1362
1363 293 avio_wb32(pb, bit_rates.buffer_size);
1364 293 avio_wb32(pb, bit_rates.max_bit_rate);
1365 293 avio_wb32(pb, bit_rates.avg_bit_rate);
1366
1367 293 return update_size(pb, pos);
1368 }
1369
1370 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1371 {
1372 7 int64_t pos = avio_tell(pb);
1373 7 int config = 0;
1374 int ret;
1375 7 uint8_t *speaker_pos = NULL;
1376 7 const AVChannelLayout *layout = &track->par->ch_layout;
1377
1378 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1379
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) {
1380 4 config = 0;
1381 4 speaker_pos = av_malloc(layout->nb_channels);
1382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1383 ✗ return AVERROR(ENOMEM);
1384 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1385 4 speaker_pos, layout->nb_channels);
1386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1387 ✗ char buf[128] = {0};
1388
1389 ✗ av_freep(&speaker_pos);
1390 ✗ av_channel_layout_describe(layout, buf, sizeof(buf));
1391 ✗ av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1392 ✗ return ret;
1393 }
1394 }
1395
1396 7 avio_wb32(pb, 0); /* size */
1397 7 ffio_wfourcc(pb, "chnl");
1398 7 avio_wb32(pb, 0); /* version & flags */
1399
1400 7 avio_w8(pb, 1); /* stream_structure */
1401 7 avio_w8(pb, config);
1402
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1403 3 avio_wb64(pb, 0);
1404 } else {
1405 4 avio_write(pb, speaker_pos, layout->nb_channels);
1406 4 av_freep(&speaker_pos);
1407 }
1408
1409 7 return update_size(pb, pos);
1410 }
1411
1412 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1413 {
1414 9 int64_t pos = avio_tell(pb);
1415 int format_flags;
1416 int sample_size;
1417
1418 9 avio_wb32(pb, 0); /* size */
1419 9 ffio_wfourcc(pb, "pcmC");
1420 9 avio_wb32(pb, 0); /* version & flags */
1421
1422 /* 0x01: indicates little-endian format */
1423 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1424
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1426
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 ||
1427 ✗ track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1428 9 avio_w8(pb, format_flags);
1429 9 sample_size = track->par->bits_per_raw_sample;
1430
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1431 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1433 9 avio_w8(pb, sample_size);
1434
1435 9 return update_size(pb, pos);
1436 }
1437
1438 5 static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track)
1439 {
1440 5 int64_t pos = avio_tell(pb);
1441 5 avio_wb32(pb, 0); /* size */
1442 5 ffio_wfourcc(pb, "srat");
1443 5 avio_wb32(pb, 0); /* version & flags */
1444
1445 5 avio_wb32(pb, track->par->sample_rate);
1446
1447 5 return update_size(pb, pos);
1448 }
1449
1450 331 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1451 {
1452 331 int64_t pos = avio_tell(pb);
1453 331 int version = 0;
1454 331 uint32_t tag = track->tag;
1455 331 int ret = 0;
1456
1457
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
331 if (track->mode == MODE_MOV) {
1458
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
39 if (track->par->sample_rate > UINT16_MAX || !track->par->ch_layout.nb_channels ||
1459
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 track->par->ch_layout.nb_channels > 2) {
1461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1462 ✗ tag = AV_RL32("lpcm");
1463 4 version = 2;
1464
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
61 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1465 26 mov_pcm_be_gt16(track->par->codec_id) ||
1466
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1467
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1469 11 version = 1;
1470 }
1471
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 3 times.
292 } else if (track->mode == MODE_MP4) {
1472
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 284 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
289 if (track->par->sample_rate > UINT16_MAX &&
1473 ✗ (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG))
1474 5 version = 1;
1475 }
1476
1477 331 avio_wb32(pb, 0); /* size */
1478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (mov->encryption_scheme != MOV_ENC_NONE) {
1479 ✗ ffio_wfourcc(pb, "enca");
1480 } else {
1481 331 avio_wl32(pb, tag); // store it byteswapped
1482 }
1483 331 avio_wb32(pb, 0); /* Reserved */
1484 331 avio_wb16(pb, 0); /* Reserved */
1485 331 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1486
1487 /* SoundDescription */
1488 331 avio_wb16(pb, version); /* Version */
1489 331 avio_wb16(pb, 0); /* Revision level */
1490 331 avio_wb32(pb, 0); /* Reserved */
1491
1492
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 327 times.
331 if (version == 2) {
1493 4 avio_wb16(pb, 3);
1494 4 avio_wb16(pb, 16);
1495 4 avio_wb16(pb, 0xfffe);
1496 4 avio_wb16(pb, 0);
1497 4 avio_wb32(pb, 0x00010000);
1498 4 avio_wb32(pb, 72);
1499 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1500 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1501 4 avio_wb32(pb, 0x7F000000);
1502 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1503 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1504 4 avio_wb32(pb, track->sample_size);
1505 4 avio_wb32(pb, get_samples_per_packet(track));
1506 } else {
1507 327 unsigned sample_rate = track->par->sample_rate;
1508
1509
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 292 times.
327 if (track->mode == MODE_MOV) {
1510 35 avio_wb16(pb, track->par->ch_layout.nb_channels);
1511
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1512
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1513 1 avio_wb16(pb, 8); /* bits per sample */
1514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1515 ✗ avio_wb16(pb, track->par->bits_per_coded_sample);
1516 else
1517 34 avio_wb16(pb, 16);
1518
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26 times.
35 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1519 } else { /* reserved for mp4/3gp */
1520
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 5 times.
579 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1521 287 0 : track->par->ch_layout.nb_channels);
1522
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 5 times.
292 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 track->par->codec_id == AV_CODEC_ID_ALAC) {
1524 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1525 } else {
1526 287 avio_wb16(pb, 16);
1527 }
1528 292 avio_wb16(pb, 0);
1529
1530
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 292 times.
297 while (sample_rate > UINT16_MAX)
1531 5 sample_rate >>= 1;
1532 }
1533
1534 327 avio_wb16(pb, 0); /* packet size (= 0) */
1535
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 322 times.
327 if (track->tag == MKTAG('i','a','m','f'))
1536 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 322 times.
322 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1538 ✗ avio_wb16(pb, 48000);
1539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 322 times.
322 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1540 ✗ avio_wb32(pb, track->par->sample_rate);
1541 else
1542 322 avio_wb16(pb, sample_rate);
1543
1544
1/2
✓ Branch 0 taken 327 times.
✗ Branch 1 not taken.
327 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1545 327 avio_wb16(pb, 0); /* Reserved */
1546 }
1547
1548
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 28 times.
331 if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */
1549
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 9 times.
22 if (mov_pcm_le_gt16(track->par->codec_id) ||
1550 11 mov_pcm_be_gt16(track->par->codec_id))
1551 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1552 else
1553 9 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1554 11 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1555 11 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1556 11 avio_wb32(pb, 2); /* Bytes per sample */
1557 }
1558
1559
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
331 if (track->mode == MODE_MOV &&
1560
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
39 (track->par->codec_id == AV_CODEC_ID_AAC ||
1561
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AC3 ||
1562
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1563
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1564
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1565
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1566
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1567
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 ||
1568
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) ||
1569
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1570 14 ret = mov_write_wave_tag(s, pb, track);
1571
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 51 times.
317 else if (track->tag == MKTAG('m','p','4','a'))
1572 266 ret = mov_write_esds_tag(pb, track);
1573 #if CONFIG_IAMFENC
1574
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 46 times.
51 else if (track->tag == MKTAG('i','a','m','f'))
1575 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1576 #endif
1577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1578 ✗ ret = mov_write_amr_tag(pb, track);
1579
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
46 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1580 7 ret = mov_write_ac3_tag(s, pb, track);
1581
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1582 4 ret = mov_write_eac3_tag(s, pb, track);
1583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1584 ✗ ret = mov_write_extradata_tag(pb, track);
1585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1586 ✗ ret = mov_write_wfex_tag(s, pb, track);
1587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1588 ✗ ret = mov_write_dfla_tag(pb, track);
1589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1590 ✗ ret = mov_write_dops_tag(s, pb, track);
1591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1592 ✗ ret = mov_write_dmlp_tag(s, pb, track);
1593
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO)
1594 1 ret = mov_write_mhac_tag(s, pb, track);
1595
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) {
1596
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (track->par->sample_rate > UINT16_MAX)
1597 5 mov_write_srat_tag(pb, track);
1598
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1599 7 ret = mov_write_chnl_tag(s, pb, track);
1600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1601 ✗ return ret;
1602 9 ret = mov_write_pcmc_tag(s, pb, track);
1603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1604 ✗ ret = mov_write_glbl_tag(pb, track);
1605
1606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (ret < 0)
1607 ✗ return ret;
1608
1609
3/4
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 289 times.
✗ Branch 3 not taken.
331 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1610
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 289 times.
289 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1611 ✗ return ret;
1612 }
1613
1614
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
331 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1615
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1616 ✗ return ret;
1617 }
1618
1619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (mov->encryption_scheme != MOV_ENC_NONE
1620 ✗ && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1621 ✗ return ret;
1622 }
1623
1624
3/4
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 289 times.
620 if (mov->write_btrt &&
1625 289 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1626 ✗ return ret;
1627
1628
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 42 times.
331 if (track->mode == MODE_MP4)
1629 289 track->entry_version = version;
1630
1631 331 ret = update_size(pb, pos);
1632 331 return ret;
1633 }
1634
1635 ✗ static int mov_write_d263_tag(AVIOContext *pb)
1636 {
1637 ✗ avio_wb32(pb, 0xf); /* size */
1638 ✗ ffio_wfourcc(pb, "d263");
1639 ✗ ffio_wfourcc(pb, "FFMP");
1640 ✗ avio_w8(pb, 0); /* decoder version */
1641 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1642 ✗ avio_w8(pb, 0xa); /* level */
1643 ✗ avio_w8(pb, 0); /* profile */
1644 ✗ return 0xf;
1645 }
1646
1647 2 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1648 {
1649 2 int64_t pos = avio_tell(pb);
1650
1651 2 avio_wb32(pb, 0);
1652 2 ffio_wfourcc(pb, "av1C");
1653 2 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1654 2 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1655 2 return update_size(pb, pos);
1656 }
1657
1658 59 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1659 {
1660 59 int64_t pos = avio_tell(pb);
1661
1662 59 avio_wb32(pb, 0);
1663 59 ffio_wfourcc(pb, "avcC");
1664 59 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1665 59 track->extradata_size[track->last_stsd_index]);
1666 59 return update_size(pb, pos);
1667 }
1668
1669 /* AVS3 Intelligent Media Coding
1670 * Information Technology - Intelligent Media Coding
1671 * Part 6: Intelligent Media Format
1672 */
1673 ✗ static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1674 {
1675 ✗ if (len < 4)
1676 ✗ return AVERROR_INVALIDDATA;
1677
1678 ✗ if (data[0] == 1) {
1679 // In Avs3DecoderConfigurationRecord format
1680 ✗ avio_write(pb, data, len);
1681 ✗ return 0;
1682 }
1683
1684 ✗ avio_w8(pb, 1); // version
1685 ✗ avio_wb16(pb, len); // sequence_header_length
1686 ✗ avio_write(pb, data, len); // sequence_header
1687 ✗ avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1688
1689 ✗ return 0;
1690 }
1691
1692 ✗ static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1693 {
1694 ✗ int64_t pos = avio_tell(pb);
1695 ✗ avio_wb32(pb, 0);
1696 ✗ ffio_wfourcc(pb, "av3c");
1697 ✗ mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1698 ✗ track->extradata_size[track->last_stsd_index]);
1699 ✗ return update_size(pb, pos);
1700 }
1701
1702 ✗ static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1703 {
1704 ✗ int64_t pos = avio_tell(pb);
1705
1706 ✗ avio_wb32(pb, 0);
1707 ✗ ffio_wfourcc(pb, "vpcC");
1708 ✗ ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1709 ✗ track->extradata_size[track->last_stsd_index], track->par);
1710 ✗ return update_size(pb, pos);
1711 }
1712
1713 11 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1714 {
1715 11 int64_t pos = avio_tell(pb);
1716
1717 11 avio_wb32(pb, 0);
1718 11 ffio_wfourcc(pb, "hvcC");
1719
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (track->tag == MKTAG('h','v','c','1'))
1720 3 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1721 3 track->extradata_size[track->last_stsd_index], 1, s);
1722 else
1723 8 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1724 8 track->extradata_size[track->last_stsd_index], 0, s);
1725 11 return update_size(pb, pos);
1726 }
1727
1728 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1729 {
1730 1 int64_t pos = avio_tell(pb);
1731 int ret;
1732
1733 1 avio_wb32(pb, 0);
1734 1 ffio_wfourcc(pb, "lhvC");
1735
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1736 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1737 1 track->extradata_size[track->last_stsd_index], 1, s);
1738 else
1739 ✗ ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1740 ✗ track->extradata_size[track->last_stsd_index], 0, s);
1741
1742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1743 ✗ avio_seek(pb, pos, SEEK_SET);
1744 ✗ return ret;
1745 }
1746
1747 1 return update_size(pb, pos);
1748 }
1749
1750 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1751 {
1752 1 int64_t pos = avio_tell(pb);
1753
1754 1 avio_wb32(pb, 0);
1755 1 ffio_wfourcc(pb, "evcC");
1756
1757
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1758 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1759 1 track->extradata_size[track->last_stsd_index], 1);
1760 else
1761 ✗ ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1762 ✗ track->extradata_size[track->last_stsd_index], 0);
1763
1764 1 return update_size(pb, pos);
1765 }
1766
1767 ✗ static int mov_write_lvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1768 {
1769 ✗ int64_t pos = avio_tell(pb);
1770
1771 ✗ avio_wb32(pb, 0);
1772 ✗ ffio_wfourcc(pb, "lvcC");
1773
1774 ✗ ff_isom_write_lvcc(pb, track->extradata[track->last_stsd_index],
1775 ✗ track->extradata_size[track->last_stsd_index], s);
1776
1777 ✗ return update_size(pb, pos);
1778 }
1779
1780 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1781 {
1782 1 int64_t pos = avio_tell(pb);
1783
1784 1 avio_wb32(pb, 0);
1785 1 ffio_wfourcc(pb, "vvcC");
1786
1787 1 avio_w8 (pb, 0); /* version */
1788 1 avio_wb24(pb, 0); /* flags */
1789
1790
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1791 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1792 1 track->extradata_size[track->last_stsd_index], 1);
1793 else
1794 ✗ ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1795 ✗ track->extradata_size[track->last_stsd_index], 0);
1796 1 return update_size(pb, pos);
1797 }
1798
1799 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1800 {
1801 1 int64_t pos = avio_tell(pb);
1802
1803 1 avio_wb32(pb, 0);
1804 1 ffio_wfourcc(pb, "apvC");
1805
1806 1 avio_w8 (pb, 0); /* version */
1807 1 avio_wb24(pb, 0); /* flags */
1808
1809 1 ff_isom_write_apvc(pb, track->apv, s);
1810
1811 1 return update_size(pb, pos);
1812 }
1813
1814 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1815 /* https://community.avid.com/forums/t/136517.aspx */
1816 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1817 {
1818 int interlaced;
1819 int cid;
1820 23 int display_width = track->par->width;
1821 const uint8_t *extradata;
1822
1823
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) {
1824
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) {
1825 /* looks like a DNxHD bit stream */
1826 23 extradata = track->extradata[track->last_stsd_index];
1827 } else {
1828 ✗ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1829 ✗ return 0;
1830 }
1831 } else {
1832 ✗ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1833 ✗ return 0;
1834 }
1835
1836 23 cid = AV_RB32(extradata + 0x28);
1837
1838 23 avio_wb32(pb, 24); /* size */
1839 23 ffio_wfourcc(pb, "ACLR");
1840 23 ffio_wfourcc(pb, "ACLR");
1841 23 ffio_wfourcc(pb, "0001");
1842 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1843 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1845 ✗ track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1846 23 avio_wb32(pb, 1);
1847 } else {
1848 ✗ avio_wb32(pb, 2);
1849 }
1850 23 avio_wb32(pb, 0); /* reserved */
1851
1852
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1853 12 int alp = extradata[0x07] & 1;
1854 12 int pma = (extradata[0x07] >> 2) & 1;
1855 12 int sbd = (extradata[0x21] >> 5) & 3;
1856 12 int ssc = (extradata[0x2C] >> 5) & 3;
1857 12 int clv = (extradata[0x2C] >> 1) & 3;
1858 12 int clf = extradata[0x2C] & 1;
1859
1860 12 avio_wb32(pb, 32);
1861 12 ffio_wfourcc(pb, "ADHR");
1862 12 ffio_wfourcc(pb, "0001");
1863 12 avio_wb32(pb, cid); // Compression ID
1864 // 0: 4:2:2 Sub Sampling
1865 // 1: 4:2:0 Sub Sampling
1866 // 2: 4:4:4 Sub Sampling
1867 12 avio_wb32(pb, ssc); // Sub Sampling Control
1868 // 1: 8-bits per sample
1869 // 2: 10-bits per sample
1870 // 3: 12-bits per sample
1871 12 avio_wb32(pb, sbd); // Sample Bit Depth
1872 // 0: Bitstream is encoded using the YCBCR format rules and tables
1873 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1874 12 avio_wb16(pb, clf); // Color Format
1875 // 0: ITU-R BT.709
1876 // 1: ITU-R BT.2020
1877 // 2: ITU-R BT.2020 C
1878 // 3: Out-of-band
1879 12 avio_wb16(pb, clv); // Color Volume
1880 // 0: Alpha channel not present
1881 // 1: Alpha channel present
1882 12 avio_wb16(pb, alp); // Alpha Present
1883 // 0: Alpha has not been applied to video channels
1884 // 1: Alpha has been applied to the video channels prior to encoding
1885 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1886 12 return 0;
1887 }
1888
1889 11 interlaced = extradata[5] & 2;
1890
1891 11 avio_wb32(pb, 24); /* size */
1892 11 ffio_wfourcc(pb, "APRG");
1893 11 ffio_wfourcc(pb, "APRG");
1894 11 ffio_wfourcc(pb, "0001");
1895 // 1 for progressive or 2 for interlaced
1896
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1897 11 avio_wb32(pb, 2);
1898 else
1899 ✗ avio_wb32(pb, 1);
1900 11 avio_wb32(pb, 0); /* reserved */
1901
1902 11 avio_wb32(pb, 120); /* size */
1903 11 ffio_wfourcc(pb, "ARES");
1904 11 ffio_wfourcc(pb, "ARES");
1905 11 ffio_wfourcc(pb, "0001");
1906 11 avio_wb32(pb, cid); /* cid */
1907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1908 ✗ && track->par->sample_aspect_ratio.den > 0)
1909 ✗ display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1910 11 avio_wb32(pb, display_width); // field width
1911
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1912 11 avio_wb32(pb, track->par->height / 2); // field height
1913 11 avio_wb32(pb, 2); // num fields
1914 11 avio_wb32(pb, 0); // num black lines (must be 0)
1915 // 4: HD1080i
1916 // 5: HD1080P
1917 // 6: HD720P
1918 11 avio_wb32(pb, 4); // video format
1919 } else {
1920 ✗ avio_wb32(pb, track->par->height);
1921 ✗ avio_wb32(pb, 1); // num fields
1922 ✗ avio_wb32(pb, 0);
1923 ✗ if (track->par->height == 1080)
1924 ✗ avio_wb32(pb, 5);
1925 else
1926 ✗ avio_wb32(pb, 6);
1927 }
1928 /* padding */
1929 11 ffio_fill(pb, 0, 10 * 8);
1930
1931 11 return 0;
1932 }
1933
1934 ✗ static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1935 {
1936 ✗ avio_wb32(pb, 12);
1937 ✗ ffio_wfourcc(pb, "DpxE");
1938 ✗ if (track->extradata_size[track->last_stsd_index] >= 12 &&
1939 ✗ !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1940 ✗ avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1941 } else {
1942 ✗ avio_wb32(pb, 1);
1943 }
1944 ✗ return 0;
1945 }
1946
1947 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1948 {
1949 int tag;
1950
1951
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1952
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1953
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');
1954 1 else tag = MKTAG('d','v','c',' ');
1955 ✗ }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1956 ✗ else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1957 ✗ else tag = MKTAG('d','v','p','p');
1958 ✗ } else if (track->par->height == 720) { /* HD 720 line */
1959 ✗ if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1960 ✗ else tag = MKTAG('d','v','h','p');
1961 ✗ } else if (track->par->height == 1080) { /* HD 1080 line */
1962 ✗ if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1963 ✗ else tag = MKTAG('d','v','h','6');
1964 } else {
1965 ✗ av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1966 ✗ return 0;
1967 }
1968
1969 1 return tag;
1970 }
1971
1972 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1973 {
1974 3 AVRational rational_framerate = st->avg_frame_rate;
1975 3 int rate = 0;
1976
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1977 3 rate = av_q2d(rational_framerate);
1978 3 return rate;
1979 }
1980
1981 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1982 {
1983 1 int tag = track->par->codec_tag;
1984 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1985 1 AVStream *st = track->st;
1986 1 int rate = defined_frame_rate(s, st);
1987
1988
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1989 ✗ tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1990
1991
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1992
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) {
1993 ✗ if (!interlaced) {
1994 ✗ if (rate == 24) tag = MKTAG('x','d','v','4');
1995 ✗ else if (rate == 25) tag = MKTAG('x','d','v','5');
1996 ✗ else if (rate == 30) tag = MKTAG('x','d','v','1');
1997 ✗ else if (rate == 50) tag = MKTAG('x','d','v','a');
1998 ✗ else if (rate == 60) tag = MKTAG('x','d','v','9');
1999 }
2000
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) {
2001 ✗ if (!interlaced) {
2002 ✗ if (rate == 24) tag = MKTAG('x','d','v','6');
2003 ✗ else if (rate == 25) tag = MKTAG('x','d','v','7');
2004 ✗ else if (rate == 30) tag = MKTAG('x','d','v','8');
2005 } else {
2006 ✗ if (rate == 25) tag = MKTAG('x','d','v','3');
2007 ✗ else if (rate == 30) tag = MKTAG('x','d','v','2');
2008 }
2009
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) {
2010 ✗ if (!interlaced) {
2011 ✗ if (rate == 24) tag = MKTAG('x','d','v','d');
2012 ✗ else if (rate == 25) tag = MKTAG('x','d','v','e');
2013 ✗ else if (rate == 30) tag = MKTAG('x','d','v','f');
2014 } else {
2015 ✗ if (rate == 25) tag = MKTAG('x','d','v','c');
2016 ✗ else if (rate == 30) tag = MKTAG('x','d','v','b');
2017 }
2018 }
2019 ✗ } else if (track->par->format == AV_PIX_FMT_YUV422P) {
2020 ✗ if (track->par->width == 1280 && track->par->height == 720) {
2021 ✗ if (!interlaced) {
2022 ✗ if (rate == 24) tag = MKTAG('x','d','5','4');
2023 ✗ else if (rate == 25) tag = MKTAG('x','d','5','5');
2024 ✗ else if (rate == 30) tag = MKTAG('x','d','5','1');
2025 ✗ else if (rate == 50) tag = MKTAG('x','d','5','a');
2026 ✗ else if (rate == 60) tag = MKTAG('x','d','5','9');
2027 }
2028 ✗ } else if (track->par->width == 1920 && track->par->height == 1080) {
2029 ✗ if (!interlaced) {
2030 ✗ if (rate == 24) tag = MKTAG('x','d','5','d');
2031 ✗ else if (rate == 25) tag = MKTAG('x','d','5','e');
2032 ✗ else if (rate == 30) tag = MKTAG('x','d','5','f');
2033 } else {
2034 ✗ if (rate == 25) tag = MKTAG('x','d','5','c');
2035 ✗ else if (rate == 30) tag = MKTAG('x','d','5','b');
2036 }
2037 }
2038 }
2039
2040 1 return tag;
2041 }
2042
2043 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
2044 {
2045 2 int tag = track->par->codec_tag;
2046 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2047 2 AVStream *st = track->st;
2048 2 int rate = defined_frame_rate(s, st);
2049
2050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
2051 ✗ tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
2052
2053
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
2054
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
2055 2 return tag;
2056
2057 ✗ if (track->par->format == AV_PIX_FMT_YUV420P10) {
2058 ✗ if (track->par->width == 960 && track->par->height == 720) {
2059 ✗ if (!interlaced) {
2060 ✗ if (rate == 24) tag = MKTAG('a','i','5','p');
2061 ✗ else if (rate == 25) tag = MKTAG('a','i','5','q');
2062 ✗ else if (rate == 30) tag = MKTAG('a','i','5','p');
2063 ✗ else if (rate == 50) tag = MKTAG('a','i','5','q');
2064 ✗ else if (rate == 60) tag = MKTAG('a','i','5','p');
2065 }
2066 ✗ } else if (track->par->width == 1440 && track->par->height == 1080) {
2067 ✗ if (!interlaced) {
2068 ✗ if (rate == 24) tag = MKTAG('a','i','5','3');
2069 ✗ else if (rate == 25) tag = MKTAG('a','i','5','2');
2070 ✗ else if (rate == 30) tag = MKTAG('a','i','5','3');
2071 } else {
2072 ✗ if (rate == 50) tag = MKTAG('a','i','5','5');
2073 ✗ else if (rate == 60) tag = MKTAG('a','i','5','6');
2074 }
2075 }
2076 ✗ } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
2077 ✗ if (track->par->width == 1280 && track->par->height == 720) {
2078 ✗ if (!interlaced) {
2079 ✗ if (rate == 24) tag = MKTAG('a','i','1','p');
2080 ✗ else if (rate == 25) tag = MKTAG('a','i','1','q');
2081 ✗ else if (rate == 30) tag = MKTAG('a','i','1','p');
2082 ✗ else if (rate == 50) tag = MKTAG('a','i','1','q');
2083 ✗ else if (rate == 60) tag = MKTAG('a','i','1','p');
2084 }
2085 ✗ } else if (track->par->width == 1920 && track->par->height == 1080) {
2086 ✗ if (!interlaced) {
2087 ✗ if (rate == 24) tag = MKTAG('a','i','1','3');
2088 ✗ else if (rate == 25) tag = MKTAG('a','i','1','2');
2089 ✗ else if (rate == 30) tag = MKTAG('a','i','1','3');
2090 } else {
2091 ✗ if (rate == 25) tag = MKTAG('a','i','1','5');
2092 ✗ else if (rate == 50) tag = MKTAG('a','i','1','5');
2093 ✗ else if (rate == 60) tag = MKTAG('a','i','1','6');
2094 }
2095 ✗ } else if ( track->par->width == 4096 && track->par->height == 2160
2096 ✗ || track->par->width == 3840 && track->par->height == 2160
2097 ✗ || track->par->width == 2048 && track->par->height == 1080) {
2098 ✗ tag = MKTAG('a','i','v','x');
2099 }
2100 }
2101
2102 ✗ return tag;
2103 }
2104
2105 ✗ static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
2106 {
2107 ✗ int tag = track->par->codec_tag;
2108
2109 ✗ if (!tag)
2110 ✗ tag = MKTAG('e', 'v', 'c', '1');
2111
2112 ✗ return tag;
2113 }
2114
2115 ✗ static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
2116 {
2117 ✗ int tag = track->par->codec_tag;
2118
2119 ✗ if (!tag)
2120 ✗ tag = MKTAG('a', 'p', 'v', '1');
2121
2122 ✗ return tag;
2123 }
2124
2125
2126 static const struct {
2127 enum AVPixelFormat pix_fmt;
2128 uint32_t tag;
2129 unsigned bps;
2130 } mov_pix_fmt_tags[] = {
2131 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
2132 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2133 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2134 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2135 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2136 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2137 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2138 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2139 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2140 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2141 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2142 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2143 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2144 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2145 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2146 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2147 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2148 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2149 };
2150
2151 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2152 {
2153 23 int tag = MKTAG('A','V','d','n');
2154
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2155
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2156 12 tag = MKTAG('A','V','d','h');
2157 23 return tag;
2158 }
2159
2160 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2161 {
2162 17 int tag = track->par->codec_tag;
2163 int i;
2164 enum AVPixelFormat pix_fmt;
2165
2166
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++) {
2167
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2168 17 tag = mov_pix_fmt_tags[i].tag;
2169 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2170
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2171 5 break;
2172 }
2173 }
2174
2175 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2176 17 track->par->bits_per_coded_sample);
2177
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2179 ✗ track->par->format != AV_PIX_FMT_GRAY8 &&
2180 ✗ track->par->format != AV_PIX_FMT_NONE)
2181 ✗ av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2182 ✗ av_get_pix_fmt_name(track->par->format));
2183 17 return tag;
2184 }
2185
2186 170 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2187 {
2188 170 unsigned int tag = track->par->codec_tag;
2189
2190 // "rtp " is used to distinguish internally created RTP-hint tracks
2191 // (with rtp_ctx) from other tracks.
2192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (tag == MKTAG('r','t','p',' '))
2193 ✗ tag = 0;
2194
3/4
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 36 times.
170 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
2195
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2196
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 17 times.
133 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2197
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 track->par->codec_id == AV_CODEC_ID_H263 ||
2198
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 2 times.
116 track->par->codec_id == AV_CODEC_ID_H264 ||
2199
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 23 times.
114 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2200
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 72 times.
181 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
2201 90 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2202
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2203 1 tag = mov_get_dv_codec_tag(s, track);
2204
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2205 17 tag = mov_get_rawvideo_codec_tag(s, track);
2206
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2207 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2208
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2209 2 tag = mov_get_h264_codec_tag(s, track);
2210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2211 ✗ tag = mov_get_evc_codec_tag(s, track);
2212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2213 ✗ tag = mov_get_apv_codec_tag(s, track);
2214
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2215 23 tag = mov_get_dnxhd_codec_tag(s, track);
2216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2217 ✗ tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2218 ✗ if (!tag) { // if no mac fcc found, try with Microsoft tags
2219 ✗ tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2220 ✗ if (tag)
2221 ✗ av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2222 "the file may be unplayable!\n");
2223 }
2224
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2225 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2227 ✗ int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2228 ✗ if (ms_tag) {
2229 ✗ tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2230 ✗ av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2231 "the file may be unplayable!\n");
2232 }
2233 }
2234 ✗ } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2235 ✗ tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2236 }
2237
2238 170 return tag;
2239 }
2240
2241 static const AVCodecTag codec_cover_image_tags[] = {
2242 { AV_CODEC_ID_MJPEG, 0xD },
2243 { AV_CODEC_ID_PNG, 0xE },
2244 { AV_CODEC_ID_BMP, 0x1B },
2245 { AV_CODEC_ID_NONE, 0 },
2246 };
2247
2248 236 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2249 unsigned int tag, int codec_id)
2250 {
2251 int i;
2252
2253 /**
2254 * Check that tag + id is in the table
2255 */
2256
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
236 for (i = 0; tags && tags[i]; i++) {
2257 236 const AVCodecTag *codec_tags = tags[i];
2258
1/2
✓ Branch 0 taken 5018 times.
✗ Branch 1 not taken.
5018 while (codec_tags->id != AV_CODEC_ID_NONE) {
2259
2/2
✓ Branch 2 taken 558 times.
✓ Branch 3 taken 4460 times.
5018 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2260
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 322 times.
558 codec_tags->id == codec_id)
2261 236 return codec_tags->tag;
2262 4782 codec_tags++;
2263 }
2264 }
2265 ✗ return 0;
2266 }
2267
2268 408 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2269 {
2270
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 406 times.
408 if (is_cover_image(track->st))
2271 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2272
2273
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 405 times.
406 if (track->mode == MODE_IPOD)
2274
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") &&
2275
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2276 1 !av_match_ext(s->url, "m4b"))
2277 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2278 "Quicktime/Ipod might not play the file\n");
2279
2280
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 236 times.
406 if (track->mode == MODE_MOV) {
2281 170 return mov_get_codec_tag(s, track);
2282 } else
2283 236 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2284 236 track->par->codec_id);
2285 }
2286
2287 /** Write uuid atom.
2288 * Needed to make file play in iPods running newest firmware
2289 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2290 */
2291 ✗ static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2292 {
2293 ✗ avio_wb32(pb, 28);
2294 ✗ ffio_wfourcc(pb, "uuid");
2295 ✗ avio_wb32(pb, 0x6b6840f2);
2296 ✗ avio_wb32(pb, 0x5f244fc5);
2297 ✗ avio_wb32(pb, 0xba39a51b);
2298 ✗ avio_wb32(pb, 0xcf0323f3);
2299 ✗ avio_wb32(pb, 0x0);
2300 ✗ return 28;
2301 }
2302
2303 static const uint16_t fiel_data[] = {
2304 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2305 };
2306
2307 101 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2308 {
2309 101 unsigned mov_field_order = 0;
2310
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2311 101 mov_field_order = fiel_data[field_order];
2312 else
2313 ✗ return 0;
2314 101 avio_wb32(pb, 10);
2315 101 ffio_wfourcc(pb, "fiel");
2316 101 avio_wb16(pb, mov_field_order);
2317 101 return 10;
2318 }
2319
2320 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2321 {
2322 6 MOVMuxContext *mov = s->priv_data;
2323 6 int ret = AVERROR_BUG;
2324 6 int64_t pos = avio_tell(pb);
2325 6 avio_wb32(pb, 0); /* size */
2326 6 avio_wl32(pb, track->tag); // store it byteswapped
2327 6 avio_wb32(pb, 0); /* Reserved */
2328 6 avio_wb16(pb, 0); /* Reserved */
2329 6 avio_wb16(pb, 1); /* Data-reference index */
2330
2331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2332 ✗ mov_write_esds_tag(pb, track);
2333
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2334
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2335 2 case MOV_ISMV_TTML_TAG:
2336 // ISMV dfxp requires no extradata.
2337 4 break;
2338 2 case MOV_MP4_TTML_TAG:
2339 // As specified in 14496-30, XMLSubtitleSampleEntry
2340 // Namespace
2341 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2342 // Empty schema_location
2343 2 avio_w8(pb, 0);
2344 // Empty auxiliary_mime_types
2345 2 avio_w8(pb, 0);
2346 2 break;
2347 ✗ default:
2348 ✗ av_log(NULL, AV_LOG_ERROR,
2349 "Unknown codec tag '%s' utilized for TTML stream with "
2350 "index %d (track id %d)!\n",
2351 ✗ av_fourcc2str(track->par->codec_tag), track->st->index,
2352 track->track_id);
2353 ✗ return AVERROR(EINVAL);
2354 }
2355
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2356 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2357
2358
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 &&
2359 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2360 ✗ return ret;
2361
2362 6 return update_size(pb, pos);
2363 }
2364
2365 1 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2366 {
2367 int8_t stereo_mode;
2368
2369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo_3d->flags != 0) {
2370 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2371 ✗ return 0;
2372 }
2373
2374
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo_3d->type) {
2375 ✗ case AV_STEREO3D_2D:
2376 ✗ stereo_mode = 0;
2377 ✗ break;
2378 ✗ case AV_STEREO3D_TOPBOTTOM:
2379 ✗ stereo_mode = 1;
2380 ✗ break;
2381 1 case AV_STEREO3D_SIDEBYSIDE:
2382 1 stereo_mode = 2;
2383 1 break;
2384 ✗ default:
2385 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2386 ✗ return 0;
2387 }
2388 1 avio_wb32(pb, 13); /* size */
2389 1 ffio_wfourcc(pb, "st3d");
2390 1 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2391 1 avio_w8(pb, stereo_mode);
2392 1 return 13;
2393 }
2394
2395 ✗ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2396 {
2397 int64_t sv3d_pos, svhd_pos, proj_pos;
2398 ✗ const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2399
2400 ✗ if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2401 ✗ spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2402 ✗ spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2403 ✗ av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2404 ✗ return 0;
2405 }
2406
2407 ✗ sv3d_pos = avio_tell(pb);
2408 ✗ avio_wb32(pb, 0); /* size */
2409 ✗ ffio_wfourcc(pb, "sv3d");
2410
2411 ✗ svhd_pos = avio_tell(pb);
2412 ✗ avio_wb32(pb, 0); /* size */
2413 ✗ ffio_wfourcc(pb, "svhd");
2414 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2415 ✗ avio_put_str(pb, metadata_source);
2416 ✗ update_size(pb, svhd_pos);
2417
2418 ✗ proj_pos = avio_tell(pb);
2419 ✗ avio_wb32(pb, 0); /* size */
2420 ✗ ffio_wfourcc(pb, "proj");
2421
2422 ✗ avio_wb32(pb, 24); /* size */
2423 ✗ ffio_wfourcc(pb, "prhd");
2424 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2425 ✗ avio_wb32(pb, spherical_mapping->yaw);
2426 ✗ avio_wb32(pb, spherical_mapping->pitch);
2427 ✗ avio_wb32(pb, spherical_mapping->roll);
2428
2429 ✗ switch (spherical_mapping->projection) {
2430 ✗ case AV_SPHERICAL_EQUIRECTANGULAR:
2431 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2432 ✗ avio_wb32(pb, 28); /* size */
2433 ✗ ffio_wfourcc(pb, "equi");
2434 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2435 ✗ avio_wb32(pb, spherical_mapping->bound_top);
2436 ✗ avio_wb32(pb, spherical_mapping->bound_bottom);
2437 ✗ avio_wb32(pb, spherical_mapping->bound_left);
2438 ✗ avio_wb32(pb, spherical_mapping->bound_right);
2439 ✗ break;
2440 ✗ case AV_SPHERICAL_CUBEMAP:
2441 ✗ avio_wb32(pb, 20); /* size */
2442 ✗ ffio_wfourcc(pb, "cbmp");
2443 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2444 ✗ avio_wb32(pb, 0); /* layout */
2445 ✗ avio_wb32(pb, spherical_mapping->padding); /* padding */
2446 ✗ break;
2447 }
2448 ✗ update_size(pb, proj_pos);
2449
2450 ✗ return update_size(pb, sv3d_pos);
2451 }
2452
2453 5 static inline int64_t rescale_rational(AVRational q, int b)
2454 {
2455 5 return av_rescale(q.num, b, q.den);
2456 }
2457
2458 2 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2459 const AVStereo3D *stereo3d)
2460 {
2461
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!stereo3d->horizontal_field_of_view.num)
2462 1 return;
2463
2464 1 avio_wb32(pb, 12); /* size */
2465 1 ffio_wfourcc(pb, "hfov");
2466 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2467 }
2468
2469 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2470 const AVSphericalMapping *spherical_mapping)
2471 {
2472 1 avio_wb32(pb, 24); /* size */
2473 1 ffio_wfourcc(pb, "proj");
2474 1 avio_wb32(pb, 16); /* size */
2475 1 ffio_wfourcc(pb, "prji");
2476 1 avio_wb32(pb, 0); /* version + flags */
2477
2478
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) {
2479 1 case AV_SPHERICAL_RECTILINEAR:
2480 1 ffio_wfourcc(pb, "rect");
2481 1 break;
2482 ✗ case AV_SPHERICAL_EQUIRECTANGULAR:
2483 ✗ ffio_wfourcc(pb, "equi");
2484 ✗ break;
2485 ✗ case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2486 ✗ ffio_wfourcc(pb, "hequ");
2487 ✗ break;
2488 ✗ case AV_SPHERICAL_FISHEYE:
2489 ✗ ffio_wfourcc(pb, "fish");
2490 ✗ break;
2491 ✗ default:
2492 ✗ av_assert0(0);
2493 }
2494 1 }
2495
2496 2 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2497 const AVStereo3D *stereo3d)
2498 {
2499 2 int64_t pos = avio_tell(pb);
2500 2 int view = 0;
2501
2502 2 avio_wb32(pb, 0); /* size */
2503 2 ffio_wfourcc(pb, "eyes");
2504
2505 // stri is mandatory
2506 2 avio_wb32(pb, 13); /* size */
2507 2 ffio_wfourcc(pb, "stri");
2508 2 avio_wb32(pb, 0); /* version + flags */
2509
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 switch (stereo3d->view) {
2510 ✗ case AV_STEREO3D_VIEW_LEFT:
2511 ✗ view |= 1 << 0;
2512 ✗ break;
2513 ✗ case AV_STEREO3D_VIEW_RIGHT:
2514 ✗ view |= 1 << 1;
2515 ✗ break;
2516 2 case AV_STEREO3D_VIEW_PACKED:
2517 2 view |= (1 << 0) | (1 << 1);
2518 2 break;
2519 }
2520 2 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2521 2 avio_w8(pb, view);
2522
2523 // hero is optional
2524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2525 ✗ avio_wb32(pb, 13); /* size */
2526 ✗ ffio_wfourcc(pb, "hero");
2527 ✗ avio_wb32(pb, 0); /* version + flags */
2528 ✗ avio_w8(pb, stereo3d->primary_eye);
2529 }
2530
2531 // it's not clear if cams is mandatory or optional
2532
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->baseline) {
2533 1 avio_wb32(pb, 24); /* size */
2534 1 ffio_wfourcc(pb, "cams");
2535 1 avio_wb32(pb, 16); /* size */
2536 1 ffio_wfourcc(pb, "blin");
2537 1 avio_wb32(pb, 0); /* version + flags */
2538 1 avio_wb32(pb, stereo3d->baseline);
2539 }
2540
2541 // it's not clear if cmfy is mandatory or optional
2542
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->horizontal_disparity_adjustment.num) {
2543 1 avio_wb32(pb, 24); /* size */
2544 1 ffio_wfourcc(pb, "cmfy");
2545 1 avio_wb32(pb, 16); /* size */
2546 1 ffio_wfourcc(pb, "dadj");
2547 1 avio_wb32(pb, 0); /* version + flags */
2548 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2549 }
2550
2551 2 return update_size(pb, pos);
2552 }
2553
2554 2 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2555 const AVStereo3D *stereo3d,
2556 const AVSphericalMapping *spherical_mapping)
2557 {
2558 int64_t pos;
2559
2560
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping &&
2561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2562 ✗ spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2563 ✗ spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2564 ✗ spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2565 ✗ av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2566 ✗ spherical_mapping->projection);
2567 ✗ spherical_mapping = NULL;
2568 }
2569
2570
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2571
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2573 ✗ stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2574 ✗ !stereo3d->baseline &&
2575 ✗ !stereo3d->horizontal_disparity_adjustment.num))) {
2576 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2577 ✗ stereo3d = NULL;
2578 }
2579
2580
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (!spherical_mapping && !stereo3d)
2581 ✗ return 0;
2582
2583 2 pos = avio_tell(pb);
2584 2 avio_wb32(pb, 0); /* size */
2585 2 ffio_wfourcc(pb, "vexu");
2586
2587
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping)
2588 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2589
2590
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (stereo3d)
2591 2 mov_write_eyes_tag(s, pb, stereo3d);
2592
2593 2 return update_size(pb, pos);
2594 }
2595
2596 2 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2597 {
2598 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2599
2600 2 avio_wb32(pb, 32); /* size = 8 + 24 */
2601
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (dovi->dv_profile > 10)
2602 ✗ ffio_wfourcc(pb, "dvwC");
2603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (dovi->dv_profile > 7)
2604 ✗ ffio_wfourcc(pb, "dvvC");
2605 else
2606 2 ffio_wfourcc(pb, "dvcC");
2607
2608 2 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2609 2 avio_write(pb, buf, sizeof(buf));
2610
2611 2 return 32; /* 8 + 24 */
2612 }
2613
2614 2 static int mov_write_hvce_tag(AVIOContext *pb, const AVPacketSideData *sd)
2615 {
2616 2 avio_wb32(pb, 8 + sd->size);
2617 2 ffio_wfourcc(pb, "hvcE");
2618 2 avio_write(pb, sd->data, sd->size);
2619 2 return 8 + sd->size;
2620 }
2621
2622 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2623 uint32_t top, uint32_t bottom,
2624 uint32_t left, uint32_t right)
2625 {
2626 5 uint32_t cropped_width = track->par->width - left - right;
2627 5 uint32_t cropped_height = track->height - top - bottom;
2628 AVRational horizOff =
2629 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2630 5 (AVRational) { left, 1 });
2631 AVRational vertOff =
2632 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2633 5 (AVRational) { top, 1 });
2634
2635 5 avio_wb32(pb, 40);
2636 5 ffio_wfourcc(pb, "clap");
2637 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2638 5 avio_wb32(pb, 1); /* apertureWidthD */
2639 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2640 5 avio_wb32(pb, 1); /* apertureHeightD */
2641
2642 5 avio_wb32(pb, -horizOff.num);
2643 5 avio_wb32(pb, horizOff.den);
2644 5 avio_wb32(pb, -vertOff.num);
2645 5 avio_wb32(pb, vertOff.den);
2646
2647 5 return 40;
2648 }
2649
2650 27 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2651 {
2652 AVRational sar;
2653 27 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2654 27 track->par->sample_aspect_ratio.den, INT_MAX);
2655
2656 27 avio_wb32(pb, 16);
2657 27 ffio_wfourcc(pb, "pasp");
2658 27 avio_wb32(pb, sar.num);
2659 27 avio_wb32(pb, sar.den);
2660 27 return 16;
2661 }
2662
2663 ✗ static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2664 {
2665 ✗ uint32_t gama = 0;
2666 ✗ if (gamma <= 0.0)
2667 ✗ gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2668 ✗ av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2669
2670 ✗ if (gamma > 1e-6) {
2671 ✗ gama = (uint32_t)lrint((double)(1<<16) * gamma);
2672 ✗ av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2673
2674 ✗ av_assert0(track->mode == MODE_MOV);
2675 ✗ avio_wb32(pb, 12);
2676 ✗ ffio_wfourcc(pb, "gama");
2677 ✗ avio_wb32(pb, gama);
2678 ✗ return 12;
2679 } else {
2680 ✗ av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2681 }
2682 ✗ return 0;
2683 }
2684
2685 12 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2686 {
2687 12 int64_t pos = avio_tell(pb);
2688
2689 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2690 // Ref (MP4): ISO/IEC 14496-12:2012
2691
2692
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (prefer_icc) {
2693 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2694 4 track->st->codecpar->nb_coded_side_data,
2695 AV_PKT_DATA_ICC_PROFILE);
2696
2697
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2698 ✗ avio_wb32(pb, 12 + sd->size);
2699 ✗ ffio_wfourcc(pb, "colr");
2700 ✗ ffio_wfourcc(pb, "prof");
2701 ✗ avio_write(pb, sd->data, sd->size);
2702 ✗ return 12 + sd->size;
2703 }
2704 else {
2705 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2706 }
2707 }
2708
2709 /* We should only ever be called for MOV, MP4 and AVIF. */
2710
3/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
12 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2711 track->mode == MODE_AVIF);
2712
2713 12 avio_wb32(pb, 0); /* size */
2714 12 ffio_wfourcc(pb, "colr");
2715
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2716 4 ffio_wfourcc(pb, "nclx");
2717 else
2718 8 ffio_wfourcc(pb, "nclc");
2719 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2720 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2721 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2722 12 avio_wb16(pb, track->par->color_primaries);
2723 12 avio_wb16(pb, track->par->color_trc);
2724 12 avio_wb16(pb, track->par->color_space);
2725
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2726 4 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2727 4 avio_w8(pb, full_range << 7);
2728 }
2729
2730 12 return update_size(pb, pos);
2731 }
2732
2733 229 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2734 {
2735 const AVPacketSideData *side_data;
2736 const AVContentLightMetadata *content_light_metadata;
2737
2738 229 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2739 229 track->st->codecpar->nb_coded_side_data,
2740 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2741
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
229 if (!side_data) {
2742 229 return 0;
2743 }
2744 ✗ content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2745
2746 ✗ avio_wb32(pb, 12); // size
2747 ✗ ffio_wfourcc(pb, "clli");
2748 ✗ avio_wb16(pb, content_light_metadata->MaxCLL);
2749 ✗ avio_wb16(pb, content_light_metadata->MaxFALL);
2750 ✗ return 12;
2751 }
2752
2753 229 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2754 {
2755 229 const int chroma_den = 50000;
2756 229 const int luma_den = 10000;
2757 const AVPacketSideData *side_data;
2758 229 const AVMasteringDisplayMetadata *metadata = NULL;
2759
2760 229 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2761 229 track->st->codecpar->nb_coded_side_data,
2762 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 if (side_data)
2764 ✗ metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2765
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
229 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2766 229 return 0;
2767 }
2768
2769 ✗ avio_wb32(pb, 32); // size
2770 ✗ ffio_wfourcc(pb, "mdcv");
2771 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2772 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2773 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2774 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2775 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2776 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2777 ✗ avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2778 ✗ avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2779 ✗ avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2780 ✗ avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2781 ✗ return 32;
2782 }
2783
2784 229 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2785 {
2786 229 const int illuminance_den = 10000;
2787 229 const int ambient_den = 50000;
2788 const AVPacketSideData *side_data;
2789 const AVAmbientViewingEnvironment *ambient;
2790
2791
2792 229 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2793 229 track->st->codecpar->nb_coded_side_data,
2794 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2795
2796
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 1 times.
229 if (!side_data)
2797 228 return 0;
2798
2799 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2800
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)
2801 ✗ return 0;
2802
2803 1 avio_wb32(pb, 16); // size
2804 1 ffio_wfourcc(pb, "amve");
2805 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2806 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2807 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2808 1 return 16;
2809 }
2810
2811 235 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2812 {
2813 AVDictionaryEntry *encoder;
2814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2815
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
234 || (track->par->width == 1440 && track->par->height == 1080)
2816
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 234 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 221 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
470 || (track->par->width == 1920 && track->par->height == 1080);
2817
2818
1/2
✓ Branch 0 taken 235 times.
✗ Branch 1 not taken.
235 if ((track->mode == MODE_AVIF ||
2819
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 144 times.
235 track->mode == MODE_MOV ||
2820
4/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 160 times.
✓ Branch 3 taken 69 times.
320 track->mode == MODE_MP4) &&
2821 229 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2822 160 av_strlcpy(compressor_name, encoder->value, 32);
2823
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
75 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2824 ✗ int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2825 ✗ AVStream *st = track->st;
2826 ✗ int rate = defined_frame_rate(NULL, st);
2827 ✗ av_strlcatf(compressor_name, len, "XDCAM");
2828 ✗ if (track->par->format == AV_PIX_FMT_YUV422P) {
2829 ✗ av_strlcatf(compressor_name, len, " HD422");
2830 ✗ } else if(track->par->width == 1440) {
2831 ✗ av_strlcatf(compressor_name, len, " HD");
2832 } else
2833 ✗ av_strlcatf(compressor_name, len, " EX");
2834
2835 ✗ av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2836
2837 ✗ av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2838 }
2839 235 }
2840
2841 ✗ static int mov_write_ccst_tag(AVIOContext *pb)
2842 {
2843 ✗ int64_t pos = avio_tell(pb);
2844 // Write sane defaults:
2845 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2846 // intra_pred_used = 1 : intra prediction may or may not be used.
2847 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2848 // reference images can be used.
2849 ✗ uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2850 (1 << 6) | /* intra_pred_used */
2851 (15 << 2); /* max_ref_per_pic */
2852 ✗ avio_wb32(pb, 0); /* size */
2853 ✗ ffio_wfourcc(pb, "ccst");
2854 ✗ avio_wb32(pb, 0); /* Version & flags */
2855 ✗ avio_w8(pb, ccstValue);
2856 ✗ avio_wb24(pb, 0); /* reserved */
2857 ✗ return update_size(pb, pos);
2858 }
2859
2860 ✗ static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2861 {
2862 ✗ int64_t pos = avio_tell(pb);
2863 ✗ avio_wb32(pb, 0); /* size */
2864 ✗ ffio_wfourcc(pb, aux_type);
2865 ✗ avio_wb32(pb, 0); /* Version & flags */
2866 ✗ avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2867 ✗ return update_size(pb, pos);
2868 }
2869
2870 235 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2871 {
2872 235 int ret = AVERROR_BUG;
2873 235 int64_t pos = avio_tell(pb);
2874 const AVPacketSideData *sd;
2875 235 char compressor_name[32] = { 0 };
2876 235 int avid = 0;
2877
2878
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)
2879
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
235 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2880
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
235 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2881
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
235 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2882
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
235 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2883
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 218 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 231 times.
470 || track->par->codec_id == AV_CODEC_ID_V210);
2884
2885 235 avio_wb32(pb, 0); /* size */
2886
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 229 times.
235 if (mov->encryption_scheme != MOV_ENC_NONE) {
2887 6 ffio_wfourcc(pb, "encv");
2888 } else {
2889 229 avio_wl32(pb, track->tag); // store it byteswapped
2890 }
2891 235 avio_wb32(pb, 0); /* Reserved */
2892 235 avio_wb16(pb, 0); /* Reserved */
2893 235 avio_wb16(pb, 1); /* Data-reference index */
2894
2895
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 231 times.
235 if (uncompressed_ycbcr) {
2896 4 avio_wb16(pb, 2); /* Codec stream version */
2897 } else {
2898 231 avio_wb16(pb, 0); /* Codec stream version */
2899 }
2900 235 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2901
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 91 times.
235 if (track->mode == MODE_MOV) {
2902 144 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2903
3/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 127 times.
144 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2904 17 avio_wb32(pb, 0); /* Temporal Quality */
2905 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2906 } else {
2907 127 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2908 127 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2909 }
2910 } else {
2911 91 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2912 }
2913 235 avio_wb16(pb, track->par->width); /* Video width */
2914 235 avio_wb16(pb, track->height); /* Video height */
2915 235 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2916 235 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2917 235 avio_wb32(pb, 0); /* Data size (= 0) */
2918 235 avio_wb16(pb, 1); /* Frame count (= 1) */
2919
2920 235 find_compressor(compressor_name, 32, track);
2921 235 avio_w8(pb, strlen(compressor_name));
2922 235 avio_write(pb, compressor_name, 31);
2923
2924
3/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
235 if (track->mode == MODE_MOV && track->par->codec_id == AV_CODEC_ID_V210)
2925 ✗ avio_wb16(pb, 0x18);
2926
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 111 times.
235 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2927 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2928
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2929 else
2930 202 avio_wb16(pb, 0x18); /* Reserved */
2931
2932
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 139 times.
240 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2933 int pal_size, i;
2934 5 avio_wb16(pb, 0); /* Color table ID */
2935 5 avio_wb32(pb, 0); /* Color table seed */
2936 5 avio_wb16(pb, 0x8000); /* Color table flags */
2937
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)
2938 ✗ return AVERROR(EINVAL);
2939 5 pal_size = 1 << track->par->bits_per_coded_sample;
2940 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2941
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2942 1040 uint32_t rgb = track->palette[i];
2943 1040 uint16_t r = (rgb >> 16) & 0xff;
2944 1040 uint16_t g = (rgb >> 8) & 0xff;
2945 1040 uint16_t b = rgb & 0xff;
2946 1040 avio_wb16(pb, 0);
2947 1040 avio_wb16(pb, (r << 8) | r);
2948 1040 avio_wb16(pb, (g << 8) | g);
2949 1040 avio_wb16(pb, (b << 8) | b);
2950 }
2951 } else
2952 230 avio_wb16(pb, 0xffff); /* Reserved */
2953
2954
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 198 times.
235 if (track->tag == MKTAG('m','p','4','v'))
2955 37 mov_write_esds_tag(pb, track);
2956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 else if (track->par->codec_id == AV_CODEC_ID_H263)
2957 ✗ mov_write_d263_tag(pb);
2958
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 3 times.
198 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2960 3 mov_write_extradata_tag(pb, track);
2961 3 avio_wb32(pb, 0);
2962
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 172 times.
195 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2963 23 mov_write_avid_tag(pb, track);
2964 23 avid = 1;
2965
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 161 times.
172 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2966 11 mov_write_hvcc_tag(mov->fc, pb, track);
2967
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2968 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2970 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2971 }
2972
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160 times.
161 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2973 1 mov_write_vvcc_tag(pb, track);
2974
16/30
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 59 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 59 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 59 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 59 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 59 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 59 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 59 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 59 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 59 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 59 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 59 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 59 times.
✗ Branch 29 not taken.
160 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2975 59 mov_write_avcc_tag(pb, track);
2976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 if (track->mode == MODE_IPOD)
2977 ✗ mov_write_uuid_tag_ipod(pb);
2978 }
2979
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2980 1 mov_write_evcc_tag(pb, track);
2981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 } else if (track->par->codec_id == AV_CODEC_ID_LCEVC) {
2982 ✗ mov_write_lvcc_tag(mov->fc, pb, track);
2983
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2984 1 mov_write_apvc_tag(mov->fc, pb, track);
2985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2986 ✗ mov_write_vpcc_tag(mov->fc, pb, track);
2987
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 97 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2988 2 mov_write_av1c_tag(pb, track);
2989
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)
2990 ✗ mov_write_dvc1_tag(pb, track);
2991
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2992
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2993 /* Don't write any potential extradata here - the cropping
2994 * is signalled via the normal width/height fields. */
2995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2996 ✗ if (track->par->codec_tag == MKTAG('R','1','0','k'))
2997 ✗ mov_write_dpxe_tag(pb, track);
2998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2999 ✗ mov_write_av3c_tag(pb, track);
3000
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
3001 4 mov_write_glbl_tag(pb, track);
3002
3003
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 59 times.
235 if (track->par->codec_id != AV_CODEC_ID_H264 &&
3004
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 31 times.
176 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
3005
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 23 times.
145 track->par->codec_id != AV_CODEC_ID_DNXHD) {
3006 122 int field_order = track->par->field_order;
3007
3008
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 21 times.
122 if (field_order != AV_FIELD_UNKNOWN)
3009 101 mov_write_fiel_tag(pb, track, field_order);
3010 }
3011
3012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
3013 ✗ if (track->mode == MODE_MOV)
3014 ✗ mov_write_gama_tag(s, pb, track, mov->gamma);
3015 else
3016 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
3017 }
3018
5/6
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 85 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
464 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
3019 466 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
3020
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 221 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
237 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
3021
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
3022
5/6
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 217 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 217 times.
446 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
3023 217 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
3024 AV_PKT_DATA_ICC_PROFILE)) {
3025
3/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
12 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
3026 12 mov_write_colr_tag(pb, track, prefer_icc);
3027 }
3028
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
3029 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
3030 }
3031
3032
4/4
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 6 times.
235 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
3033 229 mov_write_clli_tag(pb, track);
3034 229 mov_write_mdcv_tag(pb, track);
3035 229 mov_write_amve_tag(pb, track);
3036 }
3037
3038
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 150 times.
235 if (track->mode == MODE_MP4) {
3039 85 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3040 85 track->st->codecpar->nb_coded_side_data,
3041 AV_PKT_DATA_STEREO3D);
3042 85 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3043 85 track->st->codecpar->nb_coded_side_data,
3044 AV_PKT_DATA_SPHERICAL);
3045
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
85 if (stereo_3d && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3046 1 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
3047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 else if (stereo_3d)
3048 ✗ av_log(s, AV_LOG_WARNING, "Writing supported 'st3d' metadata requires -strict unofficial.\n");
3049
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
85 if (spherical_mapping && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3050 ✗ mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
3051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 else if (spherical_mapping)
3052 ✗ av_log(s, AV_LOG_WARNING, "Writing supported 'sv3d' metadata requires -strict unofficial.\n");
3053 }
3054
3055
4/4
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 6 times.
235 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
3056
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 82 times.
85 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
3057 147 const AVStereo3D *stereo3d = NULL;
3058 147 const AVSphericalMapping *spherical_mapping = NULL;
3059
3060 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3061 147 track->st->codecpar->nb_coded_side_data,
3062 AV_PKT_DATA_STEREO3D);
3063
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (sd)
3064 2 stereo3d = (AVStereo3D *)sd->data;
3065
3066 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3067 147 track->st->codecpar->nb_coded_side_data,
3068 AV_PKT_DATA_SPHERICAL);
3069
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 146 times.
147 if (sd)
3070 1 spherical_mapping = (AVSphericalMapping *)sd->data;
3071
3072
3/4
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 145 times.
147 if (stereo3d || spherical_mapping)
3073 2 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
3074
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (stereo3d)
3075 2 mov_write_hfov_tag(s, pb, stereo3d);
3076 }
3077
3078
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 150 times.
235 if (track->mode == MODE_MP4) {
3079 85 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3080 85 track->st->codecpar->nb_coded_side_data,
3081 AV_PKT_DATA_DOVI_CONF);
3082
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
85 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3083 2 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
3084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 } else if (dovi) {
3085 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
3086 }
3087
3088 85 const AVPacketSideData *hvce = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3089 85 track->st->codecpar->nb_coded_side_data,
3090 AV_PKT_DATA_HEVC_CONF);
3091
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
85 if (hvce && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3092 2 mov_write_hvce_tag(pb, hvce);
3093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 } else if (hvce) {
3094 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'hvcE' box. Requires -strict unofficial.\n");
3095 }
3096 }
3097
3098
3/4
✓ Branch 0 taken 235 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 208 times.
235 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
3099 27 mov_write_pasp_tag(pb, track);
3100 }
3101
3102 235 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3103 235 track->st->codecpar->nb_coded_side_data,
3104 AV_PKT_DATA_FRAME_CROPPING);
3105
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 234 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
236 if (sd && sd->size >= sizeof(uint32_t) * 4) {
3106 1 uint64_t top = AV_RL32(sd->data + 0);
3107 1 uint64_t bottom = AV_RL32(sd->data + 4);
3108 1 uint64_t left = AV_RL32(sd->data + 8);
3109 1 uint64_t right = AV_RL32(sd->data + 12);
3110
3111
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
3112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
3113 ✗ av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
3114 ✗ return AVERROR(EINVAL);
3115 }
3116
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)
3117 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
3118
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 230 times.
234 } else if (uncompressed_ycbcr)
3119 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
3120
3121
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 229 times.
235 if (mov->encryption_scheme != MOV_ENC_NONE) {
3122 6 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
3123 }
3124
3125
3/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 85 times.
320 if (mov->write_btrt &&
3126 85 ((ret = mov_write_btrt_tag(pb, track)) < 0))
3127 ✗ return ret;
3128
3129 /* extra padding for avid stsd */
3130 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3131
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 212 times.
235 if (avid)
3132 23 avio_wb32(pb, 0);
3133
3134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 if (track->mode == MODE_AVIF) {
3135 ✗ mov_write_ccst_tag(pb);
3136 ✗ if (mov->nb_streams > 0 && track == &mov->tracks[1])
3137 ✗ mov_write_aux_tag(pb, "auxi");
3138 }
3139
3140 235 return update_size(pb, pos);
3141 }
3142
3143 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
3144 {
3145 2 int64_t pos = avio_tell(pb);
3146 2 avio_wb32(pb, 0); /* size */
3147 2 ffio_wfourcc(pb, "rtp ");
3148 2 avio_wb32(pb, 0); /* Reserved */
3149 2 avio_wb16(pb, 0); /* Reserved */
3150 2 avio_wb16(pb, 1); /* Data-reference index */
3151
3152 2 avio_wb16(pb, 1); /* Hint track version */
3153 2 avio_wb16(pb, 1); /* Highest compatible version */
3154 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3155
3156 2 avio_wb32(pb, 12); /* size */
3157 2 ffio_wfourcc(pb, "tims");
3158 2 avio_wb32(pb, track->timescale);
3159
3160 2 return update_size(pb, pos);
3161 }
3162
3163 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3164 {
3165 2 uint64_t str_size =strlen(reel_name);
3166 2 int64_t pos = avio_tell(pb);
3167
3168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3169 ✗ av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3170 ✗ avio_wb16(pb, 0);
3171 ✗ return AVERROR(EINVAL);
3172 }
3173
3174 2 avio_wb32(pb, 0); /* size */
3175 2 ffio_wfourcc(pb, "name"); /* Data format */
3176 2 avio_wb16(pb, str_size); /* string size */
3177 2 avio_wb16(pb, track->language); /* langcode */
3178 2 avio_write(pb, reel_name, str_size); /* reel name */
3179 2 return update_size(pb,pos);
3180 }
3181
3182 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3183 {
3184 13 int64_t pos = avio_tell(pb);
3185 #if 1
3186 int frame_duration;
3187 int nb_frames;
3188 13 AVDictionaryEntry *t = NULL;
3189
3190
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) {
3191 ✗ av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3192 ✗ return AVERROR(EINVAL);
3193 } else {
3194 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3195
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);
3196 }
3197
3198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3199 ✗ av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3200 ✗ return AVERROR(EINVAL);
3201 }
3202
3203 13 avio_wb32(pb, 0); /* size */
3204 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3205 13 avio_wb32(pb, 0); /* Reserved */
3206 13 avio_wb32(pb, 1); /* Data reference index */
3207 13 avio_wb32(pb, 0); /* Flags */
3208 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3209 13 avio_wb32(pb, track->timescale); /* Timescale */
3210 13 avio_wb32(pb, frame_duration); /* Frame duration */
3211 13 avio_w8(pb, nb_frames); /* Number of frames */
3212 13 avio_w8(pb, 0); /* Reserved */
3213
3214 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3215
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)
3216 2 mov_write_source_reference_tag(pb, track, t->value);
3217 else
3218 11 avio_wb16(pb, 0); /* zero size */
3219 #else
3220
3221 avio_wb32(pb, 0); /* size */
3222 ffio_wfourcc(pb, "tmcd"); /* Data format */
3223 avio_wb32(pb, 0); /* Reserved */
3224 avio_wb32(pb, 1); /* Data reference index */
3225 if (track->par->extradata_size)
3226 avio_write(pb, track->par->extradata, track->par->extradata_size);
3227 #endif
3228 13 return update_size(pb, pos);
3229 }
3230
3231 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3232 {
3233 1 int64_t pos = avio_tell(pb);
3234 1 avio_wb32(pb, 0); /* size */
3235 1 ffio_wfourcc(pb, "gpmd");
3236 1 avio_wb32(pb, 0); /* Reserved */
3237 1 avio_wb16(pb, 0); /* Reserved */
3238 1 avio_wb16(pb, 1); /* Data-reference index */
3239 1 avio_wb32(pb, 0); /* Reserved */
3240 1 return update_size(pb, pos);
3241 }
3242
3243 586 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3244 {
3245 586 int64_t pos = avio_tell(pb);
3246 586 int ret = 0;
3247 586 avio_wb32(pb, 0); /* size */
3248 586 ffio_wfourcc(pb, "stsd");
3249 586 avio_wb32(pb, 0); /* version & flags */
3250 586 avio_wb32(pb, track->stsd_count);
3251
3252 586 int stsd_index_back = track->last_stsd_index;
3253 586 for (track->last_stsd_index = 0;
3254
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 586 times.
1174 track->last_stsd_index < track->stsd_count;
3255 588 track->last_stsd_index++) {
3256
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 353 times.
588 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3257 235 ret = mov_write_video_tag(s, pb, mov, track);
3258
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 22 times.
353 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3259 331 ret = mov_write_audio_tag(s, pb, mov, track);
3260
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3261 6 ret = mov_write_subtitle_tag(s, pb, track);
3262
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3263 2 ret = mov_write_rtp_tag(pb, track);
3264
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3265 13 ret = mov_write_tmcd_tag(pb, track);
3266
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3267 1 ret = mov_write_gpmd_tag(pb, track);
3268
3269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (ret < 0)
3270 ✗ return ret;
3271 }
3272
3273 586 track->last_stsd_index = stsd_index_back;
3274
3275 586 return update_size_and_version(pb, pos, track->entry_version);
3276 }
3277
3278 15 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3279 {
3280 15 MOVMuxContext *mov = s->priv_data;
3281 MOVCtts *ctts_entries;
3282 15 uint32_t entries = 0;
3283 uint32_t atom_size;
3284 int i;
3285
3286 15 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!ctts_entries)
3288 ✗ return AVERROR(ENOMEM);
3289 15 ctts_entries[0].count = 1;
3290 15 ctts_entries[0].offset = track->cluster[0].cts;
3291
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 15 times.
775 for (i = 1; i < track->entry; i++) {
3292
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 629 times.
760 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3293 131 ctts_entries[entries].count++; /* compress */
3294 } else {
3295 629 entries++;
3296 629 ctts_entries[entries].offset = track->cluster[i].cts;
3297 629 ctts_entries[entries].count = 1;
3298 }
3299 }
3300 15 entries++; /* last one */
3301 15 atom_size = 16 + (entries * 8);
3302 15 avio_wb32(pb, atom_size); /* size */
3303 15 ffio_wfourcc(pb, "ctts");
3304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3305 ✗ avio_w8(pb, 1); /* version */
3306 else
3307 15 avio_w8(pb, 0); /* version */
3308 15 avio_wb24(pb, 0); /* flags */
3309 15 avio_wb32(pb, entries); /* entry count */
3310
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 15 times.
659 for (i = 0; i < entries; i++) {
3311 644 avio_wb32(pb, ctts_entries[i].count);
3312 644 avio_wb32(pb, ctts_entries[i].offset);
3313 }
3314 15 av_free(ctts_entries);
3315 15 return atom_size;
3316 }
3317
3318 /* Time to sample atom */
3319 586 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3320 {
3321 586 MOVStts *stts_entries = NULL;
3322 586 uint32_t entries = -1;
3323 uint32_t atom_size;
3324 int i;
3325
3326
4/4
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 255 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 296 times.
586 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3327 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3329 ✗ return AVERROR(ENOMEM);
3330 35 stts_entries[0].count = track->sample_count;
3331 35 stts_entries[0].duration = 1;
3332 35 entries = 1;
3333 } else {
3334
2/2
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 307 times.
551 if (track->entry) {
3335 244 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (!stts_entries)
3337 ✗ return AVERROR(ENOMEM);
3338 }
3339
2/2
✓ Branch 0 taken 16655 times.
✓ Branch 1 taken 551 times.
17206 for (i = 0; i < track->entry; i++) {
3340 16655 int duration = get_cluster_duration(track, i);
3341 #if CONFIG_IAMFENC
3342
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 16600 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
16655 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3343 ✗ duration = av_rescale(duration, 48000, track->par->sample_rate);
3344 #endif
3345
4/4
✓ Branch 0 taken 16411 times.
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 15981 times.
✓ Branch 3 taken 430 times.
16655 if (i && duration == stts_entries[entries].duration) {
3346 15981 stts_entries[entries].count++; /* compress */
3347 } else {
3348 674 entries++;
3349 674 stts_entries[entries].duration = duration;
3350 674 stts_entries[entries].count = 1;
3351 }
3352 }
3353 551 entries++; /* last one */
3354 }
3355 586 atom_size = 16 + (entries * 8);
3356 586 avio_wb32(pb, atom_size); /* size */
3357 586 ffio_wfourcc(pb, "stts");
3358 586 avio_wb32(pb, 0); /* version & flags */
3359 586 avio_wb32(pb, entries); /* entry count */
3360
2/2
✓ Branch 0 taken 709 times.
✓ Branch 1 taken 586 times.
1295 for (i = 0; i < entries; i++) {
3361 709 avio_wb32(pb, stts_entries[i].count);
3362 709 avio_wb32(pb, stts_entries[i].duration);
3363 }
3364 586 av_free(stts_entries);
3365 586 return atom_size;
3366 }
3367
3368 586 static int mov_write_dref_tag(AVIOContext *pb)
3369 {
3370 586 avio_wb32(pb, 28); /* size */
3371 586 ffio_wfourcc(pb, "dref");
3372 586 avio_wb32(pb, 0); /* version & flags */
3373 586 avio_wb32(pb, 1); /* entry count */
3374
3375 586 avio_wb32(pb, 0xc); /* size */
3376 //FIXME add the alis and rsrc atom
3377 586 ffio_wfourcc(pb, "url ");
3378 586 avio_wb32(pb, 1); /* version & flags */
3379
3380 586 return 28;
3381 }
3382
3383 67 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3384 {
3385 struct sgpd_entry {
3386 int count;
3387 int16_t roll_distance;
3388 int group_description_index;
3389 };
3390
3391 67 struct sgpd_entry *sgpd_entries = NULL;
3392 67 int entries = -1;
3393 67 int group = 0;
3394 int i, j;
3395
3396 67 const int OPUS_SEEK_PREROLL_MS = 80;
3397 67 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3398 67 (AVRational){1, 1000},
3399 67 (AVRational){1, 48000});
3400
3401
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 22 times.
67 if (!track->entry)
3402 45 return 0;
3403
3404 22 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!sgpd_entries)
3406 ✗ return AVERROR(ENOMEM);
3407
3408
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3409
3410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3411 ✗ for (i = 0; i < track->entry; i++) {
3412 ✗ int roll_samples_remaining = roll_samples;
3413 ✗ int distance = 0;
3414 ✗ for (j = i - 1; j >= 0; j--) {
3415 ✗ roll_samples_remaining -= get_cluster_duration(track, j);
3416 ✗ distance++;
3417 ✗ if (roll_samples_remaining <= 0)
3418 ✗ break;
3419 }
3420 /* We don't have enough preceding samples to compute a valid
3421 roll_distance here, so this sample can't be independently
3422 decoded. */
3423 ✗ if (roll_samples_remaining > 0)
3424 ✗ distance = 0;
3425 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3426 ✗ if (distance > 32) {
3427 ✗ av_freep(&sgpd_entries);
3428 ✗ return AVERROR_INVALIDDATA;
3429 }
3430 ✗ if (i && distance == sgpd_entries[entries].roll_distance) {
3431 ✗ sgpd_entries[entries].count++;
3432 } else {
3433 ✗ entries++;
3434 ✗ sgpd_entries[entries].count = 1;
3435 ✗ sgpd_entries[entries].roll_distance = distance;
3436 ✗ sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3437 }
3438 }
3439 } else {
3440 22 entries++;
3441 22 sgpd_entries[entries].count = track->sample_count;
3442 22 sgpd_entries[entries].roll_distance = 1;
3443 22 sgpd_entries[entries].group_description_index = ++group;
3444 }
3445 22 entries++;
3446
3447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!group) {
3448 ✗ av_free(sgpd_entries);
3449 ✗ return 0;
3450 }
3451
3452 /* Write sgpd tag */
3453 22 avio_wb32(pb, 24 + (group * 2)); /* size */
3454 22 ffio_wfourcc(pb, "sgpd");
3455 22 avio_wb32(pb, 1 << 24); /* fullbox */
3456 22 ffio_wfourcc(pb, "roll");
3457 22 avio_wb32(pb, 2); /* default_length */
3458 22 avio_wb32(pb, group); /* entry_count */
3459
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 for (i = 0; i < entries; i++) {
3460
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (sgpd_entries[i].group_description_index) {
3461 22 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3462 }
3463 }
3464
3465 /* Write sbgp tag */
3466 22 avio_wb32(pb, 20 + (entries * 8)); /* size */
3467 22 ffio_wfourcc(pb, "sbgp");
3468 22 avio_wb32(pb, 0); /* fullbox */
3469 22 ffio_wfourcc(pb, "roll");
3470 22 avio_wb32(pb, entries); /* entry_count */
3471
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 for (i = 0; i < entries; i++) {
3472 22 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3473 22 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3474 }
3475
3476 22 av_free(sgpd_entries);
3477 22 return 0;
3478 }
3479
3480 586 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3481 {
3482 586 int64_t pos = avio_tell(pb);
3483 586 int ret = 0;
3484
3485 586 avio_wb32(pb, 0); /* size */
3486 586 ffio_wfourcc(pb, "stbl");
3487
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 586 times.
586 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3488 ✗ return ret;
3489 586 mov_write_stts_tag(pb, track);
3490
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 233 times.
586 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3491
1/2
✓ Branch 0 taken 353 times.
✗ Branch 1 not taken.
353 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3492
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 1 times.
353 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3493
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 285 times.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
352 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3494
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 350 times.
352 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3495
4/4
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 111 times.
236 track->has_keyframes && track->has_keyframes < track->entry)
3496 69 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3497
5/6
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 353 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 230 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
586 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3498 3 mov_write_sdtp_tag(pb, track);
3499
3/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 394 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
586 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3500 ✗ mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3501
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 353 times.
586 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3502
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24 times.
233 track->flags & MOV_TRACK_CTTS && track->entry) {
3503
3504
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3505 ✗ return ret;
3506 }
3507 586 mov_write_stsc_tag(pb, track);
3508 586 mov_write_stsz_tag(pb, track);
3509 586 mov_write_stco_tag(pb, track);
3510
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 581 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
586 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3511 5 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3512 }
3513
3/4
✓ Branch 0 taken 586 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 519 times.
586 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3514 67 mov_preroll_write_stbl_atoms(pb, track);
3515 }
3516 586 return update_size(pb, pos);
3517 }
3518
3519 586 static int mov_write_dinf_tag(AVIOContext *pb)
3520 {
3521 586 int64_t pos = avio_tell(pb);
3522 586 avio_wb32(pb, 0); /* size */
3523 586 ffio_wfourcc(pb, "dinf");
3524 586 mov_write_dref_tag(pb);
3525 586 return update_size(pb, pos);
3526 }
3527
3528 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3529 {
3530 7 avio_wb32(pb, 12);
3531 7 ffio_wfourcc(pb, "nmhd");
3532 7 avio_wb32(pb, 0);
3533 7 return 12;
3534 }
3535
3536 2 static int mov_write_sthd_tag(AVIOContext *pb)
3537 {
3538 2 avio_wb32(pb, 12);
3539 2 ffio_wfourcc(pb, "sthd");
3540 2 avio_wb32(pb, 0);
3541 2 return 12;
3542 }
3543
3544 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3545 {
3546 9 int64_t pos = avio_tell(pb);
3547 9 const char *font = "Lucida Grande";
3548 9 avio_wb32(pb, 0); /* size */
3549 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3550 9 avio_wb32(pb, 0); /* version & flags */
3551 9 avio_wb16(pb, 0); /* text font */
3552 9 avio_wb16(pb, 0); /* text face */
3553 9 avio_wb16(pb, 12); /* text size */
3554 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3555 9 avio_wb16(pb, 0x0000); /* text color (red) */
3556 9 avio_wb16(pb, 0x0000); /* text color (green) */
3557 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3558 9 avio_wb16(pb, 0xffff); /* background color (red) */
3559 9 avio_wb16(pb, 0xffff); /* background color (green) */
3560 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3561 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3562 9 avio_write(pb, font, strlen(font)); /* font name */
3563 9 return update_size(pb, pos);
3564 }
3565
3566 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3567 {
3568 11 int64_t pos = avio_tell(pb);
3569 11 avio_wb32(pb, 0); /* size */
3570 11 ffio_wfourcc(pb, "gmhd");
3571 11 avio_wb32(pb, 0x18); /* gmin size */
3572 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3573 11 avio_wb32(pb, 0); /* version & flags */
3574 11 avio_wb16(pb, 0x40); /* graphics mode = */
3575 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3576 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3577 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3578 11 avio_wb16(pb, 0); /* balance */
3579 11 avio_wb16(pb, 0); /* reserved */
3580
3581 /*
3582 * This special text atom is required for
3583 * Apple Quicktime chapters. The contents
3584 * don't appear to be documented, so the
3585 * bytes are copied verbatim.
3586 */
3587
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3588 11 avio_wb32(pb, 0x2C); /* size */
3589 11 ffio_wfourcc(pb, "text");
3590 11 avio_wb16(pb, 0x01);
3591 11 avio_wb32(pb, 0x00);
3592 11 avio_wb32(pb, 0x00);
3593 11 avio_wb32(pb, 0x00);
3594 11 avio_wb32(pb, 0x01);
3595 11 avio_wb32(pb, 0x00);
3596 11 avio_wb32(pb, 0x00);
3597 11 avio_wb32(pb, 0x00);
3598 11 avio_wb32(pb, 0x00004000);
3599 11 avio_wb16(pb, 0x0000);
3600 }
3601
3602
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3603 9 int64_t tmcd_pos = avio_tell(pb);
3604 9 avio_wb32(pb, 0); /* size */
3605 9 ffio_wfourcc(pb, "tmcd");
3606 9 mov_write_tcmi_tag(pb, track);
3607 9 update_size(pb, tmcd_pos);
3608
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3609 1 int64_t gpmd_pos = avio_tell(pb);
3610 1 avio_wb32(pb, 0); /* size */
3611 1 ffio_wfourcc(pb, "gpmd");
3612 1 avio_wb32(pb, 0); /* version */
3613 1 update_size(pb, gpmd_pos);
3614 }
3615 11 return update_size(pb, pos);
3616 }
3617
3618 331 static int mov_write_smhd_tag(AVIOContext *pb)
3619 {
3620 331 avio_wb32(pb, 16); /* size */
3621 331 ffio_wfourcc(pb, "smhd");
3622 331 avio_wb32(pb, 0); /* version & flags */
3623 331 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3624 331 avio_wb16(pb, 0); /* reserved */
3625 331 return 16;
3626 }
3627
3628 233 static uint16_t mov_graphics_mode(MOVTrack *track)
3629 {
3630
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 144 times.
233 if (track->mode != MODE_MOV)
3631 89 return 0; /* ISO/IEC 14496-12 doesn't define any other modes */
3632
3633
1/3
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
144 switch (track->par->alpha_mode) {
3634 144 default: return MOV_GRAPHICS_MODE_COPY;
3635 ✗ case AVALPHA_MODE_STRAIGHT: return MOV_GRAPHICS_MODE_STRAIGHT_ALPHA;
3636 ✗ case AVALPHA_MODE_PREMULTIPLIED: return MOV_GRAPHICS_MODE_PREMUL_BLACK_ALPHA;
3637 }
3638 }
3639
3640 233 static int mov_write_vmhd_tag(AVIOContext *pb, MOVTrack *track)
3641 {
3642 233 avio_wb32(pb, 0x14); /* size (always 0x14) */
3643 233 ffio_wfourcc(pb, "vmhd");
3644 233 avio_wb32(pb, 0x01); /* version & flags */
3645 233 avio_wb16(pb, mov_graphics_mode(track));
3646
2/2
✓ Branch 0 taken 699 times.
✓ Branch 1 taken 233 times.
932 for (int i = 0; i < 3; i++)
3647 699 avio_wb16(pb, 0); /* opcolor */
3648 233 return 0x14;
3649 }
3650
3651 229 static int is_clcp_track(MOVTrack *track)
3652 {
3653
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
458 return track->tag == MKTAG('c','7','0','8') ||
3654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 track->tag == MKTAG('c','6','0','8');
3655 }
3656
3657 778 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3658 {
3659 778 MOVMuxContext *mov = s->priv_data;
3660 778 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3661 778 int64_t pos = avio_tell(pb);
3662 size_t descr_len;
3663
3664 778 hdlr = "dhlr";
3665 778 hdlr_type = "url ";
3666 778 descr = "DataHandler";
3667
3668
2/2
✓ Branch 0 taken 586 times.
✓ Branch 1 taken 192 times.
778 if (track) {
3669
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 394 times.
586 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3670
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 353 times.
586 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 233 times.
233 if (track->mode == MODE_AVIF) {
3672 ✗ hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3673 ✗ descr = "PictureHandler";
3674 } else {
3675 233 hdlr_type = "vide";
3676 233 descr = "VideoHandler";
3677 }
3678
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 22 times.
353 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3679 331 hdlr_type = "soun";
3680 331 descr = "SoundHandler";
3681
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3682
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3683 ✗ hdlr_type = "clcp";
3684 ✗ descr = "ClosedCaptionHandler";
3685 } else {
3686
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3687 1 hdlr_type = "sbtl";
3688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3689 ✗ hdlr_type = "subp";
3690
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3691 2 hdlr_type = "subt";
3692 } else {
3693 3 hdlr_type = "text";
3694 }
3695 6 descr = "SubtitleHandler";
3696 }
3697
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3698 2 hdlr_type = "hint";
3699 2 descr = "HintHandler";
3700
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3701 13 hdlr_type = "tmcd";
3702 13 descr = "TimeCodeHandler";
3703
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3704 1 hdlr_type = "meta";
3705 1 descr = "GoPro MET"; // GoPro Metadata
3706 } else {
3707 ✗ av_log(s, AV_LOG_WARNING,
3708 "Unknown hdlr_type for %s, writing dummy values\n",
3709 ✗ av_fourcc2str(track->par->codec_tag));
3710 }
3711
2/2
✓ Branch 0 taken 583 times.
✓ Branch 1 taken 3 times.
586 if (track->st) {
3712 // hdlr.name is used by some players to identify the content title
3713 // of the track. So if an alternate handler description is
3714 // specified, use it.
3715 AVDictionaryEntry *t;
3716 583 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3717
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 555 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
583 if (t && utf8len(t->value))
3718 28 descr = t->value;
3719 }
3720 }
3721
3722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 778 times.
778 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3723 ✗ descr = "";
3724
3725 778 avio_wb32(pb, 0); /* size */
3726 778 ffio_wfourcc(pb, "hdlr");
3727 778 avio_wb32(pb, 0); /* Version & flags */
3728 778 avio_write(pb, hdlr, 4); /* handler */
3729 778 ffio_wfourcc(pb, hdlr_type); /* handler type */
3730 778 avio_wb32(pb, 0); /* reserved */
3731 778 avio_wb32(pb, 0); /* reserved */
3732 778 avio_wb32(pb, 0); /* reserved */
3733 778 descr_len = strlen(descr);
3734
4/4
✓ Branch 0 taken 586 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 394 times.
778 if (!track || track->mode == MODE_MOV)
3735 384 avio_w8(pb, descr_len); /* pascal string */
3736 778 avio_write(pb, descr, descr_len); /* handler description */
3737
4/4
✓ Branch 0 taken 586 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 394 times.
✓ Branch 3 taken 192 times.
778 if (track && track->mode != MODE_MOV)
3738 394 avio_w8(pb, 0); /* c string */
3739 778 return update_size(pb, pos);
3740 }
3741
3742 ✗ static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3743 {
3744 ✗ int64_t pos = avio_tell(pb);
3745 ✗ avio_wb32(pb, 0); /* size */
3746 ✗ ffio_wfourcc(pb, "pitm");
3747 ✗ avio_wb32(pb, 0); /* Version & flags */
3748 ✗ avio_wb16(pb, item_id); /* item_id */
3749 ✗ return update_size(pb, pos);
3750 }
3751
3752 ✗ static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3753 {
3754 ✗ int64_t pos = avio_tell(pb);
3755 ✗ avio_wb32(pb, 0); /* size */
3756 ✗ ffio_wfourcc(pb, "iloc");
3757 ✗ avio_wb32(pb, 0); /* Version & flags */
3758 ✗ avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3759 ✗ avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3760 ✗ avio_wb16(pb, mov->nb_streams); /* item_count */
3761
3762 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3763 ✗ avio_wb16(pb, i + 1); /* item_id */
3764 ✗ avio_wb16(pb, 0); /* data_reference_index */
3765 ✗ avio_wb16(pb, 1); /* extent_count */
3766 ✗ mov->avif_extent_pos[i] = avio_tell(pb);
3767 ✗ avio_wb32(pb, 0); /* extent_offset (written later) */
3768 // For animated AVIF, we simply write the first packet's size.
3769 ✗ avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3770 }
3771
3772 ✗ return update_size(pb, pos);
3773 }
3774
3775 ✗ static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3776 {
3777 ✗ int64_t iinf_pos = avio_tell(pb);
3778 ✗ avio_wb32(pb, 0); /* size */
3779 ✗ ffio_wfourcc(pb, "iinf");
3780 ✗ avio_wb32(pb, 0); /* Version & flags */
3781 ✗ avio_wb16(pb, mov->nb_streams); /* entry_count */
3782
3783 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3784 ✗ int64_t infe_pos = avio_tell(pb);
3785 ✗ avio_wb32(pb, 0); /* size */
3786 ✗ ffio_wfourcc(pb, "infe");
3787 ✗ avio_w8(pb, 0x2); /* Version */
3788 ✗ avio_wb24(pb, 0); /* flags */
3789 ✗ avio_wb16(pb, i + 1); /* item_id */
3790 ✗ avio_wb16(pb, 0); /* item_protection_index */
3791 ✗ avio_write(pb, "av01", 4); /* item_type */
3792 ✗ avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3793 ✗ update_size(pb, infe_pos);
3794 }
3795
3796 ✗ return update_size(pb, iinf_pos);
3797 }
3798
3799
3800 ✗ static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3801 {
3802 int64_t auxl_pos;
3803 ✗ int64_t iref_pos = avio_tell(pb);
3804 ✗ avio_wb32(pb, 0); /* size */
3805 ✗ ffio_wfourcc(pb, "iref");
3806 ✗ avio_wb32(pb, 0); /* Version & flags */
3807
3808 ✗ auxl_pos = avio_tell(pb);
3809 ✗ avio_wb32(pb, 0); /* size */
3810 ✗ ffio_wfourcc(pb, "auxl");
3811 ✗ avio_wb16(pb, 2); /* from_item_ID */
3812 ✗ avio_wb16(pb, 1); /* reference_count */
3813 ✗ avio_wb16(pb, 1); /* to_item_ID */
3814 ✗ update_size(pb, auxl_pos);
3815
3816 ✗ return update_size(pb, iref_pos);
3817 }
3818
3819 ✗ static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3820 int stream_index)
3821 {
3822 ✗ int64_t pos = avio_tell(pb);
3823 ✗ avio_wb32(pb, 0); /* size */
3824 ✗ ffio_wfourcc(pb, "ispe");
3825 ✗ avio_wb32(pb, 0); /* Version & flags */
3826 ✗ avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3827 ✗ avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3828 ✗ return update_size(pb, pos);
3829 }
3830
3831 ✗ static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3832 int stream_index)
3833 {
3834 ✗ int64_t pos = avio_tell(pb);
3835 const AVPixFmtDescriptor *pixdesc =
3836 ✗ av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3837 ✗ avio_wb32(pb, 0); /* size */
3838 ✗ ffio_wfourcc(pb, "pixi");
3839 ✗ avio_wb32(pb, 0); /* Version & flags */
3840 ✗ avio_w8(pb, pixdesc->nb_components); /* num_channels */
3841 ✗ for (int i = 0; i < pixdesc->nb_components; ++i) {
3842 ✗ avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3843 }
3844 ✗ return update_size(pb, pos);
3845 }
3846
3847 ✗ static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3848 {
3849 ✗ int64_t pos = avio_tell(pb);
3850 ✗ avio_wb32(pb, 0); /* size */
3851 ✗ ffio_wfourcc(pb, "ipco");
3852 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3853 ✗ mov_write_ispe_tag(pb, mov, s, i);
3854 ✗ mov_write_pixi_tag(pb, mov, s, i);
3855 ✗ mov_write_av1c_tag(pb, &mov->tracks[i]);
3856 ✗ if (!i)
3857 ✗ mov_write_colr_tag(pb, &mov->tracks[0], 0);
3858 else
3859 ✗ mov_write_aux_tag(pb, "auxC");
3860 }
3861 ✗ return update_size(pb, pos);
3862 }
3863
3864 ✗ static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3865 {
3866 ✗ int64_t pos = avio_tell(pb);
3867 ✗ avio_wb32(pb, 0); /* size */
3868 ✗ ffio_wfourcc(pb, "ipma");
3869 ✗ avio_wb32(pb, 0); /* Version & flags */
3870 ✗ avio_wb32(pb, mov->nb_streams); /* entry_count */
3871
3872 ✗ for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3873 ✗ avio_wb16(pb, i + 1); /* item_ID */
3874 ✗ avio_w8(pb, 4); /* association_count */
3875
3876 // ispe association.
3877 ✗ avio_w8(pb, index++); /* essential and property_index */
3878 // pixi association.
3879 ✗ avio_w8(pb, index++); /* essential and property_index */
3880 // av1C association.
3881 ✗ avio_w8(pb, 0x80 | index++); /* essential and property_index */
3882 // colr/auxC association.
3883 ✗ avio_w8(pb, index++); /* essential and property_index */
3884 }
3885 ✗ return update_size(pb, pos);
3886 }
3887
3888 ✗ static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3889 {
3890 ✗ int64_t pos = avio_tell(pb);
3891 ✗ avio_wb32(pb, 0); /* size */
3892 ✗ ffio_wfourcc(pb, "iprp");
3893 ✗ mov_write_ipco_tag(pb, mov, s);
3894 ✗ mov_write_ipma_tag(pb, mov, s);
3895 ✗ return update_size(pb, pos);
3896 }
3897
3898 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3899 {
3900 /* This atom must be present, but leaving the values at zero
3901 * seems harmless. */
3902 2 avio_wb32(pb, 28); /* size */
3903 2 ffio_wfourcc(pb, "hmhd");
3904 2 avio_wb32(pb, 0); /* version, flags */
3905 2 avio_wb16(pb, 0); /* maxPDUsize */
3906 2 avio_wb16(pb, 0); /* avgPDUsize */
3907 2 avio_wb32(pb, 0); /* maxbitrate */
3908 2 avio_wb32(pb, 0); /* avgbitrate */
3909 2 avio_wb32(pb, 0); /* reserved */
3910 2 return 28;
3911 }
3912
3913 586 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3914 {
3915 586 int64_t pos = avio_tell(pb);
3916 int ret;
3917
3918 586 avio_wb32(pb, 0); /* size */
3919 586 ffio_wfourcc(pb, "minf");
3920
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 353 times.
586 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3921 233 mov_write_vmhd_tag(pb, track);
3922
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 22 times.
353 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3923 331 mov_write_smhd_tag(pb);
3924
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3925
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)) {
3926 1 mov_write_gmhd_tag(pb, track);
3927
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3928 2 mov_write_sthd_tag(pb);
3929 } else {
3930 3 mov_write_nmhd_tag(pb);
3931 }
3932
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3933 2 mov_write_hmhd_tag(pb);
3934
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3935
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3936 4 mov_write_nmhd_tag(pb);
3937 else
3938 9 mov_write_gmhd_tag(pb, track);
3939
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3940 1 mov_write_gmhd_tag(pb, track);
3941 }
3942
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 394 times.
586 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3943 192 mov_write_hdlr_tag(s, pb, NULL);
3944 586 mov_write_dinf_tag(pb);
3945
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 586 times.
586 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3946 ✗ return ret;
3947 586 return update_size(pb, pos);
3948 }
3949
3950 2280 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3951 int64_t *start, int64_t *end, int elst, int mdhd)
3952 {
3953
5/6
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2230 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
2280 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd && track->nb_src_track) {
3954 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3955 // another track's duration, while the end_pts may be left at zero.
3956 // Calculate the pts duration for that track instead.
3957 38 get_pts_range(mov, &mov->tracks[*track->src_track], start, end, elst, mdhd);
3958 38 *start = av_rescale(*start, track->timescale,
3959 38 mov->tracks[*track->src_track].timescale);
3960 38 *end = av_rescale(*end, track->timescale,
3961 38 mov->tracks[*track->src_track].timescale);
3962 38 return;
3963 }
3964
4/4
✓ Branch 0 taken 1656 times.
✓ Branch 1 taken 586 times.
✓ Branch 2 taken 1614 times.
✓ Branch 3 taken 42 times.
2242 if (!mdhd && track->end_pts != AV_NOPTS_VALUE &&
3965
1/2
✓ Branch 0 taken 1614 times.
✗ Branch 1 not taken.
1614 track->start_dts != AV_NOPTS_VALUE &&
3966
1/2
✓ Branch 0 taken 1614 times.
✗ Branch 1 not taken.
1614 track->start_cts != AV_NOPTS_VALUE) {
3967 1614 *start = track->start_dts + track->start_cts;
3968
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 1092 times.
1614 *end = elst ? track->elst_end_pts : track->end_pts;
3969 1614 return;
3970 }
3971 628 *start = 0;
3972 628 *end = track->track_duration;
3973 }
3974
3975 586 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3976 {
3977 int64_t start, end;
3978 586 get_pts_range(mov, track, &start, &end, 0, 1);
3979 586 return end - start;
3980 }
3981
3982 // Calculate the actual duration of the track, after edits.
3983 // If it starts with a pts < 0, that is removed by the edit list.
3984 // If it starts with a pts > 0, the edit list adds a delay before that.
3985 // Thus, with edit lists enabled, the post-edit output of the file is
3986 // starting with pts=0.
3987 1134 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3988 {
3989 int64_t start, end;
3990 1134 get_pts_range(mov, track, &start, &end, 0, 0);
3991
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 84 times.
1134 if (mov->use_editlist != 0)
3992 1050 start = 0;
3993 1134 return end - start;
3994 }
3995
3996 522 static int64_t calc_elst_duration(MOVMuxContext *mov, MOVTrack *track)
3997 {
3998 int64_t start, end;
3999 522 get_pts_range(mov, track, &start, &end, 1, 0);
4000 522 return end - start;
4001 }
4002
4003 1458 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
4004 {
4005
4/4
✓ Branch 0 taken 1172 times.
✓ Branch 1 taken 286 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 1154 times.
1458 if (track && track->mode == MODE_ISM)
4006 18 return 1;
4007
2/2
✓ Branch 0 taken 1432 times.
✓ Branch 1 taken 8 times.
1440 if (duration < INT32_MAX)
4008 1432 return 0;
4009 8 return 1;
4010 }
4011
4012 586 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4013 MOVTrack *track)
4014 {
4015 586 int64_t duration = calc_samples_pts_duration(mov, track);
4016 586 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4017
4018
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 573 times.
586 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
4019 586 ffio_wfourcc(pb, "mdhd");
4020 586 avio_w8(pb, version);
4021 586 avio_wb24(pb, 0); /* flags */
4022
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 573 times.
586 if (version == 1) {
4023 13 avio_wb64(pb, track->time);
4024 13 avio_wb64(pb, track->time);
4025 } else {
4026 573 avio_wb32(pb, track->time); /* creation time */
4027 573 avio_wb32(pb, track->time); /* modification time */
4028 }
4029 586 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
4030
4/4
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 299 times.
586 if (!track->entry && mov->mode == MODE_ISM)
4031
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4032
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 278 times.
577 else if (!track->entry)
4033
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 295 times.
299 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4034 else
4035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
278 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
4036 586 avio_wb16(pb, track->language); /* language */
4037 586 avio_wb16(pb, 0); /* reserved (quality) */
4038
4039
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 573 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
586 if (version != 0 && track->mode == MODE_MOV) {
4040 ✗ av_log(NULL, AV_LOG_ERROR,
4041 "FATAL error, file duration too long for timebase, this file will not be\n"
4042 "playable with QuickTime. Choose a different timebase with "
4043 "-video_track_timescale or a different container format\n");
4044 }
4045
4046 586 return 32;
4047 }
4048
4049 586 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
4050 MOVMuxContext *mov, MOVTrack *track)
4051 {
4052 586 int64_t pos = avio_tell(pb);
4053 int ret;
4054
4055 586 avio_wb32(pb, 0); /* size */
4056 586 ffio_wfourcc(pb, "mdia");
4057 586 mov_write_mdhd_tag(pb, mov, track);
4058 586 mov_write_hdlr_tag(s, pb, track);
4059
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 586 times.
586 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
4060 ✗ return ret;
4061 586 return update_size(pb, pos);
4062 }
4063
4064 /* transformation matrix
4065 |a b u|
4066 |c d v|
4067 |tx ty w| */
4068 871 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
4069 int16_t d, int16_t tx, int16_t ty)
4070 {
4071 871 avio_wb32(pb, a << 16); /* 16.16 format */
4072 871 avio_wb32(pb, b << 16); /* 16.16 format */
4073 871 avio_wb32(pb, 0); /* u in 2.30 format */
4074 871 avio_wb32(pb, c << 16); /* 16.16 format */
4075 871 avio_wb32(pb, d << 16); /* 16.16 format */
4076 871 avio_wb32(pb, 0); /* v in 2.30 format */
4077 871 avio_wb32(pb, tx << 16); /* 16.16 format */
4078 871 avio_wb32(pb, ty << 16); /* 16.16 format */
4079 871 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
4080 871 }
4081
4082 586 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4083 MOVTrack *track, AVStream *st)
4084 {
4085 1172 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
4086 586 mov->movie_timescale, track->timescale,
4087 AV_ROUND_UP);
4088 int version;
4089 586 int flags = MOV_TKHD_FLAG_IN_MOVIE;
4090 586 int group = 0;
4091
4092 586 uint32_t *display_matrix = NULL;
4093 int i;
4094
4095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
586 if (mov->mode == MODE_AVIF)
4096 ✗ if (!mov->avif_loop_count)
4097 ✗ duration = INT64_MAX;
4098 else
4099 ✗ duration *= mov->avif_loop_count;
4100
4101
2/2
✓ Branch 0 taken 573 times.
✓ Branch 1 taken 13 times.
586 if (st) {
4102 const AVPacketSideData *sd;
4103
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 571 times.
573 if (mov->per_stream_grouping)
4104 2 group = st->index;
4105 else
4106 571 group = st->codecpar->codec_type;
4107
4108 573 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4109 573 st->codecpar->nb_coded_side_data,
4110 AV_PKT_DATA_DISPLAYMATRIX);
4111
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 572 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
573 if (sd && sd->size == 9 * sizeof(*display_matrix))
4112 1 display_matrix = (uint32_t *)sd->data;
4113 }
4114
4115
2/2
✓ Branch 0 taken 363 times.
✓ Branch 1 taken 223 times.
586 if (track->flags & MOV_TRACK_ENABLED)
4116 363 flags |= MOV_TKHD_FLAG_ENABLED;
4117
4118 586 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4119
4120
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 573 times.
586 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
4121 586 ffio_wfourcc(pb, "tkhd");
4122 586 avio_w8(pb, version);
4123 586 avio_wb24(pb, flags);
4124
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 573 times.
586 if (version == 1) {
4125 13 avio_wb64(pb, track->time);
4126 13 avio_wb64(pb, track->time);
4127 } else {
4128 573 avio_wb32(pb, track->time); /* creation time */
4129 573 avio_wb32(pb, track->time); /* modification time */
4130 }
4131 586 avio_wb32(pb, track->track_id); /* track-id */
4132 586 avio_wb32(pb, 0); /* reserved */
4133
4/4
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 299 times.
586 if (!track->entry && mov->mode == MODE_ISM)
4134
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4135
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 278 times.
577 else if (!track->entry)
4136
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 295 times.
299 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4137 else
4138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
278 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
4139
4140 586 avio_wb32(pb, 0); /* reserved */
4141 586 avio_wb32(pb, 0); /* reserved */
4142 586 avio_wb16(pb, 0); /* layer */
4143 586 avio_wb16(pb, group); /* alternate group) */
4144 /* Volume, only for audio */
4145
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 255 times.
586 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
4146 331 avio_wb16(pb, 0x0100);
4147 else
4148 255 avio_wb16(pb, 0);
4149 586 avio_wb16(pb, 0); /* reserved */
4150
4151 /* Matrix structure */
4152
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 585 times.
586 if (display_matrix) {
4153
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
4154 9 avio_wb32(pb, display_matrix[i]);
4155 } else {
4156 585 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4157 }
4158 /* Track width and height, for visual only */
4159
4/4
✓ Branch 0 taken 573 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 340 times.
✓ Branch 3 taken 233 times.
586 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
4160
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 335 times.
578 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
4161 int64_t track_width_1616;
4162
3/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 94 times.
238 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
4163 144 track_width_1616 = track->par->width * 0x10000ULL;
4164 } else {
4165 94 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
4166 94 track->par->width * 0x10000LL,
4167 94 st->sample_aspect_ratio.den);
4168
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 74 times.
94 if (!track_width_1616 ||
4169
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 track->height != track->par->height ||
4170 track_width_1616 > UINT32_MAX)
4171 74 track_width_1616 = track->par->width * 0x10000ULL;
4172 }
4173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 238 times.
238 if (track_width_1616 > UINT32_MAX) {
4174 ✗ av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4175 ✗ track_width_1616 = 0;
4176 }
4177 238 avio_wb32(pb, track_width_1616);
4178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 238 times.
238 if (track->height > 0xFFFF) {
4179 ✗ av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4180 ✗ avio_wb32(pb, 0);
4181 } else
4182 238 avio_wb32(pb, track->height * 0x10000U);
4183 } else {
4184 348 avio_wb32(pb, 0);
4185 348 avio_wb32(pb, 0);
4186 }
4187 586 return 0x5c;
4188 }
4189
4190 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4191 {
4192 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4193 1 track->par->sample_aspect_ratio.den);
4194
4195 1 int64_t pos = avio_tell(pb);
4196
4197 1 avio_wb32(pb, 0); /* size */
4198 1 ffio_wfourcc(pb, "tapt");
4199
4200 1 avio_wb32(pb, 20);
4201 1 ffio_wfourcc(pb, "clef");
4202 1 avio_wb32(pb, 0);
4203 1 avio_wb32(pb, width << 16);
4204 1 avio_wb32(pb, track->par->height << 16);
4205
4206 1 avio_wb32(pb, 20);
4207 1 ffio_wfourcc(pb, "prof");
4208 1 avio_wb32(pb, 0);
4209 1 avio_wb32(pb, width << 16);
4210 1 avio_wb32(pb, track->par->height << 16);
4211
4212 1 avio_wb32(pb, 20);
4213 1 ffio_wfourcc(pb, "enof");
4214 1 avio_wb32(pb, 0);
4215 1 avio_wb32(pb, track->par->width << 16);
4216 1 avio_wb32(pb, track->par->height << 16);
4217
4218 1 return update_size(pb, pos);
4219 }
4220
4221 // This box is written in the following cases:
4222 // * Seems important for the psp playback. Without it the movie seems to hang.
4223 // * Used for specifying the looping behavior of animated AVIF (as specified
4224 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4225 522 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4226 MOVTrack *track)
4227 {
4228 1044 int64_t duration = av_rescale_rnd(calc_elst_duration(mov, track),
4229 522 mov->movie_timescale, track->timescale,
4230 AV_ROUND_UP);
4231 522 int version = duration < INT32_MAX ? 0 : 1;
4232 int entry_size, entry_count, size;
4233 522 int64_t delay, start_ct = track->start_cts;
4234 522 int64_t start_dts = track->start_dts;
4235 522 int flags = 0;
4236
4237
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 260 times.
522 if (track->entry) {
4238
4/6
✓ Branch 0 taken 262 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 259 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
262 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4239
4240 ✗ av_log(mov->fc, AV_LOG_DEBUG,
4241 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4242 ✗ track->cluster[0].dts, track->cluster[0].cts,
4243 start_dts, start_ct, track->track_id);
4244 ✗ start_dts = track->cluster[0].dts;
4245 ✗ start_ct = track->cluster[0].cts;
4246 }
4247 }
4248
4249 522 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4250 522 track->timescale, AV_ROUND_DOWN);
4251
4252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 522 times.
522 if (mov->mode == MODE_AVIF) {
4253 ✗ delay = 0;
4254 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4255 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4256 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4257 // edit list is repeated.
4258 ✗ flags = mov->avif_loop_count != 1;
4259 ✗ start_ct = 0;
4260 }
4261
4262 522 version |= delay < INT32_MAX ? 0 : 1;
4263
4264
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 518 times.
522 entry_size = (version == 1) ? 20 : 12;
4265
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 518 times.
522 entry_count = 1 + (delay > 0);
4266 522 size = 24 + entry_count * entry_size;
4267
4268 /* write the atom data */
4269 522 avio_wb32(pb, size);
4270 522 ffio_wfourcc(pb, "edts");
4271 522 avio_wb32(pb, size - 8);
4272 522 ffio_wfourcc(pb, "elst");
4273 522 avio_w8(pb, version);
4274 522 avio_wb24(pb, flags); /* flags */
4275
4276 522 avio_wb32(pb, entry_count);
4277
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 518 times.
522 if (delay > 0) { /* add an empty edit to delay presentation */
4278 /* In the positive delay case, the delay includes the cts
4279 * offset, and the second edit list entry below trims out
4280 * the same amount from the actual content. This makes sure
4281 * that the offset last sample is included in the edit
4282 * list duration as well. */
4283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (version == 1) {
4284 ✗ avio_wb64(pb, delay);
4285 ✗ avio_wb64(pb, -1);
4286 } else {
4287 4 avio_wb32(pb, delay);
4288 4 avio_wb32(pb, -1);
4289 }
4290 4 avio_wb32(pb, 0x00010000);
4291
1/2
✓ Branch 0 taken 518 times.
✗ Branch 1 not taken.
518 } else if (mov->mode != MODE_AVIF) {
4292 /* Avoid accidentally ending up with start_ct = -1 which has got a
4293 * special meaning. Normally start_ct should end up positive or zero
4294 * here, but use FFMIN in case dts is a small positive integer
4295 * rounded to 0 when represented in movie timescale units. */
4296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 518 times.
518 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4297 518 start_ct = -FFMIN(start_dts, 0);
4298
4299 #if CONFIG_IAMFENC
4300
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 513 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
518 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4301 ✗ start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4302 #endif
4303 /* Note, this delay is calculated from the pts of the first sample,
4304 * ensuring that we don't reduce the duration for cases with
4305 * dts<0 pts=0. */
4306 518 duration += delay;
4307 }
4308
4309 /* For fragmented files, we don't know the full length yet. Setting
4310 * duration to 0 allows us to only specify the offset, including
4311 * the rest of the content (from all future fragments) without specifying
4312 * an explicit duration.
4313 *
4314 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4315 * don't reset duration to zero.
4316 */
4317
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 258 times.
522 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4318
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
264 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4319 264 duration = 0;
4320
4321 /* duration */
4322
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 518 times.
522 if (version == 1) {
4323 4 avio_wb64(pb, duration);
4324 4 avio_wb64(pb, start_ct);
4325 } else {
4326 518 avio_wb32(pb, duration);
4327 518 avio_wb32(pb, start_ct);
4328 }
4329 522 avio_wb32(pb, 0x00010000);
4330 522 return size;
4331 }
4332
4333 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4334 {
4335 14 int64_t pos = avio_tell(pb);
4336 14 avio_wb32(pb, 0); // size placeholder
4337 14 ffio_wfourcc(pb, "tref");
4338
4339
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 for (int i = 0; i < track->nb_tref_tags; i++) {
4340 14 MovTag *tag = &track->tref_tags[i];
4341 14 avio_wb32(pb, 8 + tag->nb_id * sizeof(*tag->id)); // size (subatom)
4342 14 avio_wl32(pb, tag->name);
4343
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 14 times.
30 for (int j = 0; j < tag->nb_id; j++)
4344 16 avio_wb32(pb, tag->id[j]);
4345 }
4346 14 return update_size(pb, pos);
4347 }
4348
4349 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4350 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4351 {
4352 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4353 2 ffio_wfourcc(pb, "uuid");
4354 2 ffio_wfourcc(pb, "USMT");
4355 2 avio_wb32(pb, 0x21d24fce);
4356 2 avio_wb32(pb, 0xbb88695c);
4357 2 avio_wb32(pb, 0xfac9c740);
4358 2 avio_wb32(pb, 0x1c); // another size here!
4359 2 ffio_wfourcc(pb, "MTDT");
4360 2 avio_wb32(pb, 0x00010012);
4361 2 avio_wb32(pb, 0x0a);
4362 2 avio_wb32(pb, 0x55c40000);
4363 2 avio_wb32(pb, 0x1);
4364 2 avio_wb32(pb, 0x0);
4365 2 return 0x34;
4366 }
4367
4368 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4369 {
4370 2 AVFormatContext *ctx = track->rtp_ctx;
4371 2 char buf[1000] = "";
4372 int len;
4373
4374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
4375 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], *track->src_track,
4376 NULL, NULL, 0, 0, ctx);
4377 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4378 2 len = strlen(buf);
4379
4380 2 avio_wb32(pb, len + 24);
4381 2 ffio_wfourcc(pb, "udta");
4382 2 avio_wb32(pb, len + 16);
4383 2 ffio_wfourcc(pb, "hnti");
4384 2 avio_wb32(pb, len + 8);
4385 2 ffio_wfourcc(pb, "sdp ");
4386 2 avio_write(pb, buf, len);
4387 2 return len + 24;
4388 }
4389
4390 563 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4391 const char *tag, const char *str)
4392 {
4393 563 int64_t pos = avio_tell(pb);
4394 563 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4395
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 562 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
563 if (!t || !utf8len(t->value))
4396 562 return 0;
4397
4398 1 avio_wb32(pb, 0); /* size */
4399 1 ffio_wfourcc(pb, tag); /* type */
4400 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4401 1 return update_size(pb, pos);
4402 }
4403
4404 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4405 const char *value)
4406 {
4407 2 int64_t pos = avio_tell(pb);
4408
4409 /* Box|FullBox basics */
4410 2 avio_wb32(pb, 0); /* size placeholder */
4411 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4412 2 avio_w8(pb, 0); /* version = 0 */
4413 2 avio_wb24(pb, 0); /* flags = 0 */
4414
4415 /* Required null-terminated scheme URI */
4416 2 avio_write(pb, (const unsigned char *)scheme_uri,
4417 2 strlen(scheme_uri));
4418 2 avio_w8(pb, 0);
4419
4420 /* Optional value string */
4421
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])
4422 2 avio_write(pb, (const unsigned char *)value,
4423 2 strlen(value));
4424
4425 2 avio_w8(pb, 0);
4426
4427 2 return update_size(pb, pos);
4428 }
4429
4430 377 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4431 {
4432 377 int ret = AVERROR_BUG;
4433
4434
2/2
✓ Branch 0 taken 377 times.
✓ Branch 1 taken 377 times.
754 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4435 377 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4436
4437
2/2
✓ Branch 0 taken 1885 times.
✓ Branch 1 taken 377 times.
2262 for (int j = 0; map.value_maps[j].disposition; j++) {
4438 1885 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4439
2/2
✓ Branch 0 taken 1883 times.
✓ Branch 1 taken 2 times.
1885 if (!(st->disposition & value_map.disposition))
4440 1883 continue;
4441
4442
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)
4443 ✗ return ret;
4444 }
4445 }
4446
4447 377 return 0;
4448 }
4449
4450 586 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4451 AVStream *st)
4452 {
4453 AVIOContext *pb_buf;
4454 int ret, size;
4455 uint8_t *buf;
4456
4457
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 573 times.
586 if (!st)
4458 13 return 0;
4459
4460 573 ret = avio_open_dyn_buf(&pb_buf);
4461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 573 times.
573 if (ret < 0)
4462 ✗ return ret;
4463
4464
2/2
✓ Branch 0 taken 563 times.
✓ Branch 1 taken 10 times.
573 if (mov->mode & (MODE_MP4|MODE_MOV))
4465 563 mov_write_track_metadata(pb_buf, st, "name", "title");
4466
4467
2/2
✓ Branch 0 taken 377 times.
✓ Branch 1 taken 196 times.
573 if (mov->mode & MODE_MP4) {
4468
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 377 times.
377 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4469 ✗ goto end;
4470 }
4471
4472
2/2
✓ Branch 1 taken 570 times.
✓ Branch 2 taken 3 times.
573 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4473 3 avio_wb32(pb, size + 8);
4474 3 ffio_wfourcc(pb, "udta");
4475 3 avio_write(pb, buf, size);
4476 }
4477 570 end:
4478 573 ffio_free_dyn_buf(&pb_buf);
4479
4480 573 return ret;
4481 }
4482
4483 586 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4484 MOVTrack *track, AVStream *st)
4485 {
4486 586 int64_t pos = avio_tell(pb);
4487 586 int entry_backup = track->entry;
4488 586 int chunk_backup = track->chunkCount;
4489 int ret;
4490
4491 /* If we want to have an empty moov, but some samples already have been
4492 * buffered (delay_moov), pretend that no samples have been written yet. */
4493
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 282 times.
586 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4494 304 track->chunkCount = track->entry = 0;
4495
4496 586 avio_wb32(pb, 0); /* size */
4497 586 ffio_wfourcc(pb, "trak");
4498 586 mov_write_tkhd_tag(pb, mov, track, st);
4499
4500 av_assert2(mov->use_editlist >= 0);
4501
4502
2/2
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 38 times.
586 if (track->start_dts != AV_NOPTS_VALUE) {
4503
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 26 times.
548 if (mov->use_editlist)
4504 522 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4505
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))
4506 ✗ av_log(mov->fc, AV_LOG_WARNING,
4507 "Not writing any edit list even though one would have been required\n");
4508 }
4509
4510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
586 if (mov->is_animated_avif)
4511 ✗ mov_write_edts_tag(pb, mov, track);
4512
4513
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 572 times.
586 if (track->nb_tref_tags)
4514 14 mov_write_tref_tag(pb, track);
4515
4516
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 586 times.
586 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4517 ✗ return ret;
4518
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 584 times.
586 if (track->mode == MODE_PSP)
4519 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4520
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 584 times.
586 if (track->tag == MKTAG('r','t','p',' '))
4521 2 mov_write_udta_sdp(pb, track);
4522
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 394 times.
586 if (track->mode == MODE_MOV) {
4523
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 48 times.
192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4524 144 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4525
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
144 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4526 1 mov_write_tapt_tag(pb, track);
4527 }
4528 }
4529
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
192 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4530 ✗ mov_write_tapt_tag(pb, track);
4531 }
4532 }
4533 586 mov_write_track_udta_tag(pb, mov, st);
4534 586 track->entry = entry_backup;
4535 586 track->chunkCount = chunk_backup;
4536 586 return update_size(pb, pos);
4537 }
4538
4539 ✗ static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4540 {
4541 ✗ int i, has_audio = 0, has_video = 0;
4542 ✗ int64_t pos = avio_tell(pb);
4543 ✗ int audio_profile = mov->iods_audio_profile;
4544 ✗ int video_profile = mov->iods_video_profile;
4545 ✗ for (i = 0; i < mov->nb_tracks; i++) {
4546 ✗ if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4547 ✗ has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4548 ✗ has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4549 }
4550 }
4551 ✗ if (audio_profile < 0)
4552 ✗ audio_profile = 0xFF - has_audio;
4553 ✗ if (video_profile < 0)
4554 ✗ video_profile = 0xFF - has_video;
4555 ✗ avio_wb32(pb, 0x0); /* size */
4556 ✗ ffio_wfourcc(pb, "iods");
4557 ✗ avio_wb32(pb, 0); /* version & flags */
4558 ✗ put_descr(pb, 0x10, 7);
4559 ✗ avio_wb16(pb, 0x004f);
4560 ✗ avio_w8(pb, 0xff);
4561 ✗ avio_w8(pb, 0xff);
4562 ✗ avio_w8(pb, audio_profile);
4563 ✗ avio_w8(pb, video_profile);
4564 ✗ avio_w8(pb, 0xff);
4565 ✗ return update_size(pb, pos);
4566 }
4567
4568 324 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4569 {
4570 324 avio_wb32(pb, 0x20); /* size */
4571 324 ffio_wfourcc(pb, "trex");
4572 324 avio_wb32(pb, 0); /* version & flags */
4573 324 avio_wb32(pb, track->track_id); /* track ID */
4574 324 avio_wb32(pb, 1); /* default sample description index */
4575 324 avio_wb32(pb, 0); /* default sample duration */
4576 324 avio_wb32(pb, 0); /* default sample size */
4577 324 avio_wb32(pb, 0); /* default sample flags */
4578 324 return 0;
4579 }
4580
4581 70 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4582 {
4583 70 int64_t pos = avio_tell(pb);
4584 int i;
4585 70 avio_wb32(pb, 0x0); /* size */
4586 70 ffio_wfourcc(pb, "mvex");
4587
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 70 times.
394 for (i = 0; i < mov->nb_tracks; i++)
4588 324 mov_write_trex_tag(pb, &mov->tracks[i]);
4589 70 return update_size(pb, pos);
4590 }
4591
4592 286 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4593 {
4594 286 int max_track_id = 1, i;
4595 286 int64_t max_track_len = 0;
4596 int version;
4597 int timescale;
4598
4599
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 286 times.
874 for (i = 0; i < mov->nb_tracks; i++) {
4600
3/4
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 548 times.
✗ Branch 3 not taken.
588 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4601 1096 int64_t max_track_len_temp = av_rescale_rnd(
4602 548 calc_pts_duration(mov, &mov->tracks[i]),
4603 548 mov->movie_timescale,
4604 548 mov->tracks[i].timescale,
4605 AV_ROUND_UP);
4606
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 268 times.
548 if (max_track_len < max_track_len_temp)
4607 280 max_track_len = max_track_len_temp;
4608
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 266 times.
548 if (max_track_id < mov->tracks[i].track_id)
4609 282 max_track_id = mov->tracks[i].track_id;
4610 }
4611 }
4612 /* If using delay_moov, make sure the output is the same as if no
4613 * samples had been written yet. */
4614
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 226 times.
286 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4615 60 max_track_len = 0;
4616 60 max_track_id = 1;
4617 }
4618
4619 286 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286 times.
286 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4621
4622 286 ffio_wfourcc(pb, "mvhd");
4623 286 avio_w8(pb, version);
4624 286 avio_wb24(pb, 0); /* flags */
4625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286 times.
286 if (version == 1) {
4626 ✗ avio_wb64(pb, mov->time);
4627 ✗ avio_wb64(pb, mov->time);
4628 } else {
4629 286 avio_wb32(pb, mov->time); /* creation time */
4630 286 avio_wb32(pb, mov->time); /* modification time */
4631 }
4632
4633 286 timescale = mov->movie_timescale;
4634
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
286 if (mov->mode == MODE_AVIF && !timescale)
4635 ✗ timescale = mov->tracks[0].timescale;
4636
4637 286 avio_wb32(pb, timescale);
4638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286 times.
286 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4639
4640 286 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4641 286 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4642 286 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4643
4644 /* Matrix structure */
4645 286 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4646
4647 286 avio_wb32(pb, 0); /* reserved (preview time) */
4648 286 avio_wb32(pb, 0); /* reserved (preview duration) */
4649 286 avio_wb32(pb, 0); /* reserved (poster time) */
4650 286 avio_wb32(pb, 0); /* reserved (selection time) */
4651 286 avio_wb32(pb, 0); /* reserved (selection duration) */
4652 286 avio_wb32(pb, 0); /* reserved (current time) */
4653 286 avio_wb32(pb, max_track_id + 1); /* Next track id */
4654 286 return 0x6c;
4655 }
4656
4657 126 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4658 AVFormatContext *s)
4659 {
4660 126 avio_wb32(pb, 33); /* size */
4661 126 ffio_wfourcc(pb, "hdlr");
4662 126 avio_wb32(pb, 0);
4663 126 avio_wb32(pb, 0);
4664 126 ffio_wfourcc(pb, "mdir");
4665 126 ffio_wfourcc(pb, "appl");
4666 126 avio_wb32(pb, 0);
4667 126 avio_wb32(pb, 0);
4668 126 avio_w8(pb, 0);
4669 126 return 33;
4670 }
4671
4672 /* helper function to write a data tag with the specified string as data */
4673 75 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4674 {
4675 75 size_t data_len = strlen(data);
4676
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 34 times.
75 if (long_style) {
4677 41 int size = 16 + data_len;
4678 41 avio_wb32(pb, size); /* size */
4679 41 ffio_wfourcc(pb, "data");
4680 41 avio_wb32(pb, 1);
4681 41 avio_wb32(pb, 0);
4682 41 avio_write(pb, data, data_len);
4683 41 return size;
4684 } else {
4685 34 avio_wb16(pb, data_len); /* string length */
4686
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4687 26 lang = ff_mov_iso639_to_lang("und", 1);
4688 34 avio_wb16(pb, lang);
4689 34 avio_write(pb, data, data_len);
4690 34 return data_len + 4;
4691 }
4692 }
4693
4694 74 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4695 const char *value, int lang, int long_style)
4696 {
4697 74 int size = 0;
4698
2/4
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
✗ Branch 3 not taken.
74 if (value && value[0]) {
4699 74 int64_t pos = avio_tell(pb);
4700 74 avio_wb32(pb, 0); /* size */
4701 74 ffio_wfourcc(pb, name);
4702 74 mov_write_string_data_tag(pb, value, lang, long_style);
4703 74 size = update_size(pb, pos);
4704 }
4705 74 return size;
4706 }
4707
4708 1 static int mov_write_freeform_tag(AVIOContext *pb, const char *mean,
4709 const char *name, const char *data)
4710 {
4711
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!data || !data[0])
4712 ✗ return 0;
4713
4714 static const char stub_flags[4] = {0, 0, 0, 0};
4715
4716 1 int64_t entry_pos = avio_tell(pb);
4717 1 avio_wb32(pb, 0); /* size */
4718 1 ffio_wfourcc(pb, "----"); /* freeform */
4719
4720 1 size_t mean_len = strlen(mean);
4721 1 avio_wb32(pb, 12 + mean_len);
4722 1 ffio_wfourcc(pb, "mean");
4723 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4724 1 avio_write(pb, mean, mean_len);
4725
4726 1 size_t name_len = strlen(name);
4727 1 avio_wb32(pb, 12 + name_len);
4728 1 ffio_wfourcc(pb, "name");
4729 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4730 1 avio_write(pb, name, name_len);
4731
4732 1 mov_write_string_data_tag(pb, data, 0, 1);
4733
4734 1 return update_size(pb, entry_pos);
4735 }
4736
4737 4620 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4738 const char *tag, int *lang)
4739 {
4740 int l, len, len2;
4741 4620 AVDictionaryEntry *t, *t2 = NULL;
4742 char tag2[16];
4743
4744 4620 *lang = 0;
4745
4746
2/2
✓ Branch 1 taken 4557 times.
✓ Branch 2 taken 63 times.
4620 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4747 4557 return NULL;
4748
4749 63 len = strlen(t->key);
4750 63 snprintf(tag2, sizeof(tag2), "%s-", tag);
4751
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 55 times.
63 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4752 8 len2 = strlen(t2->key);
4753
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)
4754
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4755 8 *lang = l;
4756 8 return t;
4757 }
4758 }
4759 55 return t;
4760 }
4761
4762 4494 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4763 const char *name, const char *tag,
4764 int long_style)
4765 {
4766 int lang;
4767 4494 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4768
2/2
✓ Branch 0 taken 4431 times.
✓ Branch 1 taken 63 times.
4494 if (!t)
4769 4431 return 0;
4770 63 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4771 }
4772
4773 126 static int mov_write_custom_metadata(AVFormatContext *s, AVIOContext *pb,
4774 const char *mean, const char *name,
4775 const char *tag)
4776 {
4777 126 AVDictionaryEntry *t = av_dict_get(s->metadata, tag, NULL, 0);
4778
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 1 times.
126 if (!t)
4779 125 return 0;
4780 1 return mov_write_freeform_tag(pb, mean, name, t->value);
4781 }
4782
4783 /* iTunes bpm number */
4784 126 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4785 {
4786 126 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 int size = 0, tmpo = t ? atoi(t->value) : 0;
4788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (tmpo) {
4789 ✗ size = 26;
4790 ✗ avio_wb32(pb, size);
4791 ✗ ffio_wfourcc(pb, "tmpo");
4792 ✗ avio_wb32(pb, size-8); /* size */
4793 ✗ ffio_wfourcc(pb, "data");
4794 ✗ avio_wb32(pb, 0x15); //type specifier
4795 ✗ avio_wb32(pb, 0);
4796 ✗ avio_wb16(pb, tmpo); // data
4797 }
4798 126 return size;
4799 }
4800
4801 /* 3GPP TS 26.244 */
4802 126 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4803 {
4804 int lang;
4805 126 int64_t pos = avio_tell(pb);
4806 double latitude, longitude, altitude;
4807 int32_t latitude_fix, longitude_fix, altitude_fix;
4808 126 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4809 126 const char *ptr, *place = "";
4810 char *end;
4811 static const char *astronomical_body = "earth";
4812
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 if (!t)
4813 126 return 0;
4814
4815 ✗ ptr = t->value;
4816 ✗ latitude = strtod(ptr, &end);
4817 ✗ if (end == ptr) {
4818 ✗ av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4819 ✗ return 0;
4820 }
4821 ✗ ptr = end;
4822 ✗ longitude = strtod(ptr, &end);
4823 ✗ if (end == ptr) {
4824 ✗ av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4825 ✗ return 0;
4826 }
4827 ✗ ptr = end;
4828 ✗ altitude = strtod(ptr, &end);
4829 /* If no altitude was present, the default 0 should be fine */
4830 ✗ if (*end == '/')
4831 ✗ place = end + 1;
4832
4833 ✗ latitude_fix = (int32_t) ((1 << 16) * latitude);
4834 ✗ longitude_fix = (int32_t) ((1 << 16) * longitude);
4835 ✗ altitude_fix = (int32_t) ((1 << 16) * altitude);
4836
4837 ✗ avio_wb32(pb, 0); /* size */
4838 ✗ ffio_wfourcc(pb, "loci"); /* type */
4839 ✗ avio_wb32(pb, 0); /* version + flags */
4840 ✗ avio_wb16(pb, lang);
4841 ✗ avio_write(pb, place, strlen(place) + 1);
4842 ✗ avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4843 ✗ avio_wb32(pb, longitude_fix);
4844 ✗ avio_wb32(pb, latitude_fix);
4845 ✗ avio_wb32(pb, altitude_fix);
4846 ✗ avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4847 ✗ avio_w8(pb, 0); /* additional notes, null terminated string */
4848
4849 ✗ return update_size(pb, pos);
4850 }
4851
4852 /* iTunes track or disc number */
4853 252 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4854 AVFormatContext *s, int disc)
4855 {
4856
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
252 AVDictionaryEntry *t = av_dict_get(s->metadata,
4857 disc ? "disc" : "track",
4858 NULL, 0);
4859
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 248 times.
252 int size = 0, track = t ? atoi(t->value) : 0;
4860
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 248 times.
252 if (track) {
4861 4 int tracks = 0;
4862 4 char *slash = strchr(t->value, '/');
4863
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (slash)
4864 3 tracks = atoi(slash + 1);
4865 4 avio_wb32(pb, 32); /* size */
4866
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4867 4 avio_wb32(pb, 24); /* size */
4868 4 ffio_wfourcc(pb, "data");
4869 4 avio_wb32(pb, 0); // 8 bytes empty
4870 4 avio_wb32(pb, 0);
4871 4 avio_wb16(pb, 0); // empty
4872 4 avio_wb16(pb, track); // track / disc number
4873 4 avio_wb16(pb, tracks); // total track / disc number
4874 4 avio_wb16(pb, 0); // empty
4875 4 size = 32;
4876 }
4877 252 return size;
4878 }
4879
4880 756 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4881 const char *name, const char *tag,
4882 int len)
4883 {
4884 756 AVDictionaryEntry *t = NULL;
4885 uint8_t num;
4886 756 int size = 24 + len;
4887
4888
3/4
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 504 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 252 times.
756 if (len != 1 && len != 4)
4889 ✗ return -1;
4890
4891
2/2
✓ Branch 1 taken 754 times.
✓ Branch 2 taken 2 times.
756 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4892 754 return 0;
4893 2 num = atoi(t->value);
4894
4895 2 avio_wb32(pb, size);
4896 2 ffio_wfourcc(pb, name);
4897 2 avio_wb32(pb, size - 8);
4898 2 ffio_wfourcc(pb, "data");
4899 2 avio_wb32(pb, 0x15);
4900 2 avio_wb32(pb, 0);
4901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4902 2 else avio_w8 (pb, num);
4903
4904 2 return size;
4905 }
4906
4907 126 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4908 {
4909 126 MOVMuxContext *mov = s->priv_data;
4910 126 int64_t pos = 0;
4911
4912
2/2
✓ Branch 0 taken 387 times.
✓ Branch 1 taken 126 times.
513 for (int i = 0; i < mov->nb_streams; i++) {
4913 387 MOVTrack *trk = &mov->tracks[i];
4914
4915
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 385 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
387 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4916 385 continue;
4917
4918
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4919 1 pos = avio_tell(pb);
4920 1 avio_wb32(pb, 0);
4921 1 ffio_wfourcc(pb, "covr");
4922 }
4923 2 avio_wb32(pb, 16 + trk->cover_image->size);
4924 2 ffio_wfourcc(pb, "data");
4925 2 avio_wb32(pb, trk->tag);
4926 2 avio_wb32(pb , 0);
4927 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4928 }
4929
4930
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 125 times.
126 return pos ? update_size(pb, pos) : 0;
4931 }
4932
4933 /* iTunes meta data list */
4934 126 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4935 AVFormatContext *s)
4936 {
4937 126 int64_t pos = avio_tell(pb);
4938 126 avio_wb32(pb, 0); /* size */
4939 126 ffio_wfourcc(pb, "ilst");
4940 126 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4941 126 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4942 126 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4943 126 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4944 126 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4945 126 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4946
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
126 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4947
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 115 times.
126 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4948 11 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4949 }
4950 126 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4951 126 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4952 126 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4953 126 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4954 126 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4955 126 mov_write_string_metadata(s, pb, "desc", "description",1);
4956 126 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4957 126 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4958 126 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4959 126 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4960 126 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4961 126 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4962 126 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4963 126 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4964 126 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4965 126 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4966 126 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4967 126 mov_write_covr(pb, s);
4968 126 mov_write_trkn_tag(pb, mov, s, 0); // track number
4969 126 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4970 126 mov_write_tmpo_tag(pb, s);
4971 126 mov_write_custom_metadata(s, pb, "com.apple.iTunes", "DISCSUBTITLE", "disc_subtitle");
4972 126 return update_size(pb, pos);
4973 }
4974
4975 ✗ static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4976 AVFormatContext *s)
4977 {
4978 ✗ avio_wb32(pb, 33); /* size */
4979 ✗ ffio_wfourcc(pb, "hdlr");
4980 ✗ avio_wb32(pb, 0);
4981 ✗ avio_wb32(pb, 0);
4982 ✗ ffio_wfourcc(pb, "mdta");
4983 ✗ avio_wb32(pb, 0);
4984 ✗ avio_wb32(pb, 0);
4985 ✗ avio_wb32(pb, 0);
4986 ✗ avio_w8(pb, 0);
4987 ✗ return 33;
4988 }
4989
4990 ✗ static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4991 AVFormatContext *s)
4992 {
4993 ✗ const AVDictionaryEntry *t = NULL;
4994 ✗ int64_t pos = avio_tell(pb);
4995 int64_t curpos, entry_pos;
4996 ✗ int count = 0;
4997
4998 ✗ avio_wb32(pb, 0); /* size */
4999 ✗ ffio_wfourcc(pb, "keys");
5000 ✗ avio_wb32(pb, 0);
5001 ✗ entry_pos = avio_tell(pb);
5002 ✗ avio_wb32(pb, 0); /* entry count */
5003
5004 ✗ while (t = av_dict_iterate(s->metadata, t)) {
5005 ✗ size_t key_len = strlen(t->key);
5006 ✗ avio_wb32(pb, key_len + 8);
5007 ✗ ffio_wfourcc(pb, "mdta");
5008 ✗ avio_write(pb, t->key, key_len);
5009 ✗ count += 1;
5010 }
5011 ✗ curpos = avio_tell(pb);
5012 ✗ avio_seek(pb, entry_pos, SEEK_SET);
5013 ✗ avio_wb32(pb, count); // rewrite entry count
5014 ✗ avio_seek(pb, curpos, SEEK_SET);
5015
5016 ✗ return update_size(pb, pos);
5017 }
5018
5019 ✗ static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
5020 AVFormatContext *s)
5021 {
5022 ✗ const AVDictionaryEntry *t = NULL;
5023 ✗ int64_t pos = avio_tell(pb);
5024 ✗ int count = 1; /* keys are 1-index based */
5025
5026 ✗ avio_wb32(pb, 0); /* size */
5027 ✗ ffio_wfourcc(pb, "ilst");
5028
5029 ✗ while (t = av_dict_iterate(s->metadata, t)) {
5030 ✗ int64_t entry_pos = avio_tell(pb);
5031 ✗ avio_wb32(pb, 0); /* size */
5032 ✗ avio_wb32(pb, count); /* key */
5033 ✗ mov_write_string_data_tag(pb, t->value, 0, 1);
5034 ✗ update_size(pb, entry_pos);
5035 ✗ count += 1;
5036 }
5037 ✗ return update_size(pb, pos);
5038 }
5039
5040 /* meta data tags */
5041 126 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
5042 AVFormatContext *s)
5043 {
5044 126 int size = 0;
5045 126 int64_t pos = avio_tell(pb);
5046 126 avio_wb32(pb, 0); /* size */
5047 126 ffio_wfourcc(pb, "meta");
5048 126 avio_wb32(pb, 0);
5049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
5050 ✗ mov_write_mdta_hdlr_tag(pb, mov, s);
5051 ✗ mov_write_mdta_keys_tag(pb, mov, s);
5052 ✗ mov_write_mdta_ilst_tag(pb, mov, s);
5053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 } else if (mov->mode == MODE_AVIF) {
5054 ✗ mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
5055 // We always write the primary item id as 1 since only one track is
5056 // supported for AVIF.
5057 ✗ mov_write_pitm_tag(pb, 1);
5058 ✗ mov_write_iloc_tag(pb, mov, s);
5059 ✗ mov_write_iinf_tag(pb, mov, s);
5060 ✗ if (mov->nb_streams > 1)
5061 ✗ mov_write_iref_tag(pb, mov, s);
5062 ✗ mov_write_iprp_tag(pb, mov, s);
5063 } else {
5064 /* iTunes metadata tag */
5065 126 mov_write_itunes_hdlr_tag(pb, mov, s);
5066 126 mov_write_ilst_tag(pb, mov, s);
5067 }
5068 126 size = update_size(pb, pos);
5069 126 return size;
5070 }
5071
5072 159 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
5073 const char *name, const char *key)
5074 {
5075 int len;
5076 AVDictionaryEntry *t;
5077
5078
1/2
✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
159 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
5079 159 return 0;
5080
5081 ✗ len = strlen(t->value);
5082 ✗ if (len > 0) {
5083 ✗ int size = len + 8;
5084 ✗ avio_wb32(pb, size);
5085 ✗ ffio_wfourcc(pb, name);
5086 ✗ avio_write(pb, t->value, len);
5087 ✗ return size;
5088 }
5089 ✗ return 0;
5090 }
5091
5092 ✗ static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
5093 {
5094 int val;
5095 ✗ while (*b) {
5096 ✗ GET_UTF8(val, *b++, return -1;)
5097 ✗ avio_wb16(pb, val);
5098 }
5099 ✗ avio_wb16(pb, 0x00);
5100 ✗ return 0;
5101 }
5102
5103 ✗ static uint16_t language_code(const char *str)
5104 {
5105 ✗ return (((str[0] - 0x60) & 0x1F) << 10) +
5106 ✗ (((str[1] - 0x60) & 0x1F) << 5) +
5107 ✗ (( str[2] - 0x60) & 0x1F);
5108 }
5109
5110 ✗ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
5111 const char *tag, const char *str)
5112 {
5113 ✗ int64_t pos = avio_tell(pb);
5114 ✗ AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
5115 ✗ if (!t || !utf8len(t->value))
5116 ✗ return 0;
5117 ✗ avio_wb32(pb, 0); /* size */
5118 ✗ ffio_wfourcc(pb, tag); /* type */
5119 ✗ avio_wb32(pb, 0); /* version + flags */
5120 ✗ if (!strcmp(tag, "yrrc"))
5121 ✗ avio_wb16(pb, atoi(t->value));
5122 else {
5123 ✗ avio_wb16(pb, language_code("eng")); /* language */
5124 ✗ avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
5125 ✗ if (!strcmp(tag, "albm") &&
5126 ✗ (t = av_dict_get(s->metadata, "track", NULL, 0)))
5127 ✗ avio_w8(pb, atoi(t->value));
5128 }
5129 ✗ return update_size(pb, pos);
5130 }
5131
5132 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
5133 {
5134 1 int64_t pos = avio_tell(pb);
5135 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
5136
5137 1 avio_wb32(pb, 0); // size
5138 1 ffio_wfourcc(pb, "chpl");
5139 1 avio_wb32(pb, 0x01000000); // version + flags
5140 1 avio_wb32(pb, 0); // unknown
5141 1 avio_w8(pb, nb_chapters);
5142
5143
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
5144 4 AVChapter *c = s->chapters[i];
5145 AVDictionaryEntry *t;
5146 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
5147
5148
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
5149
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
5150 4 avio_w8(pb, len);
5151 4 avio_write(pb, t->value, len);
5152 } else
5153 ✗ avio_w8(pb, 0);
5154 }
5155 1 return update_size(pb, pos);
5156 }
5157
5158 285 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
5159 AVFormatContext *s)
5160 {
5161 AVIOContext *pb_buf;
5162 int ret, size;
5163 uint8_t *buf;
5164
5165 285 ret = avio_open_dyn_buf(&pb_buf);
5166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 if (ret < 0)
5167 ✗ return ret;
5168
5169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 if (mov->mode & MODE_3GP) {
5170 ✗ mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
5171 ✗ mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
5172 ✗ mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
5173 ✗ mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
5174 ✗ mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
5175 ✗ mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
5176 ✗ mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
5177 ✗ mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
5178 ✗ mov_write_loci_tag(s, pb_buf);
5179
3/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
285 } 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
5180 159 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
5181 159 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
5182 159 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
5183 159 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
5184 159 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
5185 159 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
5186 // currently ignored by mov.c
5187 159 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
5188 // add support for libquicktime, this atom is also actually read by mov.c
5189 159 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
5190 159 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
5191 159 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
5192 159 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
5193 159 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
5194 159 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
5195 159 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
5196 159 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
5197 } else {
5198 /* iTunes meta data */
5199 126 mov_write_meta_tag(pb_buf, mov, s);
5200 126 mov_write_loci_tag(s, pb_buf);
5201 }
5202
5203
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 284 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
285 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
5204 1 mov_write_chpl_tag(pb_buf, s);
5205
5206
2/2
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 131 times.
285 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
5207 154 avio_wb32(pb, size + 8);
5208 154 ffio_wfourcc(pb, "udta");
5209 154 avio_write(pb, buf, size);
5210 }
5211 285 ffio_free_dyn_buf(&pb_buf);
5212
5213 285 return 0;
5214 }
5215
5216 ✗ static void mov_write_psp_udta_tag(AVIOContext *pb,
5217 const char *str, const char *lang, int type)
5218 {
5219 ✗ int len = utf8len(str) + 1;
5220 ✗ if (len <= 0)
5221 ✗ return;
5222 ✗ avio_wb16(pb, len * 2 + 10); /* size */
5223 ✗ avio_wb32(pb, type); /* type */
5224 ✗ avio_wb16(pb, language_code(lang)); /* language */
5225 ✗ avio_wb16(pb, 0x01); /* ? */
5226 ✗ ascii_to_wc(pb, str);
5227 }
5228
5229 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5230 {
5231 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5232 int64_t pos, pos2;
5233
5234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5235 ✗ pos = avio_tell(pb);
5236 ✗ avio_wb32(pb, 0); /* size placeholder*/
5237 ✗ ffio_wfourcc(pb, "uuid");
5238 ✗ ffio_wfourcc(pb, "USMT");
5239 ✗ avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5240 ✗ avio_wb32(pb, 0xbb88695c);
5241 ✗ avio_wb32(pb, 0xfac9c740);
5242
5243 ✗ pos2 = avio_tell(pb);
5244 ✗ avio_wb32(pb, 0); /* size placeholder*/
5245 ✗ ffio_wfourcc(pb, "MTDT");
5246 ✗ avio_wb16(pb, 4);
5247
5248 // ?
5249 ✗ avio_wb16(pb, 0x0C); /* size */
5250 ✗ avio_wb32(pb, 0x0B); /* type */
5251 ✗ avio_wb16(pb, language_code("und")); /* language */
5252 ✗ avio_wb16(pb, 0x0); /* ? */
5253 ✗ avio_wb16(pb, 0x021C); /* data */
5254
5255 ✗ if (!(s->flags & AVFMT_FLAG_BITEXACT))
5256 ✗ mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5257 ✗ mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5258 ✗ mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5259
5260 ✗ update_size(pb, pos2);
5261 ✗ return update_size(pb, pos);
5262 }
5263
5264 1 return 0;
5265 }
5266
5267 575 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5268 {
5269 AVEncryptionInitInfo *info;
5270 575 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5271 575 st->codecpar->nb_coded_side_data,
5272 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5273
1/2
✓ Branch 0 taken 575 times.
✗ Branch 1 not taken.
575 if (!sd)
5274 575 return 0;
5275
5276 ✗ info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5277 ✗ for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5278 int64_t pos;
5279
5280 ✗ if (!copy->data_size && !copy->num_key_ids)
5281 ✗ continue;
5282
5283 ✗ pos = avio_tell(pb);
5284 ✗ avio_wb32(pb, 0); /* size placeholder */
5285 ✗ ffio_wfourcc(pb, "pssh");
5286 ✗ avio_w8(pb, 1); /* version */
5287 ✗ avio_wb24(pb, 0);
5288 ✗ for (int i = 0; i < copy->system_id_size; i++)
5289 ✗ avio_w8(pb, copy->system_id[i]);
5290 ✗ avio_wb32(pb, copy->num_key_ids);
5291 ✗ for (int i = 0; i < copy->num_key_ids; i++)
5292 ✗ for (int j = 0; j < copy->key_id_size; j++)
5293 ✗ avio_w8(pb, copy->key_ids[i][j]);
5294 ✗ avio_wb32(pb, copy->data_size);
5295 ✗ avio_write(pb, copy->data, copy->data_size);
5296 ✗ update_size(pb, pos);
5297 }
5298
5299 ✗ av_encryption_init_info_free(info);
5300
5301 ✗ return 0;
5302 }
5303
5304 548 static void build_chunks(MOVTrack *trk)
5305 {
5306 int i;
5307 548 MOVIentry *chunk = &trk->cluster[0];
5308 548 uint64_t chunkSize = chunk->size;
5309 548 chunk->chunkNum = 1;
5310
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 390 times.
548 if (trk->chunkCount)
5311 158 return;
5312 390 trk->chunkCount = 1;
5313
2/2
✓ Branch 0 taken 20627 times.
✓ Branch 1 taken 390 times.
21017 for (i = 1; i<trk->entry; i++){
5314
2/2
✓ Branch 0 taken 18888 times.
✓ Branch 1 taken 1739 times.
20627 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5315
2/2
✓ Branch 0 taken 18886 times.
✓ Branch 1 taken 2 times.
18888 chunk->stsd_index == trk->cluster[i].stsd_index &&
5316
2/2
✓ Branch 0 taken 18241 times.
✓ Branch 1 taken 645 times.
18886 chunkSize + trk->cluster[i].size < (1<<20)){
5317 18241 chunkSize += trk->cluster[i].size;
5318 18241 chunk->samples_in_chunk += trk->cluster[i].entries;
5319 } else {
5320 2386 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5321 2386 chunk=&trk->cluster[i];
5322 2386 chunkSize = chunk->size;
5323 2386 trk->chunkCount++;
5324 }
5325 }
5326 }
5327
5328 /**
5329 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5330 * the stream ids are used as track ids.
5331 *
5332 * This assumes mov->tracks and s->streams are in the same order and
5333 * there are no gaps in either of them (so mov->tracks[n] refers to
5334 * s->streams[n]).
5335 *
5336 * As an exception, there can be more entries in
5337 * s->streams than in mov->tracks, in which case new track ids are
5338 * generated (starting after the largest found stream id).
5339 */
5340 286 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5341 {
5342 int i;
5343
5344
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 252 times.
286 if (mov->track_ids_ok)
5345 34 return 0;
5346
5347
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->use_stream_ids_as_track_ids) {
5348 1 int next_generated_track_id = 0;
5349
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5350 2 AVStream *st = mov->tracks[i].st;
5351
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5352 2 next_generated_track_id = st->id;
5353 }
5354
5355
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5356
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))
5357 ✗ continue;
5358
5359
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;
5360 }
5361 } else {
5362 251 int last_track_id = 0;
5363
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 251 times.
671 for (i = 0; i < mov->nb_tracks; i++) {
5364
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 384 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 34 times.
420 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5365 2 continue;
5366
5367 418 last_track_id =
5368 418 mov->tracks[i].track_id = (mov->tracks[i].st
5369 415 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5370
2/2
✓ Branch 0 taken 415 times.
✓ Branch 1 taken 3 times.
418 : FFMAX(i, last_track_id)) + 1;
5371 }
5372 }
5373
5374 252 mov->track_ids_ok = 1;
5375
5376 252 return 0;
5377 }
5378
5379 16 static int mov_find_tref_id(MOVMuxContext *mov, const MovTag *tag, uint32_t id)
5380 {
5381
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12 times.
19 for (int i = 0; i < tag->nb_id; i++) {
5382
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (tag->id[i] == id)
5383 4 return 1;
5384 }
5385 12 return 0;
5386 }
5387
5388 16 static int mov_add_tref_id(MOVMuxContext *mov, MovTag *tag, uint32_t id)
5389 {
5390 16 int ret = mov_find_tref_id(mov, tag, id);
5391
5392
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 if (!ret) {
5393 12 uint32_t *tmp = av_realloc_array(tag->id, tag->nb_id + 1, sizeof(*tag->id));
5394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!tmp)
5395 ✗ return AVERROR(ENOMEM);
5396 12 tag->id = tmp;
5397 12 tag->id[tag->nb_id++] = id;
5398 }
5399
5400 16 return 0;
5401 }
5402
5403 16 static MovTag *mov_find_tref_tag(MOVMuxContext *mov, const MOVTrack *trk, uint32_t name)
5404 {
5405
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 for (int i = 0; i < trk->nb_tref_tags; i++) {
5406 6 MovTag *entry = &trk->tref_tags[i];
5407
5408
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (entry->name == name)
5409 6 return entry;
5410 }
5411 10 return NULL;
5412 }
5413
5414 16 static MovTag *mov_add_tref_tag(MOVMuxContext *mov, MOVTrack *trk, uint32_t name)
5415 {
5416 16 MovTag *tag = mov_find_tref_tag(mov, trk, name);
5417
5418
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if (!tag) {
5419 10 MovTag *tmp = av_realloc_array(trk->tref_tags, trk->nb_tref_tags + 1,
5420 sizeof(*trk->tref_tags));
5421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!tmp)
5422 ✗ return NULL;
5423 10 trk->tref_tags = tmp;
5424 10 tag = &trk->tref_tags[trk->nb_tref_tags++];
5425 10 *tag = (MovTag){ .name = name };
5426 }
5427
5428 16 return tag;
5429 }
5430
5431 286 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5432 AVFormatContext *s)
5433 {
5434 int i;
5435 286 int64_t pos = avio_tell(pb);
5436 286 avio_wb32(pb, 0); /* size placeholder*/
5437 286 ffio_wfourcc(pb, "moov");
5438
5439 286 mov_setup_track_ids(mov, s);
5440
5441
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 286 times.
874 for (i = 0; i < mov->nb_tracks; i++) {
5442
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 548 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 38 times.
588 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5443 2 continue;
5444
5445 586 mov->tracks[i].time = mov->time;
5446
5447
2/2
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 38 times.
586 if (mov->tracks[i].entry)
5448 548 build_chunks(&mov->tracks[i]);
5449 }
5450
5451
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 285 times.
286 if (mov->chapter_track)
5452
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5453 1 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[i], MKTAG('c','h','a','p'));
5454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
5455 ✗ return AVERROR(ENOMEM);
5456
5457 1 int ret = mov_add_tref_id(mov, tag, mov->tracks[mov->chapter_track].track_id);
5458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
5459 ✗ return ret;
5460 }
5461
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 286 times.
874 for (i = 0; i < mov->nb_tracks; i++) {
5462 588 MOVTrack *track = &mov->tracks[i];
5463
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 586 times.
588 if (track->tag == MKTAG('r','t','p',' ')) {
5464 2 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('h','i','n','t'));
5465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
5466 ✗ return AVERROR(ENOMEM);
5467
5468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
5469 2 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
5471 ✗ return ret;
5472
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
586 } else if (track->tag == MKTAG('l','v','c','1') && track->nb_src_track) {
5473 ✗ MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('s','b','a','s'));
5474 ✗ if (!tag)
5475 ✗ return AVERROR(ENOMEM);
5476
5477 ✗ int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5478 ✗ if (ret < 0)
5479 ✗ return ret;
5480 } else {
5481
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 255 times.
586 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5482 331 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5483 331 track->st->codecpar->nb_coded_side_data,
5484 AV_PKT_DATA_FALLBACK_TRACK );
5485
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
331 if (sd && sd->size == sizeof(int)) {
5486 ✗ int *fallback = (int *)sd->data;
5487 ✗ if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5488 ✗ MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('f','a','l','l'));
5489 ✗ if (!tag)
5490 ✗ return AVERROR(ENOMEM);
5491
5492 ✗ int ret = mov_add_tref_id(mov, tag, mov->tracks[*fallback].track_id);
5493 ✗ if (ret < 0)
5494 ✗ return ret;
5495 }
5496 }
5497 }
5498
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 586 times.
599 for (int j = 0; j < track->nb_src_track; j++) {
5499 13 int src_trk = track->src_track[j];
5500 13 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[src_trk], track->tag);
5501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tag)
5502 ✗ return AVERROR(ENOMEM);
5503 13 int ret = mov_add_tref_id(mov, tag, track->track_id);
5504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (ret < 0)
5505 ✗ return ret;
5506 }
5507
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 560 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
586 if (mov->nb_meta_tmcd && track->nb_src_track) {
5508 /* Derive the duration from the first source track, matching
5509 * the convention used by get_pts_range() and the rtp/lvc1
5510 * branches above. The source may use a different timescale. */
5511 10 int src_trk = track->src_track[0];
5512 10 track->track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5513 10 track->timescale,
5514 10 mov->tracks[src_trk].timescale);
5515 }
5516 }
5517 }
5518
5519 286 mov_write_mvhd_tag(pb, mov);
5520
4/6
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 127 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 127 times.
286 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5521 ✗ mov_write_iods_tag(pb, mov);
5522
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 286 times.
874 for (i = 0; i < mov->nb_tracks; i++) {
5523
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 548 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 38 times.
588 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5525
2/2
✓ Branch 0 taken 573 times.
✓ Branch 1 taken 13 times.
586 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
586 if (ret < 0)
5527 ✗ return ret;
5528 }
5529 }
5530 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5531 * (mov->moov_written != 0)
5532 */
5533
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 214 times.
286 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5534
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
72 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
5535 70 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5536
5537
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 285 times.
286 if (mov->mode == MODE_PSP)
5538 1 mov_write_uuidusmt_tag(pb, s);
5539
1/2
✓ Branch 0 taken 285 times.
✗ Branch 1 not taken.
285 else if (mov->mode != MODE_AVIF)
5540 285 mov_write_udta_tag(pb, mov, s);
5541
2/2
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 286 times.
861 for (i = 0; i < mov->nb_streams; i++)
5542 575 mov_write_pssh_tag(pb, mov->tracks[i].st);
5543
5544 286 return update_size(pb, pos);
5545 }
5546
5547 ✗ static void param_write_int(AVIOContext *pb, const char *name, int value)
5548 {
5549 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5550 ✗ }
5551
5552 ✗ static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5553 {
5554 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5555 ✗ }
5556
5557 ✗ static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5558 {
5559 char buf[150];
5560 ✗ len = FFMIN(sizeof(buf) / 2 - 1, len);
5561 ✗ ff_data_to_hex(buf, value, len, 0);
5562 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5563 ✗ }
5564
5565 ✗ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5566 {
5567 ✗ int64_t pos = avio_tell(pb);
5568 int i;
5569
5570 static const AVUUID uuid = {
5571 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5572 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5573 };
5574
5575 ✗ avio_wb32(pb, 0);
5576 ✗ ffio_wfourcc(pb, "uuid");
5577 ✗ avio_write(pb, uuid, AV_UUID_LEN);
5578 ✗ avio_wb32(pb, 0);
5579
5580 ✗ avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5581 ✗ avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5582 ✗ avio_printf(pb, "<head>\n");
5583 ✗ if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5584 ✗ avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5585 LIBAVFORMAT_IDENT);
5586 ✗ avio_printf(pb, "</head>\n");
5587 ✗ avio_printf(pb, "<body>\n");
5588 ✗ avio_printf(pb, "<switch>\n");
5589
5590 ✗ mov_setup_track_ids(mov, s);
5591
5592 ✗ for (i = 0; i < mov->nb_tracks; i++) {
5593 ✗ MOVTrack *track = &mov->tracks[i];
5594 struct mpeg4_bit_rate_values bit_rates =
5595 ✗ calculate_mpeg4_bit_rates(track);
5596 const char *type;
5597 ✗ int track_id = track->track_id;
5598 ✗ char track_name_buf[32] = { 0 };
5599
5600 ✗ AVStream *st = track->st;
5601 ✗ AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5602
5603 ✗ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5604 ✗ type = "video";
5605 ✗ } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5606 ✗ type = "audio";
5607 } else {
5608 ✗ continue;
5609 }
5610
5611 ✗ avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5612 bit_rates.avg_bit_rate);
5613 ✗ param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5614 ✗ param_write_int(pb, "trackID", track_id);
5615 ✗ param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5616
5617 /* Build track name piece by piece: */
5618 /* 1. track type */
5619 ✗ av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5620 /* 2. track language, if available */
5621 ✗ if (lang)
5622 ✗ av_strlcatf(track_name_buf, sizeof(track_name_buf),
5623 "_%s", lang->value);
5624 /* 3. special type suffix */
5625 /* "_cc" = closed captions, "_ad" = audio_description */
5626 ✗ if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5627 ✗ av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5628 ✗ else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5629 ✗ av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5630
5631 ✗ param_write_string(pb, "trackName", track_name_buf);
5632
5633 ✗ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5634 ✗ if (track->par->codec_id == AV_CODEC_ID_H264) {
5635 uint8_t *ptr;
5636 ✗ int size = track->extradata_size[track->last_stsd_index];
5637 ✗ if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5638 &size)) {
5639 ✗ param_write_hex(pb, "CodecPrivateData",
5640 ✗ ptr ? ptr : track->extradata[track->last_stsd_index],
5641 size);
5642 ✗ av_free(ptr);
5643 }
5644 ✗ param_write_string(pb, "FourCC", "H264");
5645 ✗ } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5646 ✗ param_write_string(pb, "FourCC", "WVC1");
5647 ✗ param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5648 ✗ track->extradata_size[track->last_stsd_index]);
5649 }
5650 ✗ param_write_int(pb, "MaxWidth", track->par->width);
5651 ✗ param_write_int(pb, "MaxHeight", track->par->height);
5652 ✗ param_write_int(pb, "DisplayWidth", track->par->width);
5653 ✗ param_write_int(pb, "DisplayHeight", track->par->height);
5654 } else {
5655 ✗ if (track->par->codec_id == AV_CODEC_ID_AAC) {
5656 ✗ switch (track->par->profile) {
5657 ✗ case AV_PROFILE_AAC_HE_V2:
5658 ✗ param_write_string(pb, "FourCC", "AACP");
5659 ✗ break;
5660 ✗ case AV_PROFILE_AAC_HE:
5661 ✗ param_write_string(pb, "FourCC", "AACH");
5662 ✗ break;
5663 ✗ default:
5664 ✗ param_write_string(pb, "FourCC", "AACL");
5665 }
5666 ✗ } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5667 ✗ param_write_string(pb, "FourCC", "WMAP");
5668 }
5669 ✗ param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5670 ✗ track->extradata_size[track->last_stsd_index]);
5671 ✗ param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5672 ✗ track->par->codec_id));
5673 ✗ param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5674 ✗ param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5675 ✗ 0 : track->par->sample_rate);
5676 ✗ param_write_int(pb, "BitsPerSample", 16);
5677 ✗ param_write_int(pb, "PacketSize", track->par->block_align ?
5678 ✗ track->par->block_align : 4);
5679 }
5680 ✗ avio_printf(pb, "</%s>\n", type);
5681 }
5682 ✗ avio_printf(pb, "</switch>\n");
5683 ✗ avio_printf(pb, "</body>\n");
5684 ✗ avio_printf(pb, "</smil>\n");
5685
5686 ✗ return update_size(pb, pos);
5687 }
5688
5689 246 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5690 {
5691 246 avio_wb32(pb, 16);
5692 246 ffio_wfourcc(pb, "mfhd");
5693 246 avio_wb32(pb, 0);
5694 246 avio_wb32(pb, mov->fragments);
5695 246 return 0;
5696 }
5697
5698 19594 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5699 {
5700
2/2
✓ Branch 0 taken 13660 times.
✓ Branch 1 taken 5934 times.
19594 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5701 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5702 }
5703
5704 762 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5705 MOVTrack *track, int64_t moof_offset)
5706 {
5707 762 int64_t pos = avio_tell(pb);
5708 762 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5709 MOV_TFHD_BASE_DATA_OFFSET;
5710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
762 if (!track->entry) {
5711 ✗ flags |= MOV_TFHD_DURATION_IS_EMPTY;
5712 } else {
5713 762 flags |= MOV_TFHD_DEFAULT_FLAGS;
5714 }
5715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
762 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5716 ✗ flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5717
2/2
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 214 times.
762 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5718 548 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5719 548 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5720 }
5721 /* CMAF requires all values to be explicit in tfhd atoms */
5722
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 702 times.
762 if (mov->flags & FF_MOV_FLAG_CMAF)
5723 60 flags |= MOV_TFHD_STSD_ID;
5724
5725 /* Don't set a default sample size, the silverlight player refuses
5726 * to play files with that set. Don't set a default sample duration,
5727 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5728 * file format says it MUST NOT be set. */
5729
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 680 times.
762 if (track->mode == MODE_ISM)
5730 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5731 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5732
5733 762 avio_wb32(pb, 0); /* size placeholder */
5734 762 ffio_wfourcc(pb, "tfhd");
5735 762 avio_w8(pb, 0); /* version */
5736 762 avio_wb24(pb, flags);
5737
5738 762 avio_wb32(pb, track->track_id); /* track-id */
5739
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 630 times.
762 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5740 132 avio_wb64(pb, moof_offset);
5741
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 702 times.
762 if (flags & MOV_TFHD_STSD_ID) {
5742 60 avio_wb32(pb, 1);
5743 }
5744
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 82 times.
762 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5745 680 track->default_duration = get_cluster_duration(track, 0);
5746 680 avio_wb32(pb, track->default_duration);
5747 }
5748
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 82 times.
762 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5749
1/2
✓ Branch 0 taken 680 times.
✗ Branch 1 not taken.
680 track->default_size = track->entry ? track->cluster[0].size : 1;
5750 680 avio_wb32(pb, track->default_size);
5751 } else
5752 82 track->default_size = -1;
5753
5754
1/2
✓ Branch 0 taken 762 times.
✗ Branch 1 not taken.
762 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5755 /* Set the default flags based on the second sample, if available.
5756 * If the first sample is different, that can be signaled via a separate field. */
5757
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 72 times.
762 if (track->entry > 1)
5758 690 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5759 else
5760 72 track->default_sample_flags =
5761 72 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5762
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 56 times.
72 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5763 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5764 762 avio_wb32(pb, track->default_sample_flags);
5765 }
5766
5767 762 return update_size(pb, pos);
5768 }
5769
5770 764 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5771 MOVTrack *track, int moof_size,
5772 int first, int end)
5773 {
5774 764 int64_t pos = avio_tell(pb);
5775 764 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5776 int i;
5777
5778
2/2
✓ Branch 0 taken 18360 times.
✓ Branch 1 taken 764 times.
19124 for (i = first; i < end; i++) {
5779
2/2
✓ Branch 1 taken 1854 times.
✓ Branch 2 taken 16506 times.
18360 if (get_cluster_duration(track, i) != track->default_duration)
5780 1854 flags |= MOV_TRUN_SAMPLE_DURATION;
5781
2/2
✓ Branch 0 taken 2972 times.
✓ Branch 1 taken 15388 times.
18360 if (track->cluster[i].size != track->default_size)
5782 2972 flags |= MOV_TRUN_SAMPLE_SIZE;
5783
4/4
✓ Branch 0 taken 17596 times.
✓ Branch 1 taken 764 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 17586 times.
18360 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5784 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5785 }
5786
3/4
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 756 times.
✗ Branch 3 not taken.
764 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5787
2/2
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 576 times.
756 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5788 180 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5789
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 664 times.
764 if (track->flags & MOV_TRACK_CTTS)
5790 100 flags |= MOV_TRUN_SAMPLE_CTS;
5791
5792 764 avio_wb32(pb, 0); /* size placeholder */
5793 764 ffio_wfourcc(pb, "trun");
5794
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 606 times.
764 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5795 158 avio_w8(pb, 1); /* version */
5796 else
5797 606 avio_w8(pb, 0); /* version */
5798 764 avio_wb24(pb, flags);
5799
5800 764 avio_wb32(pb, end - first); /* sample count */
5801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 764 times.
764 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5802 ✗ !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5803 ✗ !mov->first_trun)
5804 ✗ avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5805 else
5806 764 avio_wb32(pb, moof_size + 8 + track->data_offset +
5807 764 track->cluster[first].pos); /* data offset */
5808
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 584 times.
764 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5809 180 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5810
5811
2/2
✓ Branch 0 taken 18360 times.
✓ Branch 1 taken 764 times.
19124 for (i = first; i < end; i++) {
5812
2/2
✓ Branch 0 taken 2050 times.
✓ Branch 1 taken 16310 times.
18360 if (flags & MOV_TRUN_SAMPLE_DURATION)
5813 2050 avio_wb32(pb, get_cluster_duration(track, i));
5814
2/2
✓ Branch 0 taken 3656 times.
✓ Branch 1 taken 14704 times.
18360 if (flags & MOV_TRUN_SAMPLE_SIZE)
5815 3656 avio_wb32(pb, track->cluster[i].size);
5816
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 17988 times.
18360 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5817 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5818
2/2
✓ Branch 0 taken 3162 times.
✓ Branch 1 taken 15198 times.
18360 if (flags & MOV_TRUN_SAMPLE_CTS)
5819 3162 avio_wb32(pb, track->cluster[i].cts);
5820 }
5821
5822 764 mov->first_trun = 0;
5823 764 return update_size(pb, pos);
5824 }
5825
5826 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5827 {
5828 82 int64_t pos = avio_tell(pb);
5829 static const uint8_t uuid[] = {
5830 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5831 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5832 };
5833
5834 82 avio_wb32(pb, 0); /* size placeholder */
5835 82 ffio_wfourcc(pb, "uuid");
5836 82 avio_write(pb, uuid, AV_UUID_LEN);
5837 82 avio_w8(pb, 1);
5838 82 avio_wb24(pb, 0);
5839 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5840 82 avio_wb64(pb, track->end_pts -
5841 82 (track->cluster[0].dts + track->cluster[0].cts));
5842
5843 82 return update_size(pb, pos);
5844 }
5845
5846 ✗ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5847 MOVTrack *track, int entry)
5848 {
5849 ✗ int n = track->nb_frag_info - 1 - entry, i;
5850 ✗ int size = 8 + 16 + 4 + 1 + 16*n;
5851 static const uint8_t uuid[] = {
5852 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5853 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5854 };
5855
5856 ✗ if (entry < 0)
5857 ✗ return 0;
5858
5859 ✗ avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5860 ✗ avio_wb32(pb, size);
5861 ✗ ffio_wfourcc(pb, "uuid");
5862 ✗ avio_write(pb, uuid, AV_UUID_LEN);
5863 ✗ avio_w8(pb, 1);
5864 ✗ avio_wb24(pb, 0);
5865 ✗ avio_w8(pb, n);
5866 ✗ for (i = 0; i < n; i++) {
5867 ✗ int index = entry + 1 + i;
5868 ✗ avio_wb64(pb, track->frag_info[index].time);
5869 ✗ avio_wb64(pb, track->frag_info[index].duration);
5870 }
5871 ✗ if (n < mov->ism_lookahead) {
5872 ✗ int free_size = 16 * (mov->ism_lookahead - n);
5873 ✗ avio_wb32(pb, free_size);
5874 ✗ ffio_wfourcc(pb, "free");
5875 ✗ ffio_fill(pb, 0, free_size - 8);
5876 }
5877
5878 ✗ return 0;
5879 }
5880
5881 380 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5882 MOVTrack *track)
5883 {
5884 380 int64_t pos = avio_tell(pb);
5885 int i;
5886
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
380 for (i = 0; i < mov->ism_lookahead; i++) {
5887 /* Update the tfrf tag for the last ism_lookahead fragments,
5888 * nb_frag_info - 1 is the next fragment to be written. */
5889 ✗ mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5890 }
5891 380 avio_seek(pb, pos, SEEK_SET);
5892 380 return 0;
5893 }
5894
5895 122 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5896 int size)
5897 {
5898 int i;
5899
2/2
✓ Branch 0 taken 423 times.
✓ Branch 1 taken 122 times.
545 for (i = 0; i < mov->nb_tracks; i++) {
5900 423 MOVTrack *track = &mov->tracks[i];
5901 MOVFragmentInfo *info;
5902
6/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 344 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 380 times.
423 if ((tracks >= 0 && i != tracks) || !track->entry)
5903 43 continue;
5904 380 track->nb_frag_info++;
5905
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 207 times.
380 if (track->nb_frag_info >= track->frag_info_capacity) {
5906 173 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5907
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if (av_reallocp_array(&track->frag_info,
5908 new_capacity,
5909 sizeof(*track->frag_info)))
5910 ✗ return AVERROR(ENOMEM);
5911 173 track->frag_info_capacity = new_capacity;
5912 }
5913 380 info = &track->frag_info[track->nb_frag_info - 1];
5914 380 info->offset = avio_tell(pb);
5915 380 info->size = size;
5916 // Try to recreate the original pts for the first packet
5917 // from the fields we have stored
5918 380 info->time = track->cluster[0].dts + track->cluster[0].cts;
5919 380 info->duration = track->end_pts -
5920 380 (track->cluster[0].dts + track->cluster[0].cts);
5921 // If the pts is less than zero, we will have trimmed
5922 // away parts of the media track using an edit list,
5923 // and the corresponding start presentation time is zero.
5924
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 372 times.
380 if (info->time < 0) {
5925 8 info->duration += info->time;
5926 8 info->time = 0;
5927 }
5928 380 info->tfrf_offset = 0;
5929 380 mov_write_tfrf_tags(pb, mov, track);
5930 }
5931 122 return 0;
5932 }
5933
5934 ✗ static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5935 {
5936 int i;
5937 ✗ for (i = 0; i < mov->nb_tracks; i++) {
5938 ✗ MOVTrack *track = &mov->tracks[i];
5939 ✗ if ((tracks >= 0 && i != tracks) || !track->entry)
5940 ✗ continue;
5941 ✗ if (track->nb_frag_info > max) {
5942 ✗ memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5943 ✗ track->nb_frag_info = max;
5944 }
5945 }
5946 ✗ }
5947
5948 680 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5949 {
5950 680 int64_t pos = avio_tell(pb);
5951
5952 680 avio_wb32(pb, 0); /* size */
5953 680 ffio_wfourcc(pb, "tfdt");
5954 680 avio_w8(pb, 1); /* version */
5955 680 avio_wb24(pb, 0);
5956 680 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5957 680 return update_size(pb, pos);
5958 }
5959
5960 762 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5961 MOVTrack *track, int64_t moof_offset,
5962 int moof_size)
5963 {
5964 762 int64_t pos = avio_tell(pb);
5965 762 int i, start = 0;
5966 762 avio_wb32(pb, 0); /* size placeholder */
5967 762 ffio_wfourcc(pb, "traf");
5968
5969 762 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5970
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 82 times.
762 if (mov->mode != MODE_ISM)
5971 680 mov_write_tfdt_tag(pb, track);
5972
2/2
✓ Branch 0 taken 17598 times.
✓ Branch 1 taken 762 times.
18360 for (i = 1; i < track->entry; i++) {
5973
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17596 times.
17598 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5974 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5975 2 start = i;
5976 }
5977 }
5978 762 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5979
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 680 times.
762 if (mov->mode == MODE_ISM) {
5980 82 mov_write_tfxd_tag(pb, track);
5981
5982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5983 ✗ int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5984
5985 ✗ if (track->nb_frag_info > 0) {
5986 ✗ MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5987 ✗ if (!info->tfrf_offset)
5988 ✗ info->tfrf_offset = avio_tell(pb);
5989 }
5990 ✗ avio_wb32(pb, 8 + size);
5991 ✗ ffio_wfourcc(pb, "free");
5992 ✗ ffio_fill(pb, 0, size);
5993 }
5994 }
5995
5996
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
762 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5997 ✗ ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5998
5999 762 return update_size(pb, pos);
6000 }
6001
6002 246 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
6003 int tracks, int moof_size)
6004 {
6005 246 int64_t pos = avio_tell(pb);
6006 int i;
6007
6008 246 avio_wb32(pb, 0); /* size placeholder */
6009 246 ffio_wfourcc(pb, "moof");
6010 246 mov->first_trun = 1;
6011
6012 246 mov_write_mfhd_tag(pb, mov);
6013
2/2
✓ Branch 0 taken 848 times.
✓ Branch 1 taken 246 times.
1094 for (i = 0; i < mov->nb_tracks; i++) {
6014 848 MOVTrack *track = &mov->tracks[i];
6015
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 690 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 82 times.
848 if (tracks >= 0 && i != tracks)
6016 76 continue;
6017
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 762 times.
772 if (!track->entry)
6018 10 continue;
6019
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
762 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
6020 ✗ mov_write_pssh_tag(pb, track->st);
6021 762 mov_write_traf_tag(pb, mov, track, pos, moof_size);
6022 }
6023
6024 246 return update_size(pb, pos);
6025 }
6026
6027 478 static int mov_write_sidx_tag(AVIOContext *pb,
6028 MOVTrack *track, int ref_size, int total_sidx_size)
6029 {
6030 478 int64_t pos = avio_tell(pb), offset_pos, end_pos;
6031 int64_t presentation_time, duration, offset;
6032 unsigned starts_with_SAP;
6033 int i, entries;
6034
6035
1/2
✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
478 if (track->entry) {
6036 478 entries = 1;
6037 478 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
6038 478 duration = track->end_pts -
6039 478 (track->cluster[0].dts + track->cluster[0].cts);
6040 478 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6041
6042 // pts<0 should be cut away using edts
6043
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 472 times.
478 if (presentation_time < 0) {
6044 6 duration += presentation_time;
6045 6 presentation_time = 0;
6046 }
6047 } else {
6048 ✗ entries = track->nb_frag_info;
6049 ✗ if (entries <= 0)
6050 ✗ return 0;
6051 ✗ presentation_time = track->frag_info[0].time;
6052 }
6053
6054 478 avio_wb32(pb, 0); /* size */
6055 478 ffio_wfourcc(pb, "sidx");
6056 478 avio_w8(pb, 1); /* version */
6057 478 avio_wb24(pb, 0);
6058 478 avio_wb32(pb, track->track_id); /* reference_ID */
6059 478 avio_wb32(pb, track->timescale); /* timescale */
6060 478 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
6061 478 offset_pos = avio_tell(pb);
6062 478 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
6063 478 avio_wb16(pb, 0); /* reserved */
6064
6065 478 avio_wb16(pb, entries); /* reference_count */
6066
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 478 times.
956 for (i = 0; i < entries; i++) {
6067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
478 if (!track->entry) {
6068 ✗ if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
6069 ✗ av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
6070 }
6071 ✗ duration = track->frag_info[i].duration;
6072 ✗ ref_size = track->frag_info[i].size;
6073 ✗ starts_with_SAP = 1;
6074 }
6075 478 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
6076 478 avio_wb32(pb, duration); /* subsegment_duration */
6077 478 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
6078 }
6079
6080 478 end_pos = avio_tell(pb);
6081 478 offset = pos + total_sidx_size - end_pos;
6082 478 avio_seek(pb, offset_pos, SEEK_SET);
6083 478 avio_wb64(pb, offset);
6084 478 avio_seek(pb, end_pos, SEEK_SET);
6085 478 return update_size(pb, pos);
6086 }
6087
6088 26 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
6089 int tracks, int ref_size)
6090 {
6091 int i, round, ret;
6092 AVIOContext *avio_buf;
6093 26 int total_size = 0;
6094
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 26 times.
78 for (round = 0; round < 2; round++) {
6095 // First run one round to calculate the total size of all
6096 // sidx atoms.
6097 // This would be much simpler if we'd only write one sidx
6098 // atom, for the first track in the moof.
6099
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (round == 0) {
6100
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6101 ✗ return ret;
6102 } else {
6103 26 avio_buf = pb;
6104 }
6105
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 52 times.
530 for (i = 0; i < mov->nb_tracks; i++) {
6106 478 MOVTrack *track = &mov->tracks[i];
6107
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
478 if (tracks >= 0 && i != tracks)
6108 ✗ continue;
6109 // When writing a sidx for the full file, entry is 0, but
6110 // we want to include all tracks. ref_size is 0 in this case,
6111 // since we read it from frag_info instead.
6112
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
478 if (!track->entry && ref_size > 0)
6113 ✗ continue;
6114 478 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
6115 total_size);
6116 }
6117
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (round == 0) {
6118 26 total_size = ffio_close_null_buf(avio_buf);
6119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (total_size < 0)
6120 ✗ return total_size;
6121 }
6122 }
6123 26 return 0;
6124 }
6125
6126 ✗ static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
6127 {
6128 ✗ int64_t pos = avio_tell(pb), pts_us, ntp_ts;
6129 MOVTrack *first_track;
6130 ✗ int flags = 24;
6131
6132 /* PRFT should be associated with at most one track. So, choosing only the
6133 * first track. */
6134 ✗ if (tracks > 0)
6135 ✗ return 0;
6136 ✗ first_track = &(mov->tracks[0]);
6137
6138 ✗ if (!first_track->entry) {
6139 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
6140 ✗ return 0;
6141 }
6142
6143 ✗ if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
6144 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
6145 ✗ return 0;
6146 }
6147
6148 ✗ if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
6149 ✗ if (first_track->cluster[0].prft.wallclock) {
6150 /* Round the NTP time to whole milliseconds. */
6151 ✗ ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
6152 NTP_OFFSET_US);
6153 ✗ flags = first_track->cluster[0].prft.flags;
6154 } else
6155 ✗ ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
6156 ✗ } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
6157 ✗ pts_us = av_rescale_q(first_track->cluster[0].pts,
6158 ✗ first_track->st->time_base, AV_TIME_BASE_Q);
6159 ✗ ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
6160 } else {
6161 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
6162 ✗ mov->write_prft);
6163 ✗ return 0;
6164 }
6165
6166 ✗ avio_wb32(pb, 0); // Size place holder
6167 ✗ ffio_wfourcc(pb, "prft"); // Type
6168 ✗ avio_w8(pb, 1); // Version
6169 ✗ avio_wb24(pb, flags); // Flags
6170 ✗ avio_wb32(pb, first_track->track_id); // reference track ID
6171 ✗ avio_wb64(pb, ntp_ts); // NTP time stamp
6172 ✗ avio_wb64(pb, first_track->cluster[0].pts); //media time
6173 ✗ return update_size(pb, pos);
6174 }
6175
6176 123 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
6177 int64_t mdat_size)
6178 {
6179 AVIOContext *avio_buf;
6180 int ret, moof_size;
6181
6182
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
123 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6183 ✗ return ret;
6184 123 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
6185 123 moof_size = ffio_close_null_buf(avio_buf);
6186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 if (moof_size < 0)
6187 ✗ return moof_size;
6188
6189
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 96 times.
123 if (mov->flags & FF_MOV_FLAG_DASH &&
6190
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 times.
27 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
6191 26 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
6192
6193
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
123 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
6194 ✗ mov_write_prft_tag(pb, mov, tracks);
6195
6196
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
6197
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 122 times.
123 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
6198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->ism_lookahead) {
6199
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
122 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
6200 ✗ return ret;
6201
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
6202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
6203 ✗ mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
6204 }
6205 }
6206
6207 123 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
6208 }
6209
6210 169 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
6211 {
6212 169 int64_t pos = avio_tell(pb);
6213 int i;
6214
6215 169 avio_wb32(pb, 0); /* size placeholder */
6216 169 ffio_wfourcc(pb, "tfra");
6217 169 avio_w8(pb, 1); /* version */
6218 169 avio_wb24(pb, 0);
6219
6220 169 avio_wb32(pb, track->track_id);
6221 169 avio_wb32(pb, 0); /* length of traf/trun/sample num */
6222 169 avio_wb32(pb, track->nb_frag_info);
6223
2/2
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 169 times.
543 for (i = 0; i < track->nb_frag_info; i++) {
6224 374 avio_wb64(pb, track->frag_info[i].time);
6225 374 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
6226 374 avio_w8(pb, 1); /* traf number */
6227 374 avio_w8(pb, 1); /* trun number */
6228 374 avio_w8(pb, 1); /* sample number */
6229 }
6230
6231 169 return update_size(pb, pos);
6232 }
6233
6234 41 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
6235 {
6236 AVIOContext *mfra_pb;
6237 int i, ret, sz;
6238 uint8_t *buf;
6239
6240 41 ret = avio_open_dyn_buf(&mfra_pb);
6241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (ret < 0)
6242 ✗ return ret;
6243
6244 41 avio_wb32(mfra_pb, 0); /* size placeholder */
6245 41 ffio_wfourcc(mfra_pb, "mfra");
6246 /* An empty mfra atom is enough to indicate to the publishing point that
6247 * the stream has ended. */
6248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (mov->flags & FF_MOV_FLAG_ISML)
6249 ✗ goto done_mfra;
6250
6251
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 41 times.
214 for (i = 0; i < mov->nb_tracks; i++) {
6252 173 MOVTrack *track = &mov->tracks[i];
6253
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 4 times.
173 if (track->nb_frag_info)
6254 169 mov_write_tfra_tag(mfra_pb, track);
6255 }
6256
6257 41 avio_wb32(mfra_pb, 16);
6258 41 ffio_wfourcc(mfra_pb, "mfro");
6259 41 avio_wb32(mfra_pb, 0); /* version + flags */
6260 41 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
6261
6262 41 done_mfra:
6263
6264 41 sz = update_size(mfra_pb, 0);
6265 41 ret = avio_get_dyn_buf(mfra_pb, &buf);
6266 41 avio_write(pb, buf, ret);
6267 41 ffio_free_dyn_buf(&mfra_pb);
6268
6269 41 return sz;
6270 }
6271
6272 208 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
6273 {
6274 208 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
6275
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 58 times.
208 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
6276
6277 208 mov->mdat_pos = avio_tell(pb);
6278 208 avio_wb32(pb, 0); /* size placeholder*/
6279 208 ffio_wfourcc(pb, "mdat");
6280 208 return 0;
6281 }
6282
6283 508 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
6284 int has_h264, int has_video, int write_minor)
6285 {
6286 508 MOVMuxContext *mov = s->priv_data;
6287 508 int minor = 0x200;
6288
6289
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 508 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
508 if (mov->major_brand && strlen(mov->major_brand) >= 4)
6290 ✗ ffio_wfourcc(pb, mov->major_brand);
6291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 508 times.
508 else if (mov->mode == MODE_3GP) {
6292 ✗ ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
6293 ✗ minor = has_h264 ? 0x100 : 0x200;
6294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 508 times.
508 } else if (mov->mode == MODE_AVIF) {
6295 ✗ ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
6296 ✗ minor = 0;
6297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 508 times.
508 } else if (mov->mode & MODE_3G2) {
6298 ✗ ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
6299 ✗ minor = has_h264 ? 0x20000 : 0x10000;
6300
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 506 times.
508 } else if (mov->mode == MODE_PSP)
6301 2 ffio_wfourcc(pb, "MSNV");
6302
4/4
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 112 times.
506 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
6303
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 70 times.
78 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6304 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
6305
4/4
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 148 times.
498 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6306 34 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
6307
3/4
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
464 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6308 ✗ ffio_wfourcc(pb, "iso4");
6309
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 316 times.
464 else if (mov->mode == MODE_MP4)
6310 148 ffio_wfourcc(pb, "isom");
6311
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 314 times.
316 else if (mov->mode == MODE_IPOD)
6312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6313
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 304 times.
314 else if (mov->mode == MODE_ISM)
6314 10 ffio_wfourcc(pb, "isml");
6315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 304 times.
304 else if (mov->mode == MODE_F4V)
6316 ✗ ffio_wfourcc(pb, "f4v ");
6317 else
6318 304 ffio_wfourcc(pb, "qt ");
6319
6320
2/2
✓ Branch 0 taken 254 times.
✓ Branch 1 taken 254 times.
508 if (write_minor)
6321 254 avio_wb32(pb, minor);
6322 508 }
6323
6324 254 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6325 {
6326 254 MOVMuxContext *mov = s->priv_data;
6327 254 int64_t pos = avio_tell(pb);
6328 254 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6329 254 int has_iamf = 0;
6330
6331 #if CONFIG_IAMFENC
6332
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 249 times.
254 for (int i = 0; i < s->nb_stream_groups; i++) {
6333 5 const AVStreamGroup *stg = s->stream_groups[i];
6334
6335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6336 ✗ stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6337 5 has_iamf = 1;
6338 5 break;
6339 }
6340 }
6341 #endif
6342
2/2
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 254 times.
671 for (int i = 0; i < mov->nb_streams; i++) {
6343 417 AVStream *st = mov->tracks[i].st;
6344
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 415 times.
417 if (is_cover_image(st))
6345 2 continue;
6346
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 211 times.
415 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6347 204 has_video = 1;
6348
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 377 times.
415 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6349 38 has_h264 = 1;
6350
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 413 times.
415 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6351 2 has_av1 = 1;
6352
2/2
✓ Branch 0 taken 409 times.
✓ Branch 1 taken 6 times.
415 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6353
2/2
✓ Branch 0 taken 405 times.
✓ Branch 1 taken 4 times.
409 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6354
3/4
✓ Branch 0 taken 405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 403 times.
810 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6355 405 av_packet_side_data_get(st->codecpar->coded_side_data,
6356 405 st->codecpar->nb_coded_side_data,
6357 AV_PKT_DATA_DOVI_CONF))
6358 12 has_dolby = 1;
6359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 415 times.
415 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6360 ✗ has_id3 = 1;
6361 }
6362
6363 254 avio_wb32(pb, 0); /* size */
6364 254 ffio_wfourcc(pb, "ftyp");
6365
6366 // Write major brand
6367 254 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6368 // Write the major brand as the first compatible brand as well
6369 254 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6370
6371 // Write compatible brands, ensuring that we don't write the major brand as a
6372 // compatible brand a second time.
6373
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 249 times.
254 if (mov->mode == MODE_ISM) {
6374 5 ffio_wfourcc(pb, "piff");
6375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 } else if (mov->mode == MODE_AVIF) {
6376 const AVPixFmtDescriptor *pix_fmt_desc =
6377 ✗ av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6378 ✗ const int depth = pix_fmt_desc->comp[0].depth;
6379 ✗ if (mov->is_animated_avif) {
6380 // For animated AVIF, major brand is "avis". Add "avif" as a
6381 // compatible brand.
6382 ✗ ffio_wfourcc(pb, "avif");
6383 ✗ ffio_wfourcc(pb, "msf1");
6384 ✗ ffio_wfourcc(pb, "iso8");
6385 }
6386 ✗ ffio_wfourcc(pb, "mif1");
6387 ✗ ffio_wfourcc(pb, "miaf");
6388 ✗ if (depth == 8 || depth == 10) {
6389 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6390 // computing that is based on chroma subsampling type. 420 chroma
6391 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6392 ✗ if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6393 // 444 chroma subsampling.
6394 ✗ ffio_wfourcc(pb, "MA1A");
6395 } else {
6396 // 420 chroma subsampling.
6397 ✗ ffio_wfourcc(pb, "MA1B");
6398 }
6399 }
6400
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 152 times.
249 } else if (mov->mode != MODE_MOV) {
6401 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6402 // brand, if not already the major brand. This is compatible with users that
6403 // don't understand tfdt.
6404
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 2 times.
97 if (mov->mode == MODE_MP4) {
6405
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 93 times.
95 if (mov->flags & FF_MOV_FLAG_CMAF)
6406 2 ffio_wfourcc(pb, "cmfc");
6407
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 4 times.
95 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6408 35 ffio_wfourcc(pb, "iso6");
6409
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 93 times.
95 if (has_av1)
6410 2 ffio_wfourcc(pb, "av01");
6411
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 84 times.
95 if (has_dolby)
6412 11 ffio_wfourcc(pb, "dby1");
6413
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 90 times.
95 if (has_iamf)
6414 5 ffio_wfourcc(pb, "iamf");
6415 } else {
6416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6417 ✗ ffio_wfourcc(pb, "iso6");
6418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6419 ✗ ffio_wfourcc(pb, "iso5");
6420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6421 ✗ ffio_wfourcc(pb, "iso4");
6422 }
6423 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6424
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 19 times.
97 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6425 // write isom for mp4 only if it it's not the major brand already.
6426
4/4
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 74 times.
78 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6427 4 ffio_wfourcc(pb, "isom");
6428 78 ffio_wfourcc(pb, "iso2");
6429
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 54 times.
78 if (has_h264)
6430 24 ffio_wfourcc(pb, "avc1");
6431 }
6432 }
6433
6434
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 159 times.
254 if (mov->mode == MODE_MP4)
6435 95 ffio_wfourcc(pb, "mp41");
6436
6437
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
254 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6438 ✗ ffio_wfourcc(pb, "dash");
6439
6440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 254 times.
254 if (has_id3)
6441 ✗ ffio_wfourcc(pb, "aid3");
6442
6443 254 return update_size(pb, pos);
6444 }
6445
6446 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6447 {
6448 1 AVStream *video_st = s->streams[0];
6449 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6450 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6451 1 int audio_rate = audio_par->sample_rate;
6452 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6453
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 :
6454 0;
6455 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6456 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6457
6458
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) {
6459 ✗ av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6460 ✗ return AVERROR(EINVAL);
6461 }
6462
6463 1 avio_wb32(pb, 0x94); /* size */
6464 1 ffio_wfourcc(pb, "uuid");
6465 1 ffio_wfourcc(pb, "PROF");
6466
6467 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6468 1 avio_wb32(pb, 0xbb88695c);
6469 1 avio_wb32(pb, 0xfac9c740);
6470
6471 1 avio_wb32(pb, 0x0); /* ? */
6472 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6473
6474 1 avio_wb32(pb, 0x14); /* size */
6475 1 ffio_wfourcc(pb, "FPRF");
6476 1 avio_wb32(pb, 0x0); /* ? */
6477 1 avio_wb32(pb, 0x0); /* ? */
6478 1 avio_wb32(pb, 0x0); /* ? */
6479
6480 1 avio_wb32(pb, 0x2c); /* size */
6481 1 ffio_wfourcc(pb, "APRF"); /* audio */
6482 1 avio_wb32(pb, 0x0);
6483 1 avio_wb32(pb, 0x2); /* TrackID */
6484 1 ffio_wfourcc(pb, "mp4a");
6485 1 avio_wb32(pb, 0x20f);
6486 1 avio_wb32(pb, 0x0);
6487 1 avio_wb32(pb, audio_kbitrate);
6488 1 avio_wb32(pb, audio_kbitrate);
6489 1 avio_wb32(pb, audio_rate);
6490 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6491
6492 1 avio_wb32(pb, 0x34); /* size */
6493 1 ffio_wfourcc(pb, "VPRF"); /* video */
6494 1 avio_wb32(pb, 0x0);
6495 1 avio_wb32(pb, 0x1); /* TrackID */
6496
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6497 1 ffio_wfourcc(pb, "avc1");
6498 1 avio_wb16(pb, 0x014D);
6499 1 avio_wb16(pb, 0x0015);
6500 } else {
6501 ✗ ffio_wfourcc(pb, "mp4v");
6502 ✗ avio_wb16(pb, 0x0000);
6503 ✗ avio_wb16(pb, 0x0103);
6504 }
6505 1 avio_wb32(pb, 0x0);
6506 1 avio_wb32(pb, video_kbitrate);
6507 1 avio_wb32(pb, video_kbitrate);
6508 1 avio_wb32(pb, frame_rate);
6509 1 avio_wb32(pb, frame_rate);
6510 1 avio_wb16(pb, video_par->width);
6511 1 avio_wb16(pb, video_par->height);
6512 1 avio_wb32(pb, 0x010001); /* ? */
6513
6514 1 return 0;
6515 }
6516
6517 254 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6518 {
6519 254 MOVMuxContext *mov = s->priv_data;
6520 int i;
6521
6522 254 mov_write_ftyp_tag(pb,s);
6523
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 253 times.
254 if (mov->mode == MODE_PSP) {
6524 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6525
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6526 2 AVStream *st = mov->tracks[i].st;
6527
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6528 ✗ continue;
6529
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6530 1 video_streams_nb++;
6531
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6532 1 audio_streams_nb++;
6533 else
6534 ✗ other_streams_nb++;
6535 }
6536
6537
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) {
6538 ✗ av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6539 ✗ return AVERROR(EINVAL);
6540 }
6541 1 return mov_write_uuidprof_tag(pb, s);
6542 }
6543 253 return 0;
6544 }
6545
6546 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6547 {
6548 8 uint32_t c = -1;
6549 8 int i, closed_gop = 0;
6550
6551
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6552 368 c = (c << 8) + pkt->data[i];
6553
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6554 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6555
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6556 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6557
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
6558 8 *flags = MOV_SYNC_SAMPLE;
6559 else
6560 ✗ *flags = MOV_PARTIAL_SYNC_SAMPLE;
6561 8 break;
6562 }
6563 }
6564 8 return 0;
6565 }
6566
6567 ✗ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6568 {
6569 ✗ const uint8_t *start, *next, *end = pkt->data + pkt->size;
6570 ✗ int seq = 0, entry = 0;
6571 ✗ int key = pkt->flags & AV_PKT_FLAG_KEY;
6572 ✗ start = find_next_marker(pkt->data, end);
6573 ✗ for (next = start; next < end; start = next) {
6574 ✗ next = find_next_marker(start + 4, end);
6575 ✗ switch (AV_RB32(start)) {
6576 ✗ case VC1_CODE_SEQHDR:
6577 ✗ seq = 1;
6578 ✗ break;
6579 ✗ case VC1_CODE_ENTRYPOINT:
6580 ✗ entry = 1;
6581 ✗ break;
6582 ✗ case VC1_CODE_SLICE:
6583 ✗ trk->vc1_info.slices = 1;
6584 ✗ break;
6585 }
6586 }
6587 ✗ if (!trk->entry && trk->vc1_info.first_packet_seen)
6588 ✗ trk->vc1_info.first_frag_written = 1;
6589 ✗ if (!trk->entry && !trk->vc1_info.first_frag_written) {
6590 /* First packet in first fragment */
6591 ✗ trk->vc1_info.first_packet_seq = seq;
6592 ✗ trk->vc1_info.first_packet_entry = entry;
6593 ✗ trk->vc1_info.first_packet_seen = 1;
6594 ✗ } else if ((seq && !trk->vc1_info.packet_seq) ||
6595 ✗ (entry && !trk->vc1_info.packet_entry)) {
6596 int i;
6597 ✗ for (i = 0; i < trk->entry; i++)
6598 ✗ trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6599 ✗ trk->has_keyframes = 0;
6600 ✗ if (seq)
6601 ✗ trk->vc1_info.packet_seq = 1;
6602 ✗ if (entry)
6603 ✗ trk->vc1_info.packet_entry = 1;
6604 ✗ if (!trk->vc1_info.first_frag_written) {
6605 /* First fragment */
6606 ✗ if ((!seq || trk->vc1_info.first_packet_seq) &&
6607 ✗ (!entry || trk->vc1_info.first_packet_entry)) {
6608 /* First packet had the same headers as this one, readd the
6609 * sync sample flag. */
6610 ✗ trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6611 ✗ trk->has_keyframes = 1;
6612 }
6613 }
6614 }
6615 ✗ if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6616 ✗ key = seq && entry;
6617 ✗ else if (trk->vc1_info.packet_seq)
6618 ✗ key = seq;
6619 ✗ else if (trk->vc1_info.packet_entry)
6620 ✗ key = entry;
6621 ✗ if (key) {
6622 ✗ trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6623 ✗ trk->has_keyframes++;
6624 }
6625 ✗ }
6626
6627 ✗ static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6628 {
6629 int length;
6630
6631 ✗ if (pkt->size < 8)
6632 ✗ return;
6633
6634 ✗ length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6635 ✗ if (length < 8 || length > pkt->size)
6636 ✗ return;
6637
6638 ✗ if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6639 ✗ trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6640 ✗ trk->has_keyframes++;
6641 }
6642
6643 ✗ return;
6644 }
6645
6646 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6647 {
6648 89 MOVMuxContext *mov = s->priv_data;
6649 int ret, buf_size;
6650 uint8_t *buf;
6651 int i, offset;
6652
6653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if (!track->mdat_buf)
6654 ✗ return 0;
6655
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!mov->mdat_buf) {
6656
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6657 ✗ return ret;
6658 }
6659 89 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6660
6661 89 offset = avio_tell(mov->mdat_buf);
6662 89 avio_write(mov->mdat_buf, buf, buf_size);
6663 89 ffio_reset_dyn_buf(track->mdat_buf);
6664
6665
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 89 times.
177 for (i = track->entries_flushed; i < track->entry; i++)
6666 88 track->cluster[i].pos += offset;
6667 89 track->entries_flushed = track->entry;
6668 89 return 0;
6669 }
6670
6671 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6672 {
6673 28 MOVMuxContext *mov = s->priv_data;
6674 28 AVPacket *squashed_packet = mov->pkt;
6675 28 int ret = AVERROR_BUG;
6676
6677
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6678 28 case AV_CODEC_ID_TTML: {
6679 28 int had_packets = !!track->squashed_packet_queue.head;
6680
6681
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) {
6682 ✗ goto finish_squash;
6683 }
6684
6685 // We have generated a padding packet (no actual input packets in
6686 // queue) and its duration is zero. Skipping writing it.
6687
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) {
6688 ✗ goto finish_squash;
6689 }
6690
6691 28 track->end_reliable = 1;
6692 28 break;
6693 }
6694 ✗ default:
6695 ✗ ret = AVERROR(EINVAL);
6696 ✗ goto finish_squash;
6697 }
6698
6699 28 squashed_packet->stream_index = track->st->index;
6700
6701 28 ret = mov_write_single_packet(s, squashed_packet);
6702
6703 28 finish_squash:
6704 28 av_packet_unref(squashed_packet);
6705
6706 28 return ret;
6707 }
6708
6709 409 static int mov_write_squashed_packets(AVFormatContext *s)
6710 {
6711 409 MOVMuxContext *mov = s->priv_data;
6712
6713
2/2
✓ Branch 0 taken 1081 times.
✓ Branch 1 taken 409 times.
1490 for (int i = 0; i < mov->nb_streams; i++) {
6714 1081 MOVTrack *track = &mov->tracks[i];
6715 1081 int ret = AVERROR_BUG;
6716
6717
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1051 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
1081 if (track->squash_fragment_samples_to_one && !track->entry) {
6718
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6719 ✗ av_log(s, AV_LOG_ERROR,
6720 "Failed to write squashed packet for %s stream with "
6721 "index %d and track id %d. Error: %s\n",
6722 ✗ avcodec_get_name(track->st->codecpar->codec_id),
6723 ✗ track->st->index, track->track_id,
6724 ✗ av_err2str(ret));
6725 ✗ return ret;
6726 }
6727 }
6728 }
6729
6730 409 return 0;
6731 }
6732
6733 391 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6734 int64_t ref_pos)
6735 {
6736 int i;
6737
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 389 times.
391 if (!track->entry)
6738 2 return 0;
6739
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 381 times.
389 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6740
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6741 124 track->cluster[i].pos += ref_pos + track->data_offset;
6742
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6743 // First flush. Chunking for this fragment may already have been
6744 // done, either if we didn't use empty_moov, or if we did use
6745 // delay_moov. In either case, reset chunking here.
6746
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6747 63 track->cluster[i].chunkNum = 0;
6748 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6749 }
6750 }
6751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6752 8 track->entry_written + track->entry,
6753 sizeof(*track->cluster)))
6754 ✗ return AVERROR(ENOMEM);
6755 8 memcpy(&track->cluster_written[track->entry_written],
6756 8 track->cluster, track->entry * sizeof(*track->cluster));
6757 8 track->entry_written += track->entry;
6758 }
6759 389 track->entry = 0;
6760 389 track->entries_flushed = 0;
6761 389 track->end_reliable = 0;
6762 389 return 0;
6763 }
6764
6765 157 static int mov_flush_fragment(AVFormatContext *s, int force)
6766 {
6767 157 MOVMuxContext *mov = s->priv_data;
6768 157 int i, first_track = -1;
6769 157 int64_t mdat_size = 0, mdat_start = 0;
6770 int ret;
6771 157 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6772
6773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
157 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6774 ✗ return 0;
6775
6776 // Check if we have any tracks that require squashing.
6777 // In that case, we'll have to write the packet here.
6778
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 157 times.
157 if ((ret = mov_write_squashed_packets(s)) < 0)
6779 ✗ return ret;
6780
6781 // Try to fill in the duration of the last packet in each stream
6782 // from queued packets in the interleave queues. If the flushing
6783 // of fragments was triggered automatically by an AVPacket, we
6784 // already have reliable info for the end of that track, but other
6785 // tracks may need to be filled in.
6786
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 157 times.
825 for (i = 0; i < mov->nb_streams; i++) {
6787 668 MOVTrack *track = &mov->tracks[i];
6788
2/2
✓ Branch 0 taken 577 times.
✓ Branch 1 taken 91 times.
668 if (!track->end_reliable) {
6789 577 const AVPacket *pkt = ff_interleaved_peek(s, i);
6790
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 571 times.
577 if (pkt) {
6791 int64_t offset, dts, pts;
6792 6 ff_get_muxer_ts_offset(s, i, &offset);
6793 6 pts = pkt->pts + offset;
6794 6 dts = pkt->dts + offset;
6795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6796 ✗ dts += track->dts_shift;
6797 6 track->track_duration = dts - track->start_dts;
6798
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6799 6 track->end_pts = pts;
6800 else
6801 ✗ track->end_pts = dts;
6802
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
6803 6 track->elst_end_pts = track->end_pts;
6804 }
6805 }
6806 }
6807
6808
2/2
✓ Branch 0 taken 674 times.
✓ Branch 1 taken 157 times.
831 for (i = 0; i < mov->nb_tracks; i++) {
6809 674 MOVTrack *track = &mov->tracks[i];
6810
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 487 times.
674 if (track->entry <= 1)
6811 187 continue;
6812 // Sample durations are calculated as the diff of dts values,
6813 // but for the last sample in a fragment, we don't know the dts
6814 // of the first sample in the next fragment, so we have to rely
6815 // on what was set as duration in the AVPacket. Not all callers
6816 // set this though, so we might want to replace it with an
6817 // estimate if it currently is zero.
6818
2/2
✓ Branch 1 taken 485 times.
✓ Branch 2 taken 2 times.
487 if (get_cluster_duration(track, track->entry - 1) != 0)
6819 485 continue;
6820 // Use the duration (i.e. dts diff) of the second last sample for
6821 // the last one. This is a wild guess (and fatal if it turns out
6822 // to be too long), but probably the best we can do - having a zero
6823 // duration is bad as well.
6824 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6825 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6826
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6827 2 av_log(s, AV_LOG_WARNING,
6828 "Estimating the duration of the last packet in a "
6829 "fragment, consider setting the duration field in "
6830 "AVPacket instead.\n");
6831 2 mov->missing_duration_warned = 1;
6832 }
6833 }
6834
6835
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 127 times.
157 if (!mov->moov_written) {
6836 30 int64_t pos = avio_tell(s->pb);
6837 uint8_t *buf;
6838 int buf_size, moov_size;
6839
6840
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 23 times.
174 for (i = 0; i < mov->nb_tracks; i++)
6841
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 144 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
151 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6842 7 break;
6843 /* Don't write the initial moov unless all tracks have data */
6844
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
30 if (i < mov->nb_tracks && !force)
6845 4 return 0;
6846
6847 26 moov_size = get_moov_size(s);
6848
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 26 times.
172 for (i = 0; i < mov->nb_tracks; i++)
6849 146 mov->tracks[i].data_offset = pos + moov_size + 8;
6850
6851 26 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6852
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 5 times.
26 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6853
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6854 21 mov_write_identification(s->pb, s);
6855
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6856 ✗ return ret;
6857
6858
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 5 times.
26 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6860 ✗ mov->reserved_header_pos = avio_tell(s->pb);
6861 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6862 21 mov->moov_written = 1;
6863 21 return 0;
6864 }
6865
6866
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (mov->mdat_buf) {
6867 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6868 4 avio_wb32(s->pb, buf_size + 8);
6869 4 ffio_wfourcc(s->pb, "mdat");
6870 4 avio_write(s->pb, buf, buf_size);
6871 4 ffio_reset_dyn_buf(mov->mdat_buf);
6872 }
6873
6874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6875 ✗ mov->reserved_header_pos = avio_tell(s->pb);
6876
6877 5 mov->moov_written = 1;
6878 5 mov->mdat_size = 0;
6879
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (i = 0; i < mov->nb_tracks; i++)
6880 10 mov_finish_fragment(mov, &mov->tracks[i], 0);
6881 5 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6882 5 return 0;
6883 }
6884
6885
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 125 times.
127 if (mov->frag_interleave) {
6886
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6887 4 MOVTrack *track = &mov->tracks[i];
6888 int ret;
6889
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6890 ✗ return ret;
6891 }
6892
6893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6894 ✗ return 0;
6895 2 mdat_size = avio_tell(mov->mdat_buf);
6896 }
6897
6898
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 127 times.
649 for (i = 0; i < mov->nb_tracks; i++) {
6899 522 MOVTrack *track = &mov->tracks[i];
6900
4/4
✓ Branch 0 taken 477 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 473 times.
522 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6901 49 track->data_offset = 0;
6902 else
6903 473 track->data_offset = mdat_size;
6904
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 410 times.
522 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6905 112 has_video = 1;
6906
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (first_video_track) {
6907
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 16 times.
112 if (track->entry)
6908 96 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6909 112 first_video_track = 0;
6910 }
6911 }
6912
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 381 times.
522 if (!track->entry)
6913 141 continue;
6914
1/2
✓ Branch 0 taken 381 times.
✗ Branch 1 not taken.
381 if (track->mdat_buf)
6915 381 mdat_size += avio_tell(track->mdat_buf);
6916
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 275 times.
381 if (first_track < 0)
6917 106 first_track = i;
6918 }
6919
6920
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 106 times.
127 if (!mdat_size)
6921 21 return 0;
6922
6923
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 4 times.
106 avio_write_marker(s->pb,
6924 106 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6925
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 9 times.
106 (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);
6926
6927
2/2
✓ Branch 0 taken 389 times.
✓ Branch 1 taken 106 times.
495 for (i = first_track; i < mov->nb_tracks; i++) {
6928 389 MOVTrack *track = &mov->tracks[i];
6929 389 int buf_size, write_moof = 1, moof_tracks = -1;
6930 uint8_t *buf;
6931
6932
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 381 times.
389 if (!track->entry)
6933 8 continue;
6934
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 340 times.
381 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6935 41 mdat_size = avio_tell(track->mdat_buf);
6936 41 moof_tracks = i;
6937 } else {
6938 340 write_moof = i == first_track;
6939 }
6940
6941
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 258 times.
381 if (write_moof) {
6942 123 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6943
6944 123 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6945 123 mov->fragments++;
6946
6947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 if (track->cenc.aes_ctr)
6948 ✗ ff_mov_cenc_flush(&track->cenc);
6949
6950 123 avio_wb32(s->pb, mdat_size + 8);
6951 123 ffio_wfourcc(s->pb, "mdat");
6952 123 mdat_start = avio_tell(s->pb);
6953 }
6954
6955 381 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6956
2/2
✓ Branch 0 taken 378 times.
✓ Branch 1 taken 3 times.
381 if (!mov->frag_interleave) {
6957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 378 times.
378 if (!track->mdat_buf)
6958 ✗ continue;
6959 378 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6960 378 avio_write(s->pb, buf, buf_size);
6961 378 ffio_reset_dyn_buf(track->mdat_buf);
6962 } else {
6963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!mov->mdat_buf)
6964 ✗ continue;
6965 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6966 3 avio_write(s->pb, buf, buf_size);
6967 3 ffio_reset_dyn_buf(mov->mdat_buf);
6968 }
6969 }
6970
6971 106 mov->mdat_size = 0;
6972
6973 106 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6974 106 return 0;
6975 }
6976
6977 100 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6978 {
6979 100 MOVMuxContext *mov = s->priv_data;
6980 100 int had_moov = mov->moov_written;
6981 100 int ret = mov_flush_fragment(s, force);
6982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (ret < 0)
6983 ✗ return ret;
6984 // If using delay_moov, the first flush only wrote the moov,
6985 // not the actual moof+mdat pair, thus flush once again.
6986
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
100 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6987 10 ret = mov_flush_fragment(s, force);
6988 100 return ret;
6989 }
6990
6991 53435 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6992 {
6993 int64_t ref;
6994 uint64_t duration;
6995
6996
2/2
✓ Branch 0 taken 52230 times.
✓ Branch 1 taken 1205 times.
53435 if (trk->entry) {
6997 52230 ref = trk->cluster[trk->entry - 1].dts;
6998
2/2
✓ Branch 0 taken 393 times.
✓ Branch 1 taken 812 times.
1205 } else if ( trk->start_dts != AV_NOPTS_VALUE
6999
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 8 times.
393 && !trk->frag_discont) {
7000 385 ref = trk->start_dts + trk->track_duration;
7001 } else
7002 820 ref = pkt->dts; // Skip tests for the first packet
7003
7004
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 49380 times.
53435 if (trk->dts_shift != AV_NOPTS_VALUE) {
7005 /* With negative CTS offsets we have set an offset to the DTS,
7006 * reverse this for the check. */
7007 4055 ref -= trk->dts_shift;
7008 }
7009
7010 53435 duration = pkt->dts - ref;
7011
2/4
✓ Branch 0 taken 53435 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53435 times.
53435 if (pkt->dts < ref || duration >= INT_MAX) {
7012 ✗ av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
7013 duration, pkt->dts, pkt->stream_index);
7014
7015 ✗ pkt->dts = ref + 1;
7016 ✗ pkt->pts = AV_NOPTS_VALUE;
7017 }
7018
7019
2/4
✓ Branch 0 taken 53435 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53435 times.
53435 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
7020 ✗ av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
7021 ✗ return AVERROR(EINVAL);
7022 }
7023 53435 return 0;
7024 }
7025
7026 7 int ff_mov_set_fragment_end_hint(AVFormatContext *s, int stream_index,
7027 const AVPacket *pkt, AVRational src_time_base)
7028 {
7029 7 MOVMuxContext *mov = s->priv_data;
7030 AVStream *st;
7031 MOVTrack *track;
7032 int64_t offset, dts, pts, candidate_duration;
7033
7034
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
7035
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 stream_index < 0 || stream_index >= s->nb_streams ||
7036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 pkt->dts == AV_NOPTS_VALUE)
7037 ✗ return 0;
7038
7039 7 st = s->streams[stream_index];
7040 7 track = st->priv_data;
7041
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!track->entry || track->start_dts == AV_NOPTS_VALUE)
7042 ✗ return 0;
7043
7044
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if (ff_get_muxer_ts_offset(s, stream_index, &offset) < 0)
7045 ✗ return 0;
7046
7047 7 dts = av_rescale_q(pkt->dts, src_time_base, st->time_base) + offset;
7048 14 pts = pkt->pts == AV_NOPTS_VALUE
7049 ? AV_NOPTS_VALUE
7050
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 : av_rescale_q(pkt->pts, src_time_base, st->time_base) + offset;
7051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (track->dts_shift != AV_NOPTS_VALUE)
7052 ✗ dts += track->dts_shift;
7053
7054 7 candidate_duration = dts - track->start_dts;
7055
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (dts <= track->cluster[track->entry - 1].dts ||
7056
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 candidate_duration < 0 || candidate_duration >= track->track_duration)
7057 7 return 0;
7058
7059 ✗ track->track_duration = candidate_duration;
7060 ✗ track->end_pts = pts != AV_NOPTS_VALUE ? pts : dts;
7061 ✗ if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7062 ✗ track->elst_end_pts = track->end_pts;
7063 ✗ track->end_reliable = 1;
7064
7065 ✗ return 1;
7066 }
7067
7068 26736 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7069 {
7070 26736 MOVMuxContext *mov = s->priv_data;
7071 26736 AVIOContext *pb = s->pb;
7072 MOVTrack *trk;
7073 AVCodecParameters *par;
7074 AVProducerReferenceTime *prft;
7075 26736 unsigned int samples_in_chunk = 0;
7076 int64_t duration;
7077 26736 int size = pkt->size, ret = 0, offset = 0;
7078 size_t prft_size;
7079 26736 uint8_t *reformatted_data = NULL;
7080
7081
2/2
✓ Branch 0 taken 26690 times.
✓ Branch 1 taken 46 times.
26736 if (pkt->stream_index < s->nb_streams)
7082 26690 trk = s->streams[pkt->stream_index]->priv_data;
7083 else // Timecode or chapter
7084 46 trk = &mov->tracks[pkt->stream_index];
7085 26736 par = trk->par;
7086
7087 26736 ret = check_pkt(s, trk, pkt);
7088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26736 times.
26736 if (ret < 0)
7089 ✗ return ret;
7090
7091
2/2
✓ Branch 0 taken 26115 times.
✓ Branch 1 taken 621 times.
26736 if (pkt->pts != AV_NOPTS_VALUE &&
7092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26115 times.
26115 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
7093 ✗ av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
7094 ✗ return AVERROR_PATCHWELCOME;
7095 }
7096
7097
3/4
✓ Branch 0 taken 17318 times.
✓ Branch 1 taken 9418 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17318 times.
26736 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
7098 int ret;
7099
4/4
✓ Branch 0 taken 3576 times.
✓ Branch 1 taken 5842 times.
✓ Branch 2 taken 3338 times.
✓ Branch 3 taken 238 times.
9418 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
7100
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 9092 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
9180 if (mov->frag_interleave && mov->fragments > 0) {
7101
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
7102
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
7103 ✗ return ret;
7104 }
7105 }
7106
7107
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 9006 times.
9180 if (!trk->mdat_buf) {
7108
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
7109 ✗ return ret;
7110 }
7111 9180 pb = trk->mdat_buf;
7112 } else {
7113
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
7114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
7115 ✗ return ret;
7116 }
7117 238 pb = mov->mdat_buf;
7118 }
7119 }
7120
7121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26736 times.
26736 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
7122 /* We must find out how many AMR blocks there are in one packet */
7123 static const uint16_t packed_size[16] =
7124 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
7125 ✗ int len = 0;
7126
7127 ✗ while (len < size && samples_in_chunk < 100) {
7128 ✗ len += packed_size[(pkt->data[len] >> 3) & 0x0F];
7129 ✗ samples_in_chunk++;
7130 }
7131 ✗ if (samples_in_chunk > 1) {
7132 ✗ av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
7133 ✗ return -1;
7134 }
7135
1/2
✓ Branch 0 taken 26736 times.
✗ Branch 1 not taken.
26736 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
7136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26736 times.
26736 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
7137 ✗ samples_in_chunk = trk->par->frame_size;
7138
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 25322 times.
26736 } else if (trk->sample_size)
7139 1414 samples_in_chunk = size / trk->sample_size;
7140 else
7141 25322 samples_in_chunk = 1;
7142
7143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26736 times.
26736 if (samples_in_chunk < 1) {
7144 ✗ av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
7145 ✗ return AVERROR_PATCHWELCOME;
7146 }
7147
7148 /* copy extradata if it exists */
7149
3/4
✓ Branch 0 taken 10213 times.
✓ Branch 1 taken 16523 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10213 times.
26736 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
7150 ✗ !TAG_IS_AVCI(trk->tag) &&
7151 ✗ (par->codec_id != AV_CODEC_ID_DNXHD)) {
7152 ✗ trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
7153 ✗ if (!trk->extradata[0]) {
7154 ✗ ret = AVERROR(ENOMEM);
7155 ✗ goto err;
7156 }
7157 ✗ trk->extradata_size[0] = par->extradata_size;
7158 }
7159
7160
2/2
✓ Branch 0 taken 26621 times.
✓ Branch 1 taken 115 times.
26736 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
7161
2/2
✓ Branch 0 taken 24007 times.
✓ Branch 1 taken 2614 times.
26621 par->codec_id == AV_CODEC_ID_H264 ||
7162
2/2
✓ Branch 0 taken 23635 times.
✓ Branch 1 taken 372 times.
24007 par->codec_id == AV_CODEC_ID_HEVC ||
7163
2/2
✓ Branch 0 taken 23625 times.
✓ Branch 1 taken 10 times.
23635 par->codec_id == AV_CODEC_ID_VVC ||
7164
1/2
✓ Branch 0 taken 23625 times.
✗ Branch 1 not taken.
23625 par->codec_id == AV_CODEC_ID_VP9 ||
7165
2/2
✓ Branch 0 taken 23325 times.
✓ Branch 1 taken 300 times.
23625 par->codec_id == AV_CODEC_ID_EVC ||
7166
1/2
✓ Branch 0 taken 23325 times.
✗ Branch 1 not taken.
23325 par->codec_id == AV_CODEC_ID_LCEVC ||
7167
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23325 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3387 times.
26736 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
7168
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)) {
7169 /* copy frame to create needed atoms */
7170 24 trk->extradata_size[0] = size;
7171 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
7172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
7173 ✗ ret = AVERROR(ENOMEM);
7174 ✗ goto err;
7175 }
7176 24 memcpy(trk->extradata[0], pkt->data, size);
7177 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7178 }
7179
7180 26736 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
7181
4/6
✓ Branch 0 taken 26736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 26733 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
26736 if (pkt->size && sd && sd->size > 0) {
7182 int i;
7183
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < trk->stsd_count; i++) {
7184
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
7185 1 break;
7186 }
7187
7188
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (i < trk->stsd_count)
7189 1 trk->last_stsd_index = i;
7190
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (trk->stsd_count <= INT_MAX - 1) {
7191 2 int new_count = trk->stsd_count + 1;
7192 2 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
7193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata)
7194 ✗ return AVERROR(ENOMEM);
7195 2 trk->extradata = extradata;
7196
7197 2 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
7198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata_size)
7199 ✗ return AVERROR(ENOMEM);
7200 2 trk->extradata_size = extradata_size;
7201
7202 2 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
7203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->extradata[trk->stsd_count])
7204 ✗ return AVERROR(ENOMEM);
7205
7206 2 trk->extradata_size[trk->stsd_count] = sd->size;
7207 2 trk->last_stsd_index = trk->stsd_count;
7208 2 trk->stsd_count = new_count;
7209 } else
7210 ✗ return AVERROR(ENOMEM);
7211 }
7212
7213
3/4
✓ Branch 0 taken 9008 times.
✓ Branch 1 taken 17728 times.
✓ Branch 2 taken 9008 times.
✗ Branch 3 not taken.
26736 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
7214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9008 times.
9008 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
7215 ✗ if (!trk->st->nb_frames) {
7216 ✗ av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
7217 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
7218 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
7219 ✗ return -1;
7220 }
7221 ✗ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
7222 }
7223
3/4
✓ Branch 0 taken 2614 times.
✓ Branch 1 taken 24122 times.
✓ Branch 2 taken 2614 times.
✗ Branch 3 not taken.
26736 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
7224
16/30
✓ Branch 0 taken 515 times.
✓ Branch 1 taken 2099 times.
✓ Branch 2 taken 515 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 515 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 515 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 515 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 515 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 515 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 515 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 515 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 515 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 515 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 515 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 515 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 515 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 515 times.
✗ Branch 29 not taken.
2614 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
7225 /* from x264 or from bytestream H.264 */
7226 /* NAL reformatting needed */
7227
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 515 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
515 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7228 ✗ ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
7229 &size);
7230 ✗ if (ret < 0)
7231 ✗ return ret;
7232 ✗ avio_write(pb, reformatted_data, size);
7233 } else {
7234
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 498 times.
515 if (trk->cenc.aes_ctr) {
7235 17 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (size < 0) {
7237 ✗ ret = size;
7238 ✗ goto err;
7239 }
7240 } else {
7241 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7242 }
7243 }
7244
3/4
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 25849 times.
✓ Branch 2 taken 372 times.
✗ Branch 3 not taken.
26221 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7245
3/4
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 355 times.
✓ Branch 3 taken 17 times.
727 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7246 /* extradata is Annex B, assume the bitstream is too and convert it */
7247 355 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
7248
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
355 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7249 ✗ ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
7250 &size, filter_ps, NULL);
7251 ✗ if (ret < 0)
7252 ✗ return ret;
7253 ✗ avio_write(pb, reformatted_data, size);
7254 } else {
7255
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 354 times.
355 if (trk->cenc.aes_ctr) {
7256 1 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (size < 0) {
7258 ✗ ret = size;
7259 ✗ goto err;
7260 }
7261 } else {
7262 354 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
7263 }
7264 }
7265
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 25856 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
25866 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7266
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7267 /* extradata is Annex B, assume the bitstream is too and convert it */
7268
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) {
7269 ✗ ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
7270 &size, 0, NULL);
7271 ✗ if (ret < 0)
7272 ✗ return ret;
7273 ✗ avio_write(pb, reformatted_data, size);
7274 } else {
7275 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
7276 }
7277
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25856 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
25856 } else if (par->codec_id == AV_CODEC_ID_LCEVC && trk->extradata_size[trk->last_stsd_index] > 0 &&
7278 ✗ *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1) {
7279 /* extradata is Annex B, assume the bitstream is too and convert it */
7280 ✗ if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7281 ✗ ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size);
7282 ✗ if (ret < 0)
7283 ✗ return ret;
7284 ✗ avio_write(pb, reformatted_data, size);
7285 } else {
7286 ✗ if (trk->cenc.aes_ctr) {
7287 ✗ size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7288 ✗ if (size < 0) {
7289 ✗ ret = size;
7290 ✗ goto err;
7291 }
7292 } else {
7293 ✗ size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7294 }
7295 }
7296
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 25828 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 24 times.
25856 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
7297
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) {
7298 ✗ ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
7299 &size, &offset);
7300 ✗ if (ret < 0)
7301 ✗ return ret;
7302 ✗ avio_write(pb, reformatted_data, size);
7303 } else {
7304 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
7305
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]) {
7306 ✗ mov->avif_extent_length[pkt->stream_index] = size;
7307 }
7308 }
7309
7310
2/2
✓ Branch 0 taken 25229 times.
✓ Branch 1 taken 623 times.
25852 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
7311
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 24115 times.
25229 par->codec_id == AV_CODEC_ID_EAC3) {
7312 1737 size = handle_eac3(mov, pkt, trk);
7313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (size < 0)
7314 ✗ return size;
7315
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1736 times.
1737 else if (!size)
7316 1 goto end;
7317 1736 avio_write(pb, pkt->data, size);
7318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24115 times.
24115 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
7319 ✗ size = 8;
7320
7321 ✗ for (int i = 0; i < pkt->size; i += 3) {
7322 ✗ if (pkt->data[i] == 0xFC) {
7323 ✗ size += 2;
7324 }
7325 }
7326 ✗ avio_wb32(pb, size);
7327 ✗ ffio_wfourcc(pb, "cdat");
7328 ✗ for (int i = 0; i < pkt->size; i += 3) {
7329 ✗ if (pkt->data[i] == 0xFC) {
7330 ✗ avio_w8(pb, pkt->data[i + 1]);
7331 ✗ avio_w8(pb, pkt->data[i + 2]);
7332 }
7333 }
7334
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24112 times.
24115 } else if (par->codec_id == AV_CODEC_ID_APV) {
7335 3 ff_isom_parse_apvc(trk->apv, pkt, s);
7336 3 avio_wb32(s->pb, pkt->size);
7337 3 size += 4;
7338
7339 3 avio_write(s->pb, pkt->data, pkt->size);
7340 } else {
7341
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 24079 times.
24112 if (trk->cenc.aes_ctr) {
7342 33 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
7343 33 int extradata_size = trk->extradata_size[trk->last_stsd_index];
7344
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
38 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
7345 5 int nal_size_length = (extradata[4] & 0x3) + 1;
7346 5 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7347
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
32 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
7348 4 int nal_size_length = (extradata[21] & 0x3) + 1;
7349 4 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 } else if(par->codec_id == AV_CODEC_ID_VVC) {
7351 ✗ ret = AVERROR_PATCHWELCOME;
7352
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if(par->codec_id == AV_CODEC_ID_AV1) {
7353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 av_assert0(size == pkt->size);
7354 24 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
7355
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (ret > 0) {
7356 24 size = ret;
7357 24 ret = 0;
7358 }
7359 } else {
7360 ✗ ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
7361 }
7362
7363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
7364 ✗ goto err;
7365 }
7366 } else {
7367 24079 avio_write(pb, pkt->data, size);
7368 }
7369 }
7370
7371
2/2
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 26318 times.
26735 if (trk->entry >= trk->cluster_capacity) {
7372 417 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
7373 417 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
7374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 417 times.
417 if (!cluster) {
7375 ✗ ret = AVERROR(ENOMEM);
7376 ✗ goto err;
7377 }
7378 417 trk->cluster = cluster;
7379 417 trk->cluster_capacity = new_capacity;
7380 }
7381
7382 26735 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7383 26735 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7384 26735 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7385 26735 trk->cluster[trk->entry].chunkNum = 0;
7386 26735 trk->cluster[trk->entry].size = size;
7387 26735 trk->cluster[trk->entry].entries = samples_in_chunk;
7388 26735 trk->cluster[trk->entry].dts = pkt->dts;
7389 26735 trk->cluster[trk->entry].pts = pkt->pts;
7390
2/2
✓ Branch 0 taken 26707 times.
✓ Branch 1 taken 28 times.
26735 if (!trk->squash_fragment_samples_to_one &&
7391
4/4
✓ Branch 0 taken 603 times.
✓ Branch 1 taken 26104 times.
✓ Branch 2 taken 204 times.
✓ Branch 3 taken 399 times.
26707 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7392
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 4 times.
204 if (!trk->frag_discont) {
7393 /* First packet of a new fragment. We already wrote the duration
7394 * of the last packet of the previous fragment based on track_duration,
7395 * which might not exactly match our dts. Therefore adjust the dts
7396 * of this packet to be what the previous packets duration implies. */
7397 200 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7398 /* We also may have written the pts and the corresponding duration
7399 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7400 * the next fragment. This means the cts of the first sample must
7401 * be the same in all fragments, unless end_pts was updated by
7402 * the packet causing the fragment to be written. */
7403
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 84 times.
200 if ((mov->flags & FF_MOV_FLAG_DASH &&
7404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
116 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7405
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 62 times.
84 mov->mode == MODE_ISM)
7406 138 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7407 } else {
7408 /* New fragment, but discontinuous from previous fragments.
7409 * Pretend the duration sum of the earlier fragments is
7410 * pkt->dts - trk->start_dts. */
7411 4 trk->end_pts = trk->elst_end_pts = AV_NOPTS_VALUE;
7412 4 trk->frag_discont = 0;
7413 }
7414 }
7415
7416
6/6
✓ Branch 0 taken 631 times.
✓ Branch 1 taken 26104 times.
✓ Branch 2 taken 403 times.
✓ Branch 3 taken 228 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 365 times.
26735 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7417
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 15 times.
38 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7418 /* Not using edit lists and shifting the first track to start from zero.
7419 * If the other streams start from a later timestamp, we won't be able
7420 * to signal the difference in starting time without an edit list.
7421 * Thus move the timestamp for this first sample to 0, increasing
7422 * its duration instead. */
7423 23 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7424 }
7425
2/2
✓ Branch 0 taken 380 times.
✓ Branch 1 taken 26355 times.
26735 if (trk->start_dts == AV_NOPTS_VALUE) {
7426 380 trk->start_dts = pkt->dts;
7427
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 374 times.
380 if (trk->frag_discont) {
7428
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7429 /* Pretend the whole stream started at pts=0, with earlier fragments
7430 * already written. If the stream started at pts=0, the duration sum
7431 * of earlier fragments would have been pkt->pts. */
7432 4 trk->start_dts = pkt->dts - pkt->pts;
7433 } else {
7434 /* Pretend the whole stream started at dts=0, with earlier fragments
7435 * already written, with a duration summing up to pkt->dts. */
7436 2 trk->start_dts = 0;
7437 }
7438 6 trk->frag_discont = 0;
7439
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 320 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 52 times.
374 } else if (pkt->dts && mov->moov_written)
7440 2 av_log(s, AV_LOG_WARNING,
7441 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7442 "already has been written. Set the delay_moov flag to handle "
7443 "this case.\n",
7444 pkt->stream_index, pkt->dts);
7445 }
7446
7447 26735 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
7448
5/6
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 26691 times.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 1 times.
26778 if (sd && sd->size >= 10 && trk->par->frame_size) {
7449
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 23 times.
43 duration = FFMAX(av_rescale_q(trk->par->frame_size, (AVRational){ 1, trk->par->sample_rate },
7450 trk->st->time_base), pkt->duration);
7451
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 if (mov->use_editlist)
7452 43 pkt->duration = duration;
7453 43 duration -= av_rescale_q(AV_RL32(sd->data + 4), (AVRational){ 1, trk->par->sample_rate },
7454 43 trk->st->time_base);
7455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 if (duration < 0)
7456 ✗ return AVERROR_INVALIDDATA;
7457 } else
7458 26692 duration = pkt->duration;
7459
7460 26735 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7461 26735 trk->last_sample_is_subtitle_end = 0;
7462
7463
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 26114 times.
26735 if (pkt->pts == AV_NOPTS_VALUE) {
7464 621 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7465 621 pkt->pts = pkt->dts;
7466 }
7467
2/2
✓ Branch 0 taken 1401 times.
✓ Branch 1 taken 25334 times.
26735 if (pkt->dts != pkt->pts)
7468 1401 trk->flags |= MOV_TRACK_CTTS;
7469 26735 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7470 26735 trk->cluster[trk->entry].flags = 0;
7471
6/6
✓ Branch 0 taken 26332 times.
✓ Branch 1 taken 403 times.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 26262 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 65 times.
26735 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7472 408 trk->start_cts = pkt->pts - pkt->dts;
7473
2/2
✓ Branch 0 taken 407 times.
✓ Branch 1 taken 26328 times.
26735 if (trk->end_pts == AV_NOPTS_VALUE)
7474 407 trk->end_pts = trk->cluster[trk->entry].dts +
7475 407 trk->cluster[trk->entry].cts + duration;
7476 else
7477 26328 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7478 trk->cluster[trk->entry].cts +
7479 duration);
7480
2/2
✓ Branch 0 taken 26732 times.
✓ Branch 1 taken 3 times.
26735 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7481 26732 trk->elst_end_pts = trk->end_pts;
7482
7483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26735 times.
26735 if (par->codec_id == AV_CODEC_ID_VC1) {
7484 ✗ mov_parse_vc1_frame(pkt, trk);
7485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26735 times.
26735 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7486 ✗ mov_parse_truehd_frame(pkt, trk);
7487
2/2
✓ Branch 0 taken 20675 times.
✓ Branch 1 taken 6060 times.
26735 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7488
4/4
✓ Branch 0 taken 6267 times.
✓ Branch 1 taken 14408 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6258 times.
20675 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7489
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7490 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7492 ✗ trk->flags |= MOV_TRACK_STPS;
7493 } else {
7494 20667 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7495 }
7496
1/2
✓ Branch 0 taken 20675 times.
✗ Branch 1 not taken.
20675 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7497 20675 trk->has_keyframes++;
7498 }
7499
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 26728 times.
26735 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7500 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7501 7 trk->has_disposable++;
7502 }
7503
7504 26735 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7505
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26735 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26735 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7506 ✗ memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7507 else
7508 26735 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7509
7510 26735 trk->entry++;
7511 26735 trk->sample_count += samples_in_chunk;
7512 26735 mov->mdat_size += size;
7513
7514
3/4
✓ Branch 0 taken 26653 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
26735 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7515 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7517 : NULL, size);
7518
7519 26736 end:
7520 26736 err:
7521
7522
1/2
✓ Branch 0 taken 26736 times.
✗ Branch 1 not taken.
26736 if (pkt->data != reformatted_data)
7523 26736 av_free(reformatted_data);
7524 26736 return ret;
7525 }
7526
7527 26699 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7528 {
7529 26699 MOVMuxContext *mov = s->priv_data;
7530 26699 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7531 26699 AVCodecParameters *par = trk->par;
7532 26699 int64_t frag_duration = 0;
7533 26699 int size = pkt->size;
7534
7535 26699 int ret = check_pkt(s, trk, pkt);
7536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26699 times.
26699 if (ret < 0)
7537 ✗ return ret;
7538
7539
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 26694 times.
26699 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7540
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7541 10 mov->tracks[i].frag_discont = 1;
7542 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7543 }
7544
7545
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 24687 times.
26699 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7546
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7547 15 trk->dts_shift = pkt->pts - pkt->dts;
7548 2012 pkt->dts += trk->dts_shift;
7549 }
7550
7551
1/2
✓ Branch 0 taken 26699 times.
✗ Branch 1 not taken.
26699 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7552
2/2
✓ Branch 0 taken 17689 times.
✓ Branch 1 taken 9010 times.
26699 trk->par->codec_id == AV_CODEC_ID_AAC ||
7553
2/2
✓ Branch 0 taken 17661 times.
✓ Branch 1 taken 28 times.
17689 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7554
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 17601 times.
17661 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7555 size_t side_size;
7556 9098 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7557 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7558
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9092 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
9098 if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
7559 6 void *newextra = av_malloc(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7561 ✗ return AVERROR(ENOMEM);
7562 6 memset((uint8_t*)newextra + side_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7563 6 memcpy(newextra, side, side_size);
7564 6 av_free(trk->extradata[trk->last_stsd_index]);
7565 6 trk->extradata[trk->last_stsd_index] = newextra;
7566 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7567 }
7568 }
7569
7570
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26690 times.
26699 if (!pkt->size) {
7571
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) {
7572 4 trk->start_dts = pkt->dts;
7573
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7574 4 trk->start_cts = pkt->pts - pkt->dts;
7575 else
7576 ✗ trk->start_cts = 0;
7577 }
7578
7579 9 return 0; /* Discard 0 sized packets */
7580 }
7581
7582
4/4
✓ Branch 0 taken 26121 times.
✓ Branch 1 taken 569 times.
✓ Branch 2 taken 26097 times.
✓ Branch 3 taken 24 times.
26690 if (trk->entry && pkt->stream_index < mov->nb_streams)
7583 26097 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7584 26097 s->streams[pkt->stream_index]->time_base,
7585 26097 AV_TIME_BASE_Q);
7586
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 26429 times.
26690 if ((mov->max_fragment_duration &&
7587
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7588
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26686 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26686 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7589
2/2
✓ Branch 0 taken 4895 times.
✓ Branch 1 taken 21791 times.
26686 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7590
2/2
✓ Branch 0 taken 2321 times.
✓ Branch 1 taken 2574 times.
4895 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7591
4/4
✓ Branch 0 taken 2293 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 2242 times.
✓ Branch 3 taken 51 times.
2321 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7592
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26634 times.
26635 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7593
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (frag_duration >= mov->min_fragment_duration) {
7594
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 1 times.
56 if (trk->entry) {
7595 // Set the duration of this track to line up with the next
7596 // sample in this track. This avoids relying on AVPacket
7597 // duration, but only helps for this particular track, not
7598 // for the other ones that are flushed at the same time.
7599 //
7600 // If we have trk->entry == 0, no fragment will be written
7601 // for this track, and we can't adjust the track end here.
7602 55 trk->track_duration = pkt->dts - trk->start_dts;
7603
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (pkt->pts != AV_NOPTS_VALUE)
7604 55 trk->end_pts = pkt->pts;
7605 else
7606 ✗ trk->end_pts = pkt->dts;
7607
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7608 55 trk->elst_end_pts = trk->end_pts;
7609 55 trk->end_reliable = 1;
7610 }
7611 56 mov_auto_flush_fragment(s, 0);
7612 }
7613 }
7614
7615 26690 return ff_mov_write_packet(s, pkt);
7616 }
7617
7618 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7619 int stream_index,
7620 int64_t dts) {
7621 3 MOVMuxContext *mov = s->priv_data;
7622 3 AVPacket *end = mov->pkt;
7623 3 uint8_t data[2] = {0};
7624 int ret;
7625
7626 3 end->size = sizeof(data);
7627 3 end->data = data;
7628 3 end->pts = dts;
7629 3 end->dts = dts;
7630 3 end->duration = 0;
7631 3 end->stream_index = stream_index;
7632
7633 3 ret = mov_write_single_packet(s, end);
7634 3 av_packet_unref(end);
7635
7636 3 return ret;
7637 }
7638
7639 #if CONFIG_IAMFENC
7640 300 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7641 {
7642 uint8_t *data;
7643 int ret;
7644
7645
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 240 times.
300 if (pkt->stream_index == trk->first_iamf_idx) {
7646 60 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (ret < 0)
7648 ✗ return ret;
7649 }
7650
7651 300 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7652 300 s->streams[pkt->stream_index]->id, pkt);
7653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (ret < 0)
7654 ✗ return ret;
7655
7656
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (pkt->stream_index != trk->last_iamf_idx)
7657 240 return AVERROR(EAGAIN);
7658
7659 60 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7660 60 trk->iamf_buf = NULL;
7661
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
60 if (!ret) {
7662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7663 // Either all or none of the packets for a single
7664 // IA Sample may be empty.
7665 ✗ av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7666 "stream #%d\n", pkt->stream_index);
7667 ✗ ret = AVERROR_INVALIDDATA;
7668 }
7669 5 av_free(data);
7670 5 return ret;
7671 }
7672
7673 55 av_buffer_unref(&pkt->buf);
7674 55 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (!pkt->buf) {
7676 ✗ av_free(data);
7677 ✗ return AVERROR(ENOMEM);
7678 }
7679 55 pkt->data = data;
7680 55 pkt->size = ret;
7681 55 pkt->stream_index = trk->first_iamf_idx;
7682
7683 55 return avio_open_dyn_buf(&trk->iamf_buf);
7684 }
7685 #endif
7686
7687 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7688 {
7689 2 int64_t pos = avio_tell(pb);
7690 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7691 2 const char *value = "";
7692
7693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7694
7695 2 avio_write_marker(pb,
7696 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7697 AVIO_DATA_MARKER_BOUNDARY_POINT);
7698
7699 2 avio_wb32(pb, 0); /* size */
7700 2 ffio_wfourcc(pb, "emsg");
7701 2 avio_w8(pb, 1); /* version */
7702 2 avio_wb24(pb, 0);
7703 2 avio_wb32(pb, st->time_base.den); /* timescale */
7704 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7705 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7706 2 avio_wb32(pb, 0); /* id */
7707 /* null terminated UTF8 strings */
7708 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7709 2 avio_write(pb, value, strlen(value) + 1);
7710 2 avio_write(pb, pkt->data, pkt->size);
7711
7712 2 return update_size(pb, pos);
7713 }
7714
7715 27107 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7716 {
7717 27107 MOVMuxContext *mov = s->priv_data;
7718 MOVTrack *trk;
7719
7720
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 27060 times.
27107 if (!pkt) {
7721 47 mov_flush_fragment(s, 1);
7722 47 return 1;
7723 }
7724
7725
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 27058 times.
27060 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7726 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7727 2 return 0;
7728 }
7729
7730 27058 trk = s->streams[pkt->stream_index]->priv_data;
7731
7732 #if CONFIG_IAMFENC
7733
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 26758 times.
27058 if (trk->iamf) {
7734 300 int ret = mov_build_iamf_packet(s, trk, pkt);
7735
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (ret < 0) {
7736
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if (ret == AVERROR(EAGAIN))
7737 240 return 0;
7738 ✗ av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7739 ✗ "for stream #%d\n", trk->st->index);
7740 ✗ return ret;
7741 }
7742 }
7743 #endif
7744
7745
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 26816 times.
26818 if (is_cover_image(trk->st)) {
7746 int ret;
7747
7748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7749 ✗ if (trk->st->nb_frames == 1)
7750 ✗ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7751 ✗ " ignoring.\n", pkt->stream_index);
7752 ✗ return 0;
7753 }
7754
7755
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7756 ✗ return ret;
7757
7758 2 return 0;
7759 } else {
7760 int i;
7761
7762
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26807 times.
26816 if (!pkt->size)
7763 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7764
7765 /*
7766 * Subtitles require special handling.
7767 *
7768 * 1) For full compliance, every track must have a sample at
7769 * dts == 0, which is rarely true for subtitles. So, as soon
7770 * as we see any packet with dts > 0, write an empty subtitle
7771 * at dts == 0 for any subtitle track with no samples in it.
7772 *
7773 * 2) For each subtitle track, check if the current packet's
7774 * dts is past the duration of the last subtitle sample. If
7775 * so, we now need to write an end sample for that subtitle.
7776 *
7777 * This must be done conditionally to allow for subtitles that
7778 * immediately replace each other, in which case an end sample
7779 * is not needed, and is, in fact, actively harmful.
7780 *
7781 * 3) See mov_write_trailer for how the final end sample is
7782 * handled.
7783 */
7784
2/2
✓ Branch 0 taken 320001 times.
✓ Branch 1 taken 26807 times.
346808 for (i = 0; i < mov->nb_tracks; i++) {
7785 320001 MOVTrack *trk = &mov->tracks[i];
7786 int ret;
7787
7788
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 319998 times.
320001 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7789
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7790
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)) {
7791 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7793 2 trk->last_sample_is_subtitle_end = 1;
7794 }
7795 }
7796
7797
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 26659 times.
26807 if (trk->squash_fragment_samples_to_one) {
7798 /*
7799 * If the track has to have its samples squashed into one sample,
7800 * we just take it into the track's queue.
7801 * This will then be utilized as the samples get written in either
7802 * mov_flush_fragment or when the mux is finalized in
7803 * mov_write_trailer.
7804 */
7805 148 int ret = AVERROR_BUG;
7806
7807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7808 ✗ av_log(s, AV_LOG_ERROR,
7809 "Packets without a valid presentation timestamp are "
7810 "not supported with packet squashing!\n");
7811 ✗ return AVERROR(EINVAL);
7812 }
7813
7814 /* The following will reset pkt and is only allowed to be used
7815 * because we return immediately. afterwards. */
7816
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = ff_packet_list_put(&trk->squashed_packet_queue,
7817 pkt, NULL, 0)) < 0) {
7818 ✗ return ret;
7819 }
7820
7821 148 return 0;
7822 }
7823
7824
7825
4/4
✓ Branch 0 taken 7939 times.
✓ Branch 1 taken 18720 times.
✓ Branch 2 taken 3917 times.
✓ Branch 3 taken 4022 times.
26659 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7826 3917 AVPacket *opkt = pkt;
7827 int reshuffle_ret, ret;
7828
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3892 times.
3917 if (trk->is_unaligned_qt_rgb) {
7829
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;
7830 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7831 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7833 ✗ return reshuffle_ret;
7834 } else
7835 3892 reshuffle_ret = 0;
7836
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3679 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3917 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7837 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7839 ✗ goto fail;
7840
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7841 5 trk->pal_done++;
7842
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 3087 times.
3912 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7843
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7845 ✗ ret = av_packet_make_writable(pkt);
7846 ✗ if (ret < 0)
7847 ✗ goto fail;
7848 ✗ for (i = 0; i < pkt->size; i++)
7849 ✗ pkt->data[i] = ~pkt->data[i];
7850 }
7851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3917 times.
3917 if (reshuffle_ret) {
7852 ✗ ret = mov_write_single_packet(s, pkt);
7853 ✗ fail:
7854 ✗ if (reshuffle_ret)
7855 ✗ av_packet_free(&pkt);
7856 ✗ return ret;
7857 }
7858 }
7859
7860 26659 return mov_write_single_packet(s, pkt);
7861 }
7862 }
7863
7864 // QuickTime chapters involve an additional text track with the chapter names
7865 // as samples, and a tref pointing from the other tracks to the chapter one.
7866 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7867 {
7868 static const uint8_t stub_header[] = {
7869 // TextSampleEntry
7870 0x00, 0x00, 0x00, 0x01, // displayFlags
7871 0x00, 0x00, // horizontal + vertical justification
7872 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7873 // BoxRecord
7874 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7875 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7876 // StyleRecord
7877 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7878 0x00, 0x01, // fontID
7879 0x00, 0x00, // fontStyleFlags + fontSize
7880 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7881 // FontTableBox
7882 0x00, 0x00, 0x00, 0x0D, // box size
7883 'f', 't', 'a', 'b', // box atom name
7884 0x00, 0x01, // entry count
7885 // FontRecord
7886 0x00, 0x01, // font ID
7887 0x00, // font name length
7888 };
7889 1 MOVMuxContext *mov = s->priv_data;
7890 1 MOVTrack *track = &mov->tracks[tracknum];
7891 1 AVPacket *pkt = mov->pkt;
7892 int i, len;
7893 int ret;
7894
7895 1 track->mode = mov->mode;
7896 1 track->tag = MKTAG('t','e','x','t');
7897 1 track->timescale = mov->movie_timescale;
7898 1 track->par = avcodec_parameters_alloc();
7899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7900 ✗ return AVERROR(ENOMEM);
7901 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7902 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7904 ✗ return ret;
7905 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7906
7907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7908 ✗ track->stsd_count = 1;
7909 ✗ track->extradata = av_calloc(1, sizeof(*track->extradata));
7910 ✗ track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7911 ✗ if (!track->extradata || !track->extradata_size)
7912 ✗ return AVERROR(ENOMEM);
7913 }
7914
7915 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7917 ✗ return AVERROR(ENOMEM);
7918 1 track->extradata_size[0] = sizeof(stub_header);
7919
7920 1 pkt->stream_index = tracknum;
7921 1 pkt->flags = AV_PKT_FLAG_KEY;
7922
7923
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7924 4 AVChapter *c = s->chapters[i];
7925 AVDictionaryEntry *t;
7926
7927 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7928 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7929 4 pkt->duration = end - pkt->dts;
7930
7931
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7932 static const char encd[12] = {
7933 0x00, 0x00, 0x00, 0x0C,
7934 'e', 'n', 'c', 'd',
7935 0x00, 0x00, 0x01, 0x00 };
7936 4 len = strlen(t->value);
7937 4 pkt->size = len + 2 + 12;
7938 4 pkt->data = av_malloc(pkt->size);
7939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7940 ✗ av_packet_unref(pkt);
7941 ✗ return AVERROR(ENOMEM);
7942 }
7943 4 AV_WB16(pkt->data, len);
7944 4 memcpy(pkt->data + 2, t->value, len);
7945 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7946 4 ff_mov_write_packet(s, pkt);
7947 4 av_freep(&pkt->data);
7948 }
7949 }
7950
7951 1 av_packet_unref(mov->pkt);
7952
7953 1 return 0;
7954 }
7955
7956
7957 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7958 {
7959 int ret;
7960
7961 /* compute the frame number */
7962 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7963 13 return ret;
7964 }
7965
7966 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7967 {
7968 6 MOVMuxContext *mov = s->priv_data;
7969 6 MOVTrack *track = &mov->tracks[index];
7970 6 AVStream *src_st = mov->tracks[src_index].st;
7971 uint8_t data[4];
7972 6 AVPacket *pkt = mov->pkt;
7973 6 AVRational rate = src_st->avg_frame_rate;
7974 int ret;
7975
7976 /* tmcd track based on video stream */
7977 6 track->mode = mov->mode;
7978 6 track->tag = MKTAG('t','m','c','d');
7979 6 track->src_track = av_malloc(sizeof(*track->src_track));
7980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->src_track)
7981 ✗ return AVERROR(ENOMEM);
7982 6 *track->src_track = src_index;
7983 6 track->nb_src_track = 1;
7984
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7985 3 track->timescale = tc.fps * 1000;
7986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (tc.rate.den == 1001)
7987 ✗ track->timescale = tc.rate.num;
7988 else
7989 3 track->timescale = tc.fps;
7990
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7991 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7992
7993 /* set st to src_st for metadata access*/
7994 6 track->st = src_st;
7995
7996 /* encode context: tmcd data stream */
7997 6 track->par = avcodec_parameters_alloc();
7998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7999 ✗ return AVERROR(ENOMEM);
8000 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
8001 6 track->par->codec_tag = track->tag;
8002 6 track->st->avg_frame_rate = rate;
8003
8004 /* the tmcd track just contains one packet with the frame number */
8005 6 pkt->data = data;
8006 6 pkt->stream_index = index;
8007 6 pkt->flags = AV_PKT_FLAG_KEY;
8008 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){ 1, track->timescale });
8009 6 pkt->size = 4;
8010 6 AV_WB32(pkt->data, tc.start);
8011 6 ret = ff_mov_write_packet(s, pkt);
8012 6 av_packet_unref(pkt);
8013 6 return ret;
8014 }
8015
8016 /*
8017 * st->disposition controls the "enabled" flag in the tkhd tag.
8018 * QuickTime will not play a track if it is not enabled. So make sure
8019 * that one track of each type (audio, video, subtitle) is enabled.
8020 *
8021 * Subtitles are special. For audio and video, setting "enabled" also
8022 * makes the track "default" (i.e. it is rendered when played). For
8023 * subtitles, an "enabled" subtitle is not rendered by default, but
8024 * if no subtitle is enabled, the subtitle menu in QuickTime will be
8025 * empty!
8026 */
8027 252 static void enable_tracks(AVFormatContext *s)
8028 {
8029 252 MOVMuxContext *mov = s->priv_data;
8030 int i;
8031 int enabled[AVMEDIA_TYPE_NB];
8032 int first[AVMEDIA_TYPE_NB];
8033
8034
2/2
✓ Branch 0 taken 1260 times.
✓ Branch 1 taken 252 times.
1512 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8035 1260 enabled[i] = 0;
8036 1260 first[i] = -1;
8037 }
8038
8039
2/2
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 252 times.
665 for (i = 0; i < mov->nb_streams; i++) {
8040 413 AVStream *st = mov->tracks[i].st;
8041
8042
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
8043
3/4
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 411 times.
826 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
8044 413 is_cover_image(st))
8045 2 continue;
8046
8047
2/2
✓ Branch 0 taken 297 times.
✓ Branch 1 taken 114 times.
411 if (first[st->codecpar->codec_type] < 0)
8048 297 first[st->codecpar->codec_type] = i;
8049
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 374 times.
411 if (st->disposition & AV_DISPOSITION_DEFAULT) {
8050 37 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
8051 37 enabled[st->codecpar->codec_type]++;
8052 }
8053 }
8054
8055
2/2
✓ Branch 0 taken 1260 times.
✓ Branch 1 taken 252 times.
1512 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8056
2/2
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 504 times.
1260 switch (i) {
8057 756 case AVMEDIA_TYPE_VIDEO:
8058 case AVMEDIA_TYPE_AUDIO:
8059 case AVMEDIA_TYPE_SUBTITLE:
8060
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 755 times.
756 if (enabled[i] > 1)
8061 1 mov->per_stream_grouping = 1;
8062
4/4
✓ Branch 0 taken 724 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 461 times.
756 if (!enabled[i] && first[i] >= 0)
8063 263 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
8064 756 break;
8065 }
8066 }
8067 252 }
8068
8069 252 static void mov_free(AVFormatContext *s)
8070 {
8071 252 MOVMuxContext *mov = s->priv_data;
8072
8073
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 252 times.
686 for (int i = 0; i < s->nb_streams; i++)
8074 434 s->streams[i]->priv_data = NULL;
8075
8076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (!mov->tracks)
8077 ✗ return;
8078
8079
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->chapter_track) {
8080 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
8081 }
8082
8083
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 252 times.
674 for (int i = 0; i < mov->nb_tracks; i++) {
8084 422 MOVTrack *const track = &mov->tracks[i];
8085
8086
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 420 times.
422 if (track->tag == MKTAG('r','t','p',' '))
8087 2 ff_mov_close_hinting(track);
8088
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 411 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
420 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
8089 6 av_freep(&track->par);
8090 422 av_freep(&track->cluster);
8091 422 av_freep(&track->cluster_written);
8092 422 av_freep(&track->frag_info);
8093 422 av_packet_free(&track->cover_image);
8094
8095
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 412 times.
422 if (track->eac3_priv) {
8096 10 struct eac3_info *info = track->eac3_priv;
8097 10 av_packet_free(&info->pkt);
8098 10 av_freep(&track->eac3_priv);
8099 }
8100
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 422 times.
846 for (int j = 0; j < track->stsd_count; j++)
8101 424 av_freep(&track->extradata[j]);
8102 422 av_freep(&track->extradata);
8103 422 av_freep(&track->extradata_size);
8104
8105
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 422 times.
432 for (int i = 0; i < track->nb_tref_tags; i++)
8106 10 av_freep(&track->tref_tags[i].id);
8107 422 av_freep(&track->tref_tags);
8108 422 av_freep(&track->src_track);
8109
8110 422 ff_mov_cenc_free(&track->cenc);
8111 422 ffio_free_dyn_buf(&track->mdat_buf);
8112
8113 #if CONFIG_IAMFENC
8114 422 ffio_free_dyn_buf(&track->iamf_buf);
8115
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 417 times.
422 if (track->iamf)
8116 5 ff_iamf_uninit_context(track->iamf);
8117 422 av_freep(&track->iamf);
8118 #endif
8119 422 ff_isom_close_apvc(&track->apv);
8120
8121 422 ff_packet_list_free(&track->squashed_packet_queue);
8122 }
8123
8124 252 av_freep(&mov->tracks);
8125 252 ffio_free_dyn_buf(&mov->mdat_buf);
8126 }
8127
8128 ✗ static uint32_t rgb_to_yuv(uint32_t rgb)
8129 {
8130 uint8_t r, g, b;
8131 int y, cb, cr;
8132
8133 ✗ r = (rgb >> 16) & 0xFF;
8134 ✗ g = (rgb >> 8) & 0xFF;
8135 ✗ b = (rgb ) & 0xFF;
8136
8137 ✗ y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
8138 ✗ cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
8139 ✗ cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
8140
8141 ✗ return (y << 16) | (cr << 8) | cb;
8142 }
8143
8144 ✗ static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
8145 AVStream *st)
8146 {
8147 ✗ int i, width = 720, height = 480;
8148 ✗ int have_palette = 0, have_size = 0;
8149 uint32_t palette[16];
8150 ✗ char *cur = st->codecpar->extradata;
8151
8152 ✗ while (cur && *cur) {
8153 ✗ if (strncmp("palette:", cur, 8) == 0) {
8154 int i, count;
8155 ✗ count = sscanf(cur + 8,
8156 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8157 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8158 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8159 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
8160 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
8161 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
8162 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
8163 &palette[12], &palette[13], &palette[14], &palette[15]);
8164
8165 ✗ for (i = 0; i < count; i++) {
8166 ✗ palette[i] = rgb_to_yuv(palette[i]);
8167 }
8168 ✗ have_palette = 1;
8169 ✗ } else if (!strncmp("size:", cur, 5)) {
8170 ✗ sscanf(cur + 5, "%dx%d", &width, &height);
8171 ✗ have_size = 1;
8172 }
8173 ✗ if (have_palette && have_size)
8174 ✗ break;
8175 ✗ cur += strcspn(cur, "\n\r");
8176 ✗ cur += strspn(cur, "\n\r");
8177 }
8178 ✗ if (have_palette) {
8179 ✗ track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
8180 ✗ if (!track->extradata[track->last_stsd_index])
8181 ✗ return AVERROR(ENOMEM);
8182 ✗ for (i = 0; i < 16; i++) {
8183 ✗ AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
8184 }
8185 ✗ memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8186 ✗ track->extradata_size[track->last_stsd_index] = 16 * 4;
8187 }
8188 ✗ st->codecpar->width = width;
8189 ✗ st->codecpar->height = track->height = height;
8190
8191 ✗ return 0;
8192 }
8193
8194 #if CONFIG_IAMFENC
8195 252 static int mov_init_iamf_track(AVFormatContext *s)
8196 {
8197 252 MOVMuxContext *mov = s->priv_data;
8198 MOVTrack *track;
8199 IAMFContext *iamf;
8200 252 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
8201 252 int nb_audio_elements = 0, nb_mix_presentations = 0;
8202 int ret;
8203
8204
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 252 times.
262 for (int i = 0; i < s->nb_stream_groups; i++) {
8205 10 const AVStreamGroup *stg = s->stream_groups[i];
8206
8207
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8208 5 nb_audio_elements++;
8209
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
8210 5 nb_mix_presentations++;
8211 }
8212
8213
3/4
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 247 times.
✗ Branch 3 not taken.
252 if (!nb_audio_elements && !nb_mix_presentations)
8214 247 return 0;
8215
8216
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) {
8217 ✗ av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
8218 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
8219 ✗ return AVERROR(EINVAL);
8220 }
8221
8222 5 iamf = av_mallocz(sizeof(*iamf));
8223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
8224 ✗ return AVERROR(ENOMEM);
8225
8226
8227
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8228 10 const AVStreamGroup *stg = s->stream_groups[i];
8229
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
8230 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
8231
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8232 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
8233 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
8234 }
8235
8236 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
8237 5 break;
8238 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
8239 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
8240 5 break;
8241 ✗ default:
8242 ✗ av_assert0(0);
8243 }
8244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
8245 ✗ ff_iamf_uninit_context(iamf);
8246 ✗ av_free(iamf);
8247 ✗ return ret;
8248 }
8249 }
8250
8251 5 track = &mov->tracks[first_iamf_idx];
8252 5 track->iamf = iamf;
8253 5 track->first_iamf_idx = first_iamf_idx;
8254 5 track->last_iamf_idx = last_iamf_idx;
8255 5 track->tag = MKTAG('i','a','m','f');
8256
8257
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8258 10 AVStreamGroup *stg = s->stream_groups[i];
8259
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8260 5 continue;
8261
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
8262 25 stg->streams[j]->priv_data = track;
8263 }
8264
8265 5 ret = avio_open_dyn_buf(&track->iamf_buf);
8266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
8267 ✗ return ret;
8268
8269 5 return 0;
8270 }
8271 #endif
8272
8273 252 static int mov_init(AVFormatContext *s)
8274 {
8275 252 MOVMuxContext *mov = s->priv_data;
8276 252 int has_iamf = 0;
8277 int i, ret;
8278
8279 252 mov->fc = s;
8280 252 mov->pkt = ffformatcontext(s)->pkt;
8281
8282 /* Default mode == MP4 */
8283 252 mov->mode = MODE_MP4;
8284
8285 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
8286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
8287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
8288
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 101 times.
252 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
8289
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
8290
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
8291
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 94 times.
99 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
8292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
8293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
8294 #undef IS_MODE
8295
8296
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 231 times.
252 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
8297 21 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
8298
8299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (mov->mode == MODE_AVIF)
8300 ✗ mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
8301
8302 /* Set the FRAGMENT flag if any of the fragmentation methods are
8303 * enabled. */
8304
3/4
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 250 times.
✗ Branch 3 not taken.
252 if (mov->max_fragment_duration || mov->max_fragment_size ||
8305
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 214 times.
250 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
8306 FF_MOV_FLAG_FRAG_KEYFRAME |
8307 FF_MOV_FLAG_FRAG_CUSTOM |
8308 FF_MOV_FLAG_FRAG_EVERY_FRAME))
8309 38 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8310
8311
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 250 times.
252 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
8312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
8313 ✗ av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
8314 ✗ return AVERROR(EINVAL);
8315 }
8316
8317 /* Set other implicit flags immediately */
8318
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 250 times.
252 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8319 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8320
8321
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 247 times.
252 if (mov->mode == MODE_ISM)
8322 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
8323 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8324
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 237 times.
252 if (mov->flags & FF_MOV_FLAG_DASH)
8325 15 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8326 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
8327
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 250 times.
252 if (mov->flags & FF_MOV_FLAG_CMAF)
8328 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8329 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8330
8331
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 213 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 4 times.
252 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
8332 35 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
8333 35 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
8334 }
8335
8336
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
252 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
8337 ✗ av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
8338 ✗ mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
8339 }
8340
8341
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 249 times.
252 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8342 3 mov->reserved_moov_size = -1;
8343 }
8344
8345
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 7 times.
252 if (mov->use_editlist < 0) {
8346 245 mov->use_editlist = 1;
8347
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 208 times.
245 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8348
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 19 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8349 // If we can avoid needing an edit list by shifting the
8350 // tracks, prefer that over (trying to) write edit lists
8351 // in fragmented output.
8352
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
8353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
8354 17 mov->use_editlist = 0;
8355 }
8356 }
8357
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 213 times.
252 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8358
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17 times.
39 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
8359 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
8360
8361
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 250 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
252 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist)
8362 ✗ mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8363
8364
4/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 229 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 1 times.
252 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
8365
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
22 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
8366 14 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
8367
8368 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
8369 * if the latter is set that's enough and omit_tfhd_offset doesn't
8370 * add anything extra on top of that. */
8371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
8372 ✗ mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
8373 ✗ mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
8374
8375
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->frag_interleave &&
8376
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)) {
8377 ✗ av_log(s, AV_LOG_ERROR,
8378 "Sample interleaving in fragments is mutually exclusive with "
8379 "omit_tfhd_offset and separate_moof\n");
8380 ✗ return AVERROR(EINVAL);
8381 }
8382
8383 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8384 * is enabled, we don't support non-seekable output at all. */
8385
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 223 times.
252 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
8386
2/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
8387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 mov->mode == MODE_AVIF)) {
8388 ✗ av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
8389 ✗ return AVERROR(EINVAL);
8390 }
8391
8392 /* AVIF output must have at most two video streams (one for YUV and one for
8393 * alpha). */
8394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (mov->mode == MODE_AVIF) {
8395 ✗ if (s->nb_streams > 2) {
8396 ✗ av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
8397 ✗ return AVERROR(EINVAL);
8398 }
8399 ✗ if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
8400 ✗ (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
8401 ✗ av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
8402 ✗ return AVERROR(EINVAL);
8403 }
8404 ✗ if (s->nb_streams > 1) {
8405 const AVPixFmtDescriptor *pixdesc =
8406 ✗ av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
8407 ✗ if (pixdesc->nb_components != 1) {
8408 ✗ av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8409 ✗ return AVERROR(EINVAL);
8410 }
8411 }
8412 ✗ s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
8413 }
8414
8415
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 252 times.
262 for (i = 0; i < s->nb_stream_groups; i++) {
8416 10 AVStreamGroup *stg = s->stream_groups[i];
8417
8418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_LCEVC) {
8419 ✗ if (stg->nb_streams != 2) {
8420 ✗ av_log(s, AV_LOG_ERROR, "Exactly two Streams are supported for Stream Groups of type LCEVC\n");
8421 ✗ return AVERROR(EINVAL);
8422 }
8423 ✗ AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8424 ✗ if (lcevc->el_index > 1)
8425 ✗ return AVERROR(EINVAL);
8426 ✗ AVStream *st = stg->streams[lcevc->el_index];
8427 ✗ if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) {
8428 ✗ av_log(s, AV_LOG_ERROR, "Stream #%u is not an LCEVC stream\n", lcevc->el_index);
8429 ✗ return AVERROR(EINVAL);
8430 }
8431 }
8432
8433 #if CONFIG_IAMFENC
8434
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8435 5 continue;
8436
8437
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8438 25 AVStream *st = stg->streams[j];
8439
8440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8441 ✗ av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8442 "IAMF Audio Element\n", j);
8443 ✗ return AVERROR(EINVAL);
8444 }
8445 25 st->priv_data = st;
8446 }
8447 5 has_iamf = 1;
8448
8449
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
8450 5 mov->nb_tracks++;
8451 #endif
8452 }
8453
8454
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 252 times.
686 for (i = 0; i < s->nb_streams; i++) {
8455 434 AVStream *st = s->streams[i];
8456
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 409 times.
434 if (st->priv_data)
8457 25 continue;
8458 // Don't produce a track in the output file for timed ID3 streams.
8459
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 408 times.
409 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8460 // Leave priv_data set to NULL for these AVStreams that don't
8461 // have a corresponding track.
8462 1 continue;
8463 }
8464 408 st->priv_data = st;
8465 408 mov->nb_tracks++;
8466 }
8467
8468 252 mov->nb_streams = mov->nb_tracks;
8469
8470
4/4
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 245 times.
252 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8471 1 mov->chapter_track = mov->nb_tracks++;
8472
8473
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8474
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8475
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8476 2 mov->nb_tracks++;
8477 }
8478
8479
1/2
✓ Branch 0 taken 252 times.
✗ Branch 1 not taken.
252 if (mov->write_btrt < 0) {
8480 252 mov->write_btrt = mov->mode == MODE_MP4;
8481 }
8482
8483
6/6
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 151 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 94 times.
252 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8484
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8485 248 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8486 NULL, 0);
8487
8488 /* +1 tmcd track for each video stream with a timecode */
8489
2/2
✓ Branch 0 taken 427 times.
✓ Branch 1 taken 248 times.
675 for (i = 0; i < s->nb_streams; i++) {
8490 427 AVStream *st = s->streams[i];
8491 427 AVDictionaryEntry *t = global_tcr;
8492
4/4
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 226 times.
✓ Branch 2 taken 195 times.
✓ Branch 3 taken 6 times.
427 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8493
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 194 times.
195 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8494 AVTimecode tc;
8495 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8496
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8497 7 mov->nb_meta_tmcd++;
8498 }
8499 }
8500
8501 /* check if there is already a tmcd track to remux */
8502
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 241 times.
248 if (mov->nb_meta_tmcd) {
8503
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8504 13 AVStream *st = s->streams[i];
8505
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8506 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8507 "so timecode metadata are now ignored\n");
8508 3 mov->nb_meta_tmcd = 0;
8509 }
8510 }
8511 }
8512
8513 248 mov->nb_tracks += mov->nb_meta_tmcd;
8514 }
8515
8516 // Reserve an extra stream for chapters for the case where chapters
8517 // are written in the trailer
8518 252 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (!mov->tracks)
8520 ✗ return AVERROR(ENOMEM);
8521
8522
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 252 times.
674 for (i = 0; i < mov->nb_tracks; i++) {
8523 422 MOVTrack *track = &mov->tracks[i];
8524
8525 422 track->stsd_count = 1;
8526 422 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8527 422 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8528
2/4
✓ Branch 0 taken 422 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 422 times.
422 if (!track->extradata || !track->extradata_size)
8529 ✗ return AVERROR(ENOMEM);
8530 }
8531
8532
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
252 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8533
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8534 5 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8535
8536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8537 ✗ av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8538 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8539 ✗ return AVERROR(EINVAL);
8540 }
8541
8542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8543 ✗ av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8544 mov->encryption_kid_len, CENC_KID_SIZE);
8545 ✗ return AVERROR(EINVAL);
8546 }
8547 } else {
8548 ✗ av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8549 mov->encryption_scheme_str);
8550 ✗ return AVERROR(EINVAL);
8551 }
8552 }
8553
8554 #if CONFIG_IAMFENC
8555 252 ret = mov_init_iamf_track(s);
8556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (ret < 0)
8557 ✗ return ret;
8558 #endif
8559
8560
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 252 times.
686 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8561 434 AVStream *st = s->streams[j];
8562
8563
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 408 times.
434 if (st != st->priv_data) {
8564
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8565 5 i += has_iamf--;
8566 26 continue;
8567 }
8568 408 st->priv_data = &mov->tracks[i++];
8569 }
8570
8571 252 AVRational movie_timescale = (AVRational) { 0, 1 };
8572
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 252 times.
686 for (i = 0; i < s->nb_streams; i++) {
8573 434 AVStream *st= s->streams[i];
8574 434 MOVTrack *track = st->priv_data;
8575
8576
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 433 times.
434 if (!track)
8577 1 continue;
8578
8579
2/2
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 20 times.
433 if (!track->st) {
8580 413 track->st = st;
8581 413 track->par = st->codecpar;
8582 }
8583
8584 433 movie_timescale = av_gcd_q(movie_timescale, st->time_base, INT_MAX, (AVRational){1,0});
8585 }
8586
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (!movie_timescale.den)
8587 ✗ movie_timescale = MOV_TIMESCALE_Q;
8588
8589
1/2
✓ Branch 0 taken 252 times.
✗ Branch 1 not taken.
252 if (!mov->movie_timescale)
8590 252 mov->movie_timescale = FFMAX(movie_timescale.den, MOV_TIMESCALE);
8591
8592
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 252 times.
686 for (i = 0; i < s->nb_streams; i++) {
8593 434 AVStream *st= s->streams[i];
8594 434 MOVTrack *track = st->priv_data;
8595 434 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8596
8597
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 433 times.
434 if (!track)
8598 1 continue;
8599
8600
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 402 times.
433 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8601
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 275 times.
433 if (track->language < 0)
8602 158 track->language = 32767; // Unspecified Macintosh language code
8603 433 track->mode = mov->mode;
8604
2/2
✓ Branch 0 taken 408 times.
✓ Branch 1 taken 25 times.
433 if (!track->tag)
8605 408 track->tag = mov_find_codec_tag(s, track);
8606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 433 times.
433 if (!track->tag) {
8607 ✗ av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8608 "codec not currently supported in container\n",
8609 ✗ avcodec_get_name(st->codecpar->codec_id), i);
8610 ✗ return AVERROR(EINVAL);
8611 }
8612 /* If hinting of this track is enabled by a later hint track,
8613 * this is updated. */
8614 433 track->hint_track = -1;
8615 433 track->start_dts = AV_NOPTS_VALUE;
8616 433 track->start_cts = AV_NOPTS_VALUE;
8617 433 track->end_pts = AV_NOPTS_VALUE;
8618 433 track->dts_shift = AV_NOPTS_VALUE;
8619
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 229 times.
433 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8620
2/4
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
204 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8621
2/4
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
204 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8622
2/4
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
204 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8623 ✗ if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8624 ✗ av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8625 ✗ return AVERROR(EINVAL);
8626 }
8627 ✗ track->height = track->tag >> 24 == 'n' ? 486 : 576;
8628 }
8629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 if (mov->video_track_timescale) {
8630 ✗ track->timescale = mov->video_track_timescale;
8631 ✗ if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8632 ✗ av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8633 } else {
8634 204 track->timescale = st->time_base.den;
8635
2/2
✓ Branch 0 taken 1608 times.
✓ Branch 1 taken 204 times.
1812 while(track->timescale < 10000)
8636 1608 track->timescale *= 2;
8637 }
8638
2/4
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
204 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8639 ✗ av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8640 ✗ return AVERROR(EINVAL);
8641 }
8642
4/4
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 131 times.
204 if (track->mode == MODE_MOV && track->timescale > 100000)
8643 5 av_log(s, AV_LOG_WARNING,
8644 "WARNING codec timebase is very high. If duration is too long,\n"
8645 "file may not be playable by quicktime. Specify a shorter timebase\n"
8646 "or choose different container.\n");
8647
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 68 times.
204 if (track->mode == MODE_MOV &&
8648
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 119 times.
136 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8649
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8650 1 enum AVPixelFormat pix_fmt = track->par->format;
8651
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)
8652 ✗ pix_fmt = AV_PIX_FMT_MONOWHITE;
8653 1 track->is_unaligned_qt_rgb =
8654 ✗ pix_fmt == AV_PIX_FMT_RGB24 ||
8655 ✗ pix_fmt == AV_PIX_FMT_BGR24 ||
8656 ✗ pix_fmt == AV_PIX_FMT_PAL8 ||
8657 ✗ pix_fmt == AV_PIX_FMT_GRAY8 ||
8658
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 ||
8659 pix_fmt == AV_PIX_FMT_MONOBLACK;
8660 }
8661
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
204 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8662 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8663 ✗ return AVERROR(EINVAL);
8664
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 202 times.
204 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8665
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8666 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8667 ✗ return AVERROR(EINVAL);
8668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8669 /* altref frames handling is not defined in the spec as of version v1.0,
8670 * so just forbid muxing VP8 streams altogether until a new version does */
8671 ✗ av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8672 ✗ return AVERROR_PATCHWELCOME;
8673
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 203 times.
204 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8674 1 ret = ff_isom_init_apvc(&track->apv, s);
8675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8676 ✗ return ret;
8677 }
8678
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 202 times.
204 if (is_cover_image(st)) {
8679 2 track->cover_image = av_packet_alloc();
8680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8681 ✗ return AVERROR(ENOMEM);
8682 }
8683
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 9 times.
229 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8684 220 track->timescale = st->codecpar->sample_rate;
8685
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 186 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 26 times.
220 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8686 8 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8687 8 track->audio_vbr = 1;
8688
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8689
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8691 ✗ if (!st->codecpar->block_align) {
8692 ✗ av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8693 ✗ return AVERROR(EINVAL);
8694 }
8695 ✗ track->sample_size = st->codecpar->block_align;
8696
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 26 times.
212 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8697 186 track->audio_vbr = 1;
8698 }else{
8699 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8700 26 st->codecpar->ch_layout.nb_channels;
8701 }
8702
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8704 ✗ track->audio_vbr = 1;
8705 }
8706
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 31 times.
220 if (track->mode != MODE_MOV &&
8707
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
189 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8708 ✗ if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8709 ✗ av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8710 ✗ i, track->par->sample_rate);
8711 ✗ return AVERROR(EINVAL);
8712 } else {
8713 ✗ av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8714 ✗ i, track->par->sample_rate);
8715 }
8716 }
8717
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 25 times.
220 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8718
1/2
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
195 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 track->par->codec_id == AV_CODEC_ID_OPUS) {
8720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8721 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8722 ✗ return AVERROR(EINVAL);
8723 }
8724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8725 ✗ s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8726 ✗ av_log(s, AV_LOG_ERROR,
8727 "%s in MP4 support is experimental, add "
8728 "'-strict %d' if you want to use it.\n",
8729 ✗ avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8730 ✗ return AVERROR_EXPERIMENTAL;
8731 }
8732 }
8733
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8734 5 track->timescale = st->time_base.den;
8735
8736
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8737 /* 14496-30 requires us to use a single sample per fragment
8738 for TTML, for which we define a per-track flag.
8739
8740 We set the flag in case we are receiving TTML paragraphs
8741 from the input, in other words in case we are not doing
8742 stream copy. */
8743 4 track->squash_fragment_samples_to_one =
8744 4 ff_is_ttml_stream_paragraph_based(track->par);
8745
8746
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8747
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8749 ✗ av_log(s, AV_LOG_ERROR,
8750 "ISMV style TTML support with the 'dfxp' tag in "
8751 "non-ISMV formats is not officially supported. Add "
8752 "'-strict unofficial' if you want to use it.\n");
8753 ✗ return AVERROR_EXPERIMENTAL;
8754 }
8755 }
8756
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8757 4 track->timescale = st->time_base.den;
8758
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->tag == MKTAG('t','m','c','d') &&
8759
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->extradata_size >= 8)
8760 3 track->timecode_flags = AV_RB32(st->codecpar->extradata + 4);
8761 } else {
8762 ✗ track->timescale = mov->movie_timescale;
8763 }
8764
1/2
✓ Branch 0 taken 433 times.
✗ Branch 1 not taken.
433 if (!track->height)
8765 433 track->height = st->codecpar->height;
8766 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8767 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8768 for video tracks, so if user-set, it isn't overwritten */
8769
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 426 times.
433 if (mov->mode == MODE_ISM &&
8770
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8771
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))) {
8772 7 track->timescale = 10000000;
8773 }
8774
8775 433 avpriv_set_pts_info(st, 64, 1, track->timescale);
8776
8777
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 428 times.
433 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8778 5 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8779
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8780
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8781
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret)
8783 ✗ return ret;
8784 }
8785 }
8786
8787
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 252 times.
262 for (i = 0; i < s->nb_stream_groups; i++) {
8788 10 AVStreamGroup *stg = s->stream_groups[i];
8789
8790
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 switch (stg->type) {
8791 ✗ case AV_STREAM_GROUP_PARAMS_LCEVC: {
8792 ✗ AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8793 ✗ AVStream *st = stg->streams[lcevc->el_index];
8794 ✗ MOVTrack *track = st->priv_data;
8795
8796 ✗ for (int j = 0; j < mov->nb_tracks; j++) {
8797 ✗ MOVTrack *trk = &mov->tracks[j];
8798
8799 ✗ if (trk->st == stg->streams[!lcevc->el_index]) {
8800 ✗ track->src_track = av_malloc(sizeof(*track->src_track));
8801 ✗ if (!track->src_track)
8802 ✗ return AVERROR(ENOMEM);
8803 ✗ *track->src_track = j;
8804 ✗ track->nb_src_track = 1;
8805 ✗ break;
8806 }
8807 }
8808
8809 ✗ track->par->width = lcevc->width;
8810 ✗ track->par->height = track->height = lcevc->height;
8811 ✗ break;
8812 }
8813 ✗ case AV_STREAM_GROUP_PARAMS_TREF: {
8814 ✗ const AVStreamGroupTREF *tref = stg->params.tref;
8815 MOVTrack *track;
8816
8817 ✗ if (tref->metadata_index >= stg->nb_streams)
8818 ✗ return AVERROR(EINVAL);
8819
8820 ✗ track = stg->streams[tref->metadata_index]->priv_data;
8821 ✗ for (int j = 0; j < stg->nb_streams; j++) {
8822 ✗ const AVStream *st2 = stg->streams[j];
8823 ✗ int index = -1;
8824
8825 ✗ if (j == tref->metadata_index)
8826 ✗ continue;
8827
8828 ✗ for (int k = 0; k < mov->nb_tracks; k++) {
8829 ✗ if (mov->tracks[k].st != st2)
8830 ✗ continue;
8831 ✗ index = k;
8832 ✗ break;
8833 }
8834 ✗ if (index < 0)
8835 ✗ return AVERROR(EINVAL);
8836
8837 ✗ int *tmp = av_realloc(track->src_track,
8838 ✗ (track->nb_src_track + 1) * sizeof(*track->src_track));
8839 ✗ if (!tmp)
8840 ✗ return AVERROR(ENOMEM);
8841 ✗ track->src_track = tmp;
8842 ✗ track->src_track[track->nb_src_track++] = index;
8843 }
8844 ✗ break;
8845 }
8846 10 default:
8847 10 break;
8848 }
8849 }
8850
8851 /* fill src_track for tmcd tracks not covered by stream groups or
8852 * created by this muxer, retaining the old behavior of src_track
8853 * being arbitrarily 0. */
8854
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 252 times.
686 for (i = 0; i < s->nb_streams; i++) {
8855 434 AVStream *st = s->streams[i];
8856 434 MOVTrack *track = st->priv_data;
8857
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 431 times.
434 if (st->codecpar->codec_tag != MKTAG('t','m','c','d') ||
8858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 track->nb_src_track)
8859 431 continue;
8860
8861 3 track->src_track = av_malloc(sizeof(*track->src_track));
8862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!track->src_track)
8863 ✗ return AVERROR(ENOMEM);
8864 3 *track->src_track = 0;
8865 3 track->nb_src_track = 1;
8866 }
8867
8868 252 enable_tracks(s);
8869 252 return 0;
8870 }
8871
8872 252 static int mov_write_header(AVFormatContext *s)
8873 {
8874 252 AVIOContext *pb = s->pb;
8875 252 MOVMuxContext *mov = s->priv_data;
8876 252 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8877
8878
4/4
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 245 times.
252 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8879 1 nb_tracks++;
8880
8881
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8882 1 hint_track = nb_tracks;
8883
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8884
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8885 2 nb_tracks++;
8886 }
8887 }
8888
8889
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 246 times.
252 if (mov->nb_meta_tmcd)
8890 6 tmcd_track = nb_tracks;
8891
8892
2/2
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 252 times.
665 for (int i = 0; i < mov->nb_streams; i++) {
8893 413 MOVTrack *track = &mov->tracks[i];
8894 413 AVStream *st = track->st;
8895
8896 /* copy extradata if it exists */
8897
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 264 times.
413 if (st->codecpar->extradata_size) {
8898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8899 ✗ mov_create_dvd_sub_decoder_specific_info(track, st);
8900
15/30
✓ Branch 0 taken 149 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 149 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 149 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 149 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 149 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 149 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 149 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 149 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 149 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 149 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 149 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 149 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 149 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 149 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 149 times.
✗ Branch 29 not taken.
149 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8901 149 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8902 298 track->extradata[track->last_stsd_index] =
8903 149 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 if (!track->extradata[track->last_stsd_index]) {
8905 ✗ return AVERROR(ENOMEM);
8906 }
8907 149 memcpy(track->extradata[track->last_stsd_index],
8908 149 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8909 149 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8910 0, AV_INPUT_BUFFER_PADDING_SIZE);
8911 }
8912 }
8913
8914
4/4
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 213 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 114 times.
613 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8915 200 av_channel_layout_compare(&track->par->ch_layout,
8916 200 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8917 299 continue;
8918
8919
2/2
✓ Branch 0 taken 10032 times.
✓ Branch 1 taken 114 times.
10146 for (int j = 0; j < mov->nb_streams; j++) {
8920 10032 AVStream *stj= mov->tracks[j].st;
8921 10032 MOVTrack *trackj= &mov->tracks[j];
8922
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 9918 times.
10032 if (j == i)
8923 114 continue;
8924
8925
2/2
✓ Branch 0 taken 9911 times.
✓ Branch 1 taken 7 times.
9918 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8926
4/4
✓ Branch 0 taken 9907 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 9900 times.
✓ Branch 3 taken 7 times.
19818 (trackj->par->ch_layout.nb_channels != 1 ||
8927 9907 !av_channel_layout_compare(&trackj->par->ch_layout,
8928 9907 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8929 )
8930 9904 track->mono_as_fc = -1;
8931
8932
4/4
✓ Branch 0 taken 9911 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 9900 times.
19829 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8933 9911 av_channel_layout_compare(&trackj->par->ch_layout,
8934 9911 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8935
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
8936 )
8937 7 track->mono_as_fc++;
8938
8939
4/4
✓ Branch 0 taken 9911 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 9900 times.
✓ Branch 3 taken 11 times.
19829 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8940 9911 av_channel_layout_compare(&trackj->par->ch_layout,
8941 9911 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8942
1/2
✓ Branch 0 taken 9900 times.
✗ Branch 1 not taken.
9900 trackj->language != track->language ||
8943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9900 times.
9900 trackj->tag != track->tag
8944 )
8945 18 continue;
8946 9900 track->multichannel_as_mono++;
8947 }
8948 }
8949
8950
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 231 times.
252 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8952
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 231 times.
231 if ((ret = mov_write_identification(pb, s)) < 0)
8953 ✗ return ret;
8954 }
8955
8956
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 249 times.
252 if (mov->reserved_moov_size){
8957 3 mov->reserved_header_pos = avio_tell(pb);
8958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8959 ✗ avio_skip(pb, mov->reserved_moov_size);
8960 }
8961
8962
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 208 times.
252 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8963 /* If no fragmentation options have been set, set a default. */
8964
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 37 times.
44 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8965 FF_MOV_FLAG_FRAG_CUSTOM |
8966 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8967
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)
8968 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8969
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 42 times.
44 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8970 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8971
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8972 2 mov->mdat_pos = avio_tell(pb);
8973 // The free/wide header that later will be converted into an
8974 // mdat, covering the initial moov and all the fragments.
8975 2 avio_wb32(pb, 0);
8976
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8977 // Write an ftyp atom, hidden in a free/wide. This is neither
8978 // exposed while the file is written, as fragmented, nor when the
8979 // file is finalized into non-fragmented form. However, this allows
8980 // accessing a pristine, sequential ftyp+moov init segment, even
8981 // after the file is finalized. It also allows dumping the whole
8982 // contents of the mdat box, to get the fragmented form of the
8983 // file.
8984
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_identification(pb, s)) < 0)
8985 ✗ return ret;
8986 2 update_size(pb, mov->mdat_pos);
8987 }
8988
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 } else if (mov->mode != MODE_AVIF) {
8989
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 205 times.
208 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8990 3 mov->reserved_header_pos = avio_tell(pb);
8991 208 mov_write_mdat_tag(pb, mov);
8992 }
8993
8994 252 ff_parse_creation_time_metadata(s, &mov->time, 1);
8995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (mov->time)
8996 ✗ mov->time += 0x7C25B080; // 1970 based -> 1904 based
8997
8998
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->chapter_track)
8999
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9000 ✗ return ret;
9001
9002
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 251 times.
252 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
9003
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
9004
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
9005
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
9006 ✗ return ret;
9007 2 hint_track++;
9008 }
9009 }
9010 }
9011
9012
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 246 times.
252 if (mov->nb_meta_tmcd) {
9013 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
9014 "timecode", NULL, 0);
9015 /* Initialize the tmcd tracks */
9016
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
9017 8 AVStream *st = mov->tracks[i].st;
9018 8 t = global_tcr;
9019
9020
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
9021 AVTimecode tc;
9022
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
9023 ✗ t = av_dict_get(st->metadata, "timecode", NULL, 0);
9024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
9025 ✗ continue;
9026
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
9027 ✗ continue;
9028
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
9029 ✗ return ret;
9030 6 tmcd_track++;
9031 }
9032 }
9033 }
9034
9035 252 avio_flush(pb);
9036
9037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
252 if (mov->flags & FF_MOV_FLAG_ISML)
9038 ✗ mov_write_isml_manifest(pb, mov, s);
9039
9040
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 213 times.
252 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
9041
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
39 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
9042
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9043 ✗ return ret;
9044 18 mov->moov_written = 1;
9045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
9046 ✗ mov->reserved_header_pos = avio_tell(pb);
9047 }
9048
9049 252 return 0;
9050 }
9051
9052 32 static int get_moov_size(AVFormatContext *s)
9053 {
9054 int ret;
9055 AVIOContext *moov_buf;
9056 32 MOVMuxContext *mov = s->priv_data;
9057
9058
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
9059 ✗ return ret;
9060
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
9061 ✗ return ret;
9062 32 return ffio_close_null_buf(moov_buf);
9063 }
9064
9065 ✗ static int get_sidx_size(AVFormatContext *s)
9066 {
9067 int ret;
9068 AVIOContext *buf;
9069 ✗ MOVMuxContext *mov = s->priv_data;
9070
9071 ✗ if ((ret = ffio_open_null_buf(&buf)) < 0)
9072 ✗ return ret;
9073 ✗ mov_write_sidx_tags(buf, mov, -1, 0);
9074 ✗ return ffio_close_null_buf(buf);
9075 }
9076
9077 /*
9078 * This function gets the moov size if moved to the top of the file: the chunk
9079 * offset table can switch between stco (32-bit entries) to co64 (64-bit
9080 * entries) when the moov is moved to the beginning, so the size of the moov
9081 * would change. It also updates the chunk offset tables.
9082 */
9083 3 static int compute_moov_size(AVFormatContext *s)
9084 {
9085 int i, moov_size, moov_size2;
9086 3 MOVMuxContext *mov = s->priv_data;
9087
9088 3 moov_size = get_moov_size(s);
9089
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9090 ✗ return moov_size;
9091
9092
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
9093 8 mov->tracks[i].data_offset += moov_size;
9094
9095 3 moov_size2 = get_moov_size(s);
9096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
9097 ✗ return moov_size2;
9098
9099 /* if the size changed, we just switched from stco to co64 and need to
9100 * update the offsets */
9101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
9102 ✗ for (i = 0; i < mov->nb_tracks; i++)
9103 ✗ mov->tracks[i].data_offset += moov_size2 - moov_size;
9104
9105 3 return moov_size2;
9106 }
9107
9108 ✗ static int compute_sidx_size(AVFormatContext *s)
9109 {
9110 int i, sidx_size;
9111 ✗ MOVMuxContext *mov = s->priv_data;
9112
9113 ✗ sidx_size = get_sidx_size(s);
9114 ✗ if (sidx_size < 0)
9115 ✗ return sidx_size;
9116
9117 ✗ for (i = 0; i < mov->nb_tracks; i++)
9118 ✗ mov->tracks[i].data_offset += sidx_size;
9119
9120 ✗ return sidx_size;
9121 }
9122
9123 3 static int shift_data(AVFormatContext *s)
9124 {
9125 int moov_size;
9126 3 MOVMuxContext *mov = s->priv_data;
9127
9128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
9129 ✗ moov_size = compute_sidx_size(s);
9130 else
9131 3 moov_size = compute_moov_size(s);
9132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9133 ✗ return moov_size;
9134
9135 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
9136 }
9137
9138 210 static void mov_write_mdat_size(AVFormatContext *s)
9139 {
9140 210 MOVMuxContext *mov = s->priv_data;
9141 210 AVIOContext *pb = s->pb;
9142
9143 /* Write size of mdat tag */
9144
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 if (mov->mdat_size + 8 <= UINT32_MAX) {
9145 210 avio_seek(pb, mov->mdat_pos, SEEK_SET);
9146 210 avio_wb32(pb, mov->mdat_size + 8);
9147
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 208 times.
210 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
9148 2 ffio_wfourcc(pb, "mdat"); // overwrite the original free/wide into a mdat
9149 } else {
9150 /* overwrite 'wide' placeholder atom */
9151 ✗ avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
9152 /* special value: real atom size will be 64 bit value after
9153 * tag field */
9154 ✗ avio_wb32(pb, 1);
9155 ✗ ffio_wfourcc(pb, "mdat");
9156 ✗ avio_wb64(pb, mov->mdat_size + 16);
9157 }
9158 210 }
9159
9160 252 static int mov_write_trailer(AVFormatContext *s)
9161 {
9162 252 MOVMuxContext *mov = s->priv_data;
9163 252 AVIOContext *pb = s->pb;
9164 252 int res = 0;
9165 int i;
9166 int64_t moov_pos;
9167
9168 /*
9169 * Before actually writing the trailer, make sure that there are no
9170 * dangling subtitles, that need a terminating sample.
9171 */
9172
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 252 times.
674 for (i = 0; i < mov->nb_tracks; i++) {
9173 422 MOVTrack *trk = &mov->tracks[i];
9174
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 421 times.
422 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
9175
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
9176 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
9177 1 trk->last_sample_is_subtitle_end = 1;
9178 }
9179 }
9180
9181 //Also check for a buffered EAC3 packet
9182
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 252 times.
674 for (i = 0; i < mov->nb_tracks; i++) {
9183 422 MOVTrack *trk = &mov->tracks[i];
9184
2/2
✓ Branch 0 taken 418 times.
✓ Branch 1 taken 4 times.
422 if (trk->par->codec_id != AV_CODEC_ID_EAC3)
9185 418 continue;
9186 4 struct eac3_info *info = trk->eac3_priv;
9187
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 if (!info || !info->pkt || !info->pkt->size)
9188 4 continue;
9189
9190 ✗ av_packet_move_ref(mov->pkt, info->pkt);
9191 ✗ info->eof = 1;
9192 ✗ res = mov_write_single_packet(s, mov->pkt);
9193 ✗ if (res < 0)
9194 ✗ return res;
9195
9196 ✗ av_packet_unref(mov->pkt);
9197 }
9198
9199 // Check if we have any tracks that require squashing.
9200 // In that case, we'll have to write the packet here.
9201
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 252 times.
252 if ((res = mov_write_squashed_packets(s)) < 0)
9202 ✗ return res;
9203
9204 // If there were no chapters when the header was written, but there
9205 // are chapters now, write them in the trailer. This only works
9206 // when we are not doing fragments.
9207
4/4
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 207 times.
✓ Branch 3 taken 44 times.
252 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
9208
3/4
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 206 times.
207 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
9209 ✗ mov->chapter_track = mov->nb_tracks++;
9210 ✗ if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9211 ✗ return res;
9212 }
9213 }
9214
9215
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 208 times.
252 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
9216
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 42 times.
44 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9217
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 208 times.
210 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9218 2 mov_auto_flush_fragment(s, 1);
9219 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
9220
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
9221 4 MOVTrack *track = &mov->tracks[i];
9222 4 track->data_offset = 0;
9223 4 av_free(track->cluster);
9224 4 track->cluster = track->cluster_written;
9225 4 track->entry = track->entry_written;
9226 4 track->cluster_written = NULL;
9227 4 track->entry_written = 0;
9228 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
9229 }
9230 // Clear the empty_moov flag, as we do want the moov to include
9231 // all the samples at this point.
9232 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
9233 }
9234
9235 210 moov_pos = avio_tell(pb);
9236
9237
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 2 times.
210 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
9238 208 mov_write_mdat_size(s);
9239
9240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
9241
9242
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 207 times.
210 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
9243 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
9244 3 res = shift_data(s);
9245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
9246 ✗ return res;
9247 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9248
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9249 ✗ return res;
9250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 } else if (mov->reserved_moov_size > 0) {
9251 int64_t size;
9252 ✗ if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9253 ✗ return res;
9254 ✗ size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
9255 ✗ if (size < 8){
9256 ✗ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
9257 ✗ return AVERROR(EINVAL);
9258 }
9259 ✗ avio_wb32(pb, size);
9260 ✗ ffio_wfourcc(pb, "free");
9261 ✗ ffio_fill(pb, 0, size - 8);
9262 ✗ avio_seek(pb, moov_pos, SEEK_SET);
9263 } else {
9264
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
207 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9265 ✗ return res;
9266 }
9267
9268
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 208 times.
210 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9269 // With hybrid fragmentation, only write the mdat size (hiding
9270 // the original moov and all the fragments within the mdat)
9271 // after we've successfully written the complete moov, to avoid
9272 // risk for an unreadable file if writing the final moov fails.
9273 2 mov_write_mdat_size(s);
9274 }
9275
9276 210 res = 0;
9277 } else {
9278 42 mov_auto_flush_fragment(s, 1);
9279
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 42 times.
216 for (i = 0; i < mov->nb_tracks; i++)
9280 174 mov->tracks[i].data_offset = 0;
9281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
9282 int64_t end;
9283 ✗ av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
9284 ✗ res = shift_data(s);
9285 ✗ if (res < 0)
9286 ✗ return res;
9287 ✗ end = avio_tell(pb);
9288 ✗ avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9289 ✗ mov_write_sidx_tags(pb, mov, -1, 0);
9290 ✗ avio_seek(pb, end, SEEK_SET);
9291 }
9292
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 1 times.
42 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
9293 41 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
9294 41 res = mov_write_mfra_tag(pb, mov);
9295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (res < 0)
9296 ✗ return res;
9297 }
9298 }
9299
9300 252 return res;
9301 }
9302
9303 266 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
9304 const AVPacket *pkt)
9305 {
9306 266 int ret = 1;
9307
9308
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 247 times.
266 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
9309
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
19 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
9310 ✗ ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
9311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
9312 ✗ ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
9313 }
9314
9315 266 return ret;
9316 }
9317
9318 #if CONFIG_AVIF_MUXER
9319 ✗ static int avif_write_trailer(AVFormatContext *s)
9320 {
9321 ✗ AVIOContext *pb = s->pb;
9322 ✗ MOVMuxContext *mov = s->priv_data;
9323 int64_t pos_backup, extent_offsets[2];
9324 uint8_t *buf;
9325 int buf_size, moov_size;
9326
9327 ✗ if (mov->moov_written) return 0;
9328
9329 ✗ mov->is_animated_avif = s->streams[0]->nb_frames > 1;
9330 ✗ if (mov->is_animated_avif && mov->nb_streams > 1) {
9331 // For animated avif with alpha channel, we need to write a tref tag
9332 // with type "auxl".
9333 ✗ MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[1], MKTAG('a', 'u', 'x', 'l'));
9334 ✗ if (!tag)
9335 ✗ return AVERROR(ENOMEM);
9336
9337 ✗ int ret = mov_add_tref_id(mov, tag, 1);
9338 ✗ if (ret < 0)
9339 ✗ return ret;
9340 }
9341 ✗ mov_write_identification(pb, s);
9342 ✗ mov_write_meta_tag(pb, mov, s);
9343
9344 ✗ moov_size = get_moov_size(s);
9345 ✗ for (int i = 0; i < mov->nb_tracks; i++)
9346 ✗ mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
9347
9348 ✗ if (mov->is_animated_avif) {
9349 int ret;
9350 ✗ if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9351 ✗ return ret;
9352 }
9353
9354 ✗ buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
9355 ✗ avio_wb32(pb, buf_size + 8);
9356 ✗ ffio_wfourcc(pb, "mdat");
9357
9358 // The offset for the YUV planes is the starting position of mdat.
9359 ✗ extent_offsets[0] = avio_tell(pb);
9360 // The offset for alpha plane is YUV offset + YUV size.
9361 ✗ extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
9362
9363 ✗ avio_write(pb, buf, buf_size);
9364
9365 // write extent offsets.
9366 ✗ pos_backup = avio_tell(pb);
9367 ✗ for (int i = 0; i < mov->nb_streams; i++) {
9368 ✗ if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
9369 ✗ av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
9370 ✗ return AVERROR_INVALIDDATA;
9371 }
9372 ✗ avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
9373 ✗ avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
9374 }
9375 ✗ avio_seek(pb, pos_backup, SEEK_SET);
9376
9377 ✗ return 0;
9378 }
9379 #endif
9380
9381 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
9382 static const AVCodecTag codec_3gp_tags[] = {
9383 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
9384 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9385 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9386 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9387 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
9388 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
9389 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9390 { AV_CODEC_ID_NONE, 0 },
9391 };
9392 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
9393 #endif
9394
9395 static const AVCodecTag codec_mp4_tags[] = {
9396 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
9397 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
9398 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
9399 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
9400 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
9401 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
9402 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
9403 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
9404 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
9405 { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') },
9406 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
9407 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
9408 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
9409 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
9410 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
9411 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
9412 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
9413 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
9414 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
9415 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
9416 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
9417 { AV_CODEC_ID_AV1, MKTAG('d', 'a', 'v', '1') },
9418 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
9419 { AV_CODEC_ID_APPLE_APAC, MKTAG('a', 'p', 'a', 'c') },
9420 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
9421 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
9422 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
9423 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
9424 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
9425 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
9426 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
9427 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
9428 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
9429 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
9430 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
9431 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
9432 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
9433 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
9434 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
9435 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
9436 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
9437 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
9438 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
9439 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
9440
9441 /* ISO/IEC 23003-5 integer formats */
9442 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
9443 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
9444 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
9445 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
9446 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
9447 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
9448 /* ISO/IEC 23003-5 floating-point formats */
9449 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
9450 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
9451 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
9452 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
9453
9454 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
9455
9456 { AV_CODEC_ID_NONE, 0 },
9457 };
9458 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
9459 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
9460 #endif
9461
9462 static const AVCodecTag codec_ism_tags[] = {
9463 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
9464 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
9465 { AV_CODEC_ID_NONE , 0 },
9466 };
9467
9468 static const AVCodecTag codec_ipod_tags[] = {
9469 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9470 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9471 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9472 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
9473 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
9474 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9475 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
9476 { AV_CODEC_ID_NONE, 0 },
9477 };
9478
9479 static const AVCodecTag codec_f4v_tags[] = {
9480 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
9481 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9482 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9483 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
9484 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
9485 { AV_CODEC_ID_NONE, 0 },
9486 };
9487
9488 #if CONFIG_AVIF_MUXER
9489
9490 static const AVOption avif_options[] = {
9491 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
9492 { "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 },
9493 { NULL },
9494 };
9495 static const AVCodecTag codec_avif_tags[] = {
9496 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
9497 { AV_CODEC_ID_NONE, 0 },
9498 };
9499 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
9500
9501 static const AVClass mov_avif_muxer_class = {
9502 .class_name = "avif muxer",
9503 .item_name = av_default_item_name,
9504 .option = avif_options,
9505 .version = LIBAVUTIL_VERSION_INT,
9506 };
9507 #endif
9508
9509 #if CONFIG_MOV_MUXER
9510 const FFOutputFormat ff_mov_muxer = {
9511 .p.name = "mov",
9512 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
9513 .p.extensions = "mov",
9514 .priv_data_size = sizeof(MOVMuxContext),
9515 .p.audio_codec = AV_CODEC_ID_AAC,
9516 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9517 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9518 .init = mov_init,
9519 .write_header = mov_write_header,
9520 .write_packet = mov_write_packet,
9521 .write_trailer = mov_write_trailer,
9522 .deinit = mov_free,
9523 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9524 .p.codec_tag = (const AVCodecTag* const []){
9525 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
9526 },
9527 .check_bitstream = mov_check_bitstream,
9528 .p.priv_class = &mov_isobmff_muxer_class,
9529 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9530 };
9531 #endif
9532 #if CONFIG_TGP_MUXER
9533 const FFOutputFormat ff_tgp_muxer = {
9534 .p.name = "3gp",
9535 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9536 .p.extensions = "3gp",
9537 .priv_data_size = sizeof(MOVMuxContext),
9538 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9539 .p.video_codec = AV_CODEC_ID_H263,
9540 .init = mov_init,
9541 .write_header = mov_write_header,
9542 .write_packet = mov_write_packet,
9543 .write_trailer = mov_write_trailer,
9544 .deinit = mov_free,
9545 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9546 .p.codec_tag = codec_3gp_tags_list,
9547 .check_bitstream = mov_check_bitstream,
9548 .p.priv_class = &mov_isobmff_muxer_class,
9549 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9550 };
9551 #endif
9552 #if CONFIG_MP4_MUXER
9553 const FFOutputFormat ff_mp4_muxer = {
9554 .p.name = "mp4",
9555 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9556 .p.mime_type = "video/mp4",
9557 .p.extensions = "mp4",
9558 .priv_data_size = sizeof(MOVMuxContext),
9559 .p.audio_codec = AV_CODEC_ID_AAC,
9560 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9561 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9562 .init = mov_init,
9563 .write_header = mov_write_header,
9564 .write_packet = mov_write_packet,
9565 .write_trailer = mov_write_trailer,
9566 .deinit = mov_free,
9567 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9568 .p.codec_tag = mp4_codec_tags_list,
9569 .check_bitstream = mov_check_bitstream,
9570 .p.priv_class = &mov_isobmff_muxer_class,
9571 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9572 };
9573 #endif
9574 #if CONFIG_PSP_MUXER
9575 const FFOutputFormat ff_psp_muxer = {
9576 .p.name = "psp",
9577 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9578 .p.extensions = "mp4,psp",
9579 .priv_data_size = sizeof(MOVMuxContext),
9580 .p.audio_codec = AV_CODEC_ID_AAC,
9581 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9582 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9583 .init = mov_init,
9584 .write_header = mov_write_header,
9585 .write_packet = mov_write_packet,
9586 .write_trailer = mov_write_trailer,
9587 .deinit = mov_free,
9588 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9589 .p.codec_tag = mp4_codec_tags_list,
9590 .check_bitstream = mov_check_bitstream,
9591 .p.priv_class = &mov_isobmff_muxer_class,
9592 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9593 };
9594 #endif
9595 #if CONFIG_TG2_MUXER
9596 const FFOutputFormat ff_tg2_muxer = {
9597 .p.name = "3g2",
9598 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9599 .p.extensions = "3g2",
9600 .priv_data_size = sizeof(MOVMuxContext),
9601 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9602 .p.video_codec = AV_CODEC_ID_H263,
9603 .init = mov_init,
9604 .write_header = mov_write_header,
9605 .write_packet = mov_write_packet,
9606 .write_trailer = mov_write_trailer,
9607 .deinit = mov_free,
9608 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9609 .p.codec_tag = codec_3gp_tags_list,
9610 .check_bitstream = mov_check_bitstream,
9611 .p.priv_class = &mov_isobmff_muxer_class,
9612 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9613 };
9614 #endif
9615 #if CONFIG_IPOD_MUXER
9616 const FFOutputFormat ff_ipod_muxer = {
9617 .p.name = "ipod",
9618 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9619 .p.mime_type = "video/mp4",
9620 .p.extensions = "m4v,m4a,m4b",
9621 .priv_data_size = sizeof(MOVMuxContext),
9622 .p.audio_codec = AV_CODEC_ID_AAC,
9623 .p.video_codec = AV_CODEC_ID_H264,
9624 .init = mov_init,
9625 .write_header = mov_write_header,
9626 .write_packet = mov_write_packet,
9627 .write_trailer = mov_write_trailer,
9628 .deinit = mov_free,
9629 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9630 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9631 .check_bitstream = mov_check_bitstream,
9632 .p.priv_class = &mov_isobmff_muxer_class,
9633 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9634 };
9635 #endif
9636 #if CONFIG_ISMV_MUXER
9637 const FFOutputFormat ff_ismv_muxer = {
9638 .p.name = "ismv",
9639 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9640 .p.mime_type = "video/mp4",
9641 .p.extensions = "ismv,isma",
9642 .priv_data_size = sizeof(MOVMuxContext),
9643 .p.audio_codec = AV_CODEC_ID_AAC,
9644 .p.video_codec = AV_CODEC_ID_H264,
9645 .init = mov_init,
9646 .write_header = mov_write_header,
9647 .write_packet = mov_write_packet,
9648 .write_trailer = mov_write_trailer,
9649 .deinit = mov_free,
9650 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9651 .p.codec_tag = (const AVCodecTag* const []){
9652 codec_mp4_tags, codec_ism_tags, 0 },
9653 .check_bitstream = mov_check_bitstream,
9654 .p.priv_class = &mov_isobmff_muxer_class,
9655 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9656 };
9657 #endif
9658 #if CONFIG_F4V_MUXER
9659 const FFOutputFormat ff_f4v_muxer = {
9660 .p.name = "f4v",
9661 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9662 .p.mime_type = "application/f4v",
9663 .p.extensions = "f4v",
9664 .priv_data_size = sizeof(MOVMuxContext),
9665 .p.audio_codec = AV_CODEC_ID_AAC,
9666 .p.video_codec = AV_CODEC_ID_H264,
9667 .init = mov_init,
9668 .write_header = mov_write_header,
9669 .write_packet = mov_write_packet,
9670 .write_trailer = mov_write_trailer,
9671 .deinit = mov_free,
9672 .p.flags = AVFMT_GLOBALHEADER,
9673 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9674 .check_bitstream = mov_check_bitstream,
9675 .p.priv_class = &mov_isobmff_muxer_class,
9676 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9677 };
9678 #endif
9679 #if CONFIG_AVIF_MUXER
9680 const FFOutputFormat ff_avif_muxer = {
9681 .p.name = "avif",
9682 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9683 .p.mime_type = "image/avif",
9684 .p.extensions = "avif",
9685 .priv_data_size = sizeof(MOVMuxContext),
9686 .p.video_codec = AV_CODEC_ID_AV1,
9687 .init = mov_init,
9688 .write_header = mov_write_header,
9689 .write_packet = mov_write_packet,
9690 .write_trailer = avif_write_trailer,
9691 .deinit = mov_free,
9692 .p.flags = AVFMT_GLOBALHEADER,
9693 .p.codec_tag = codec_avif_tags_list,
9694 .p.priv_class = &mov_avif_muxer_class,
9695 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9696 };
9697 #endif
9698