FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2025-09-01 20:07:09
Exec Total Coverage
Lines: 3681 5488 67.1%
Functions: 174 228 76.3%
Branches: 2164 3771 57.4%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "apv.h"
41 #include "libavcodec/ac3_parser_internal.h"
42 #include "libavcodec/dnxhddata.h"
43 #include "libavcodec/flac.h"
44 #include "libavcodec/get_bits.h"
45
46 #include "libavcodec/internal.h"
47 #include "libavcodec/put_bits.h"
48 #include "libavcodec/vc1_common.h"
49 #include "libavcodec/raw.h"
50 #include "internal.h"
51 #include "libavutil/avstring.h"
52 #include "libavutil/channel_layout.h"
53 #include "libavutil/csp.h"
54 #include "libavutil/intfloat.h"
55 #include "libavutil/mathematics.h"
56 #include "libavutil/libm.h"
57 #include "libavutil/mem.h"
58 #include "libavutil/opt.h"
59 #include "libavutil/dict.h"
60 #include "libavutil/pixdesc.h"
61 #include "libavutil/stereo3d.h"
62 #include "libavutil/timecode.h"
63 #include "libavutil/dovi_meta.h"
64 #include "libavutil/uuid.h"
65 #include "hevc.h"
66 #include "rtpenc.h"
67 #include "nal.h"
68 #include "mov_chan.h"
69 #include "movenc_ttml.h"
70 #include "mux.h"
71 #include "rawutils.h"
72 #include "ttmlenc.h"
73 #include "version.h"
74 #include "vpcc.h"
75 #include "vvc.h"
76
77 static const AVOption options[] = {
78 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
79 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
80 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
82 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
84 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
85 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
87 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
88 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
89 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
90 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
91 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
92 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
104 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
105 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
106 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
107 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
116 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
117 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
118 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
119 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
120 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
121 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
122 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
124 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
125 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
128 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
129 { NULL },
130 };
131
132 static const AVClass mov_isobmff_muxer_class = {
133 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
134 .item_name = av_default_item_name,
135 .option = options,
136 .version = LIBAVUTIL_VERSION_INT,
137 };
138
139 static int get_moov_size(AVFormatContext *s);
140 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
141
142 29 static int utf8len(const uint8_t *b)
143 {
144 29 int len = 0;
145 int val;
146
2/2
✓ Branch 0 taken 552 times.
✓ Branch 1 taken 29 times.
581 while (*b) {
147
3/8
✓ Branch 0 taken 552 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 552 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 552 times.
552 GET_UTF8(val, *b++, return -1;)
148 552 len++;
149 }
150 29 return len;
151 }
152
153 //FIXME support 64 bit variant with wide placeholders
154 6393 static int64_t update_size(AVIOContext *pb, int64_t pos)
155 {
156 6393 int64_t curpos = avio_tell(pb);
157 6393 avio_seek(pb, pos, SEEK_SET);
158 6393 avio_wb32(pb, curpos - pos); /* rewrite size */
159 6393 avio_seek(pb, curpos, SEEK_SET);
160
161 6393 return curpos - pos;
162 }
163
164 343 static int co64_required(const MOVTrack *track)
165 {
166
3/4
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 249 times.
343 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
167 return 1;
168 343 return 0;
169 }
170
171 19436 static int is_cover_image(const AVStream *st)
172 {
173 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
174 * is encoded as sparse video track */
175
3/4
✓ Branch 0 taken 19436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 19424 times.
19436 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
176 }
177
178 6 static int rtp_hinting_needed(const AVStream *st)
179 {
180 /* Add hint tracks for each real audio and video stream */
181
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
182 return 0;
183
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
184
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
185 }
186
187 /* Chunk offset atom */
188 343 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
189 {
190 int i;
191 343 int mode64 = co64_required(track); // use 32 bit size variant if possible
192 343 int64_t pos = avio_tell(pb);
193 343 avio_wb32(pb, 0); /* size */
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
343 if (mode64)
195 ffio_wfourcc(pb, "co64");
196 else
197 343 ffio_wfourcc(pb, "stco");
198 343 avio_wb32(pb, 0); /* version & flags */
199 343 avio_wb32(pb, track->chunkCount); /* entry count */
200
2/2
✓ Branch 0 taken 13678 times.
✓ Branch 1 taken 343 times.
14021 for (i = 0; i < track->entry; i++) {
201
2/2
✓ Branch 0 taken 10571 times.
✓ Branch 1 taken 3107 times.
13678 if (!track->cluster[i].chunkNum)
202 10571 continue;
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3107 times.
3107 if (mode64 == 1)
204 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
205 else
206 3107 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
207 }
208 343 return update_size(pb, pos);
209 }
210
211 /* Sample size atom */
212 343 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
213 {
214 343 int equalChunks = 1;
215 343 int i, j, entries = 0, tst = -1, oldtst = -1;
216
217 343 int64_t pos = avio_tell(pb);
218 343 avio_wb32(pb, 0); /* size */
219 343 ffio_wfourcc(pb, "stsz");
220 343 avio_wb32(pb, 0); /* version & flags */
221
222
2/2
✓ Branch 0 taken 13678 times.
✓ Branch 1 taken 343 times.
14021 for (i = 0; i < track->entry; i++) {
223 13678 tst = track->cluster[i].size / track->cluster[i].entries;
224
4/4
✓ Branch 0 taken 13429 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 8736 times.
✓ Branch 3 taken 4693 times.
13678 if (oldtst != -1 && tst != oldtst)
225 8736 equalChunks = 0;
226 13678 oldtst = tst;
227 13678 entries += track->cluster[i].entries;
228 }
229
4/4
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 94 times.
456 if (equalChunks && track->entry) {
230
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
231 113 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
232 113 avio_wb32(pb, sSize); // sample size
233 113 avio_wb32(pb, entries); // sample count
234 } else {
235 230 avio_wb32(pb, 0); // sample size
236 230 avio_wb32(pb, entries); // sample count
237
2/2
✓ Branch 0 taken 9899 times.
✓ Branch 1 taken 230 times.
10129 for (i = 0; i < track->entry; i++) {
238
2/2
✓ Branch 0 taken 9899 times.
✓ Branch 1 taken 9899 times.
19798 for (j = 0; j < track->cluster[i].entries; j++) {
239 9899 avio_wb32(pb, track->cluster[i].size /
240 9899 track->cluster[i].entries);
241 }
242 }
243 }
244 343 return update_size(pb, pos);
245 }
246
247 /* Sample to chunk atom */
248 343 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
249 {
250 343 int index = 0, oldidx = -1, oldval = -1, i;
251 int64_t entryPos, curpos;
252
253 343 int64_t pos = avio_tell(pb);
254 343 avio_wb32(pb, 0); /* size */
255 343 ffio_wfourcc(pb, "stsc");
256 343 avio_wb32(pb, 0); // version & flags
257 343 entryPos = avio_tell(pb);
258 343 avio_wb32(pb, track->chunkCount); // entry count
259
2/2
✓ Branch 0 taken 13678 times.
✓ Branch 1 taken 343 times.
14021 for (i = 0; i < track->entry; i++) {
260
2/2
✓ Branch 0 taken 2283 times.
✓ Branch 1 taken 11395 times.
13678 if ((oldval != track->cluster[i].samples_in_chunk ||
261
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2282 times.
✓ Branch 2 taken 825 times.
✓ Branch 3 taken 10571 times.
13678 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
262 825 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
263 825 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
264 825 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
265 825 oldval = track->cluster[i].samples_in_chunk;
266 825 oldidx = track->cluster[i].stsd_index;
267 825 index++;
268 }
269 }
270 343 curpos = avio_tell(pb);
271 343 avio_seek(pb, entryPos, SEEK_SET);
272 343 avio_wb32(pb, index); // rewrite size
273 343 avio_seek(pb, curpos, SEEK_SET);
274
275 343 return update_size(pb, pos);
276 }
277
278 /* Sync sample atom */
279 59 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
280 {
281 int64_t curpos, entryPos;
282 59 int i, index = 0;
283 59 int64_t pos = avio_tell(pb);
284 59 avio_wb32(pb, 0); // size
285
1/2
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
59 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
286 59 avio_wb32(pb, 0); // version & flags
287 59 entryPos = avio_tell(pb);
288 59 avio_wb32(pb, track->entry); // entry count
289
2/2
✓ Branch 0 taken 3213 times.
✓ Branch 1 taken 59 times.
3272 for (i = 0; i < track->entry; i++) {
290
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 3004 times.
3213 if (track->cluster[i].flags & flag) {
291 209 avio_wb32(pb, i + 1);
292 209 index++;
293 }
294 }
295 59 curpos = avio_tell(pb);
296 59 avio_seek(pb, entryPos, SEEK_SET);
297 59 avio_wb32(pb, index); // rewrite size
298 59 avio_seek(pb, curpos, SEEK_SET);
299 59 return update_size(pb, pos);
300 }
301
302 /* Sample dependency atom */
303 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
304 {
305 int i;
306 uint8_t leading, dependent, reference, redundancy;
307 3 int64_t pos = avio_tell(pb);
308 3 avio_wb32(pb, 0); // size
309 3 ffio_wfourcc(pb, "sdtp");
310 3 avio_wb32(pb, 0); // version & flags
311
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
312 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
313 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
314
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
315 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
316 }
317
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
318 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
319 }
320 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
321 13 (reference << 2) | redundancy);
322 }
323 3 return update_size(pb, pos);
324 }
325
326 #if CONFIG_IAMFENC
327 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
328 {
329 AVIOContext *dyn_bc;
330 5 int64_t pos = avio_tell(pb);
331 5 uint8_t *dyn_buf = NULL;
332 int dyn_size;
333 5 int ret = avio_open_dyn_buf(&dyn_bc);
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
335 return ret;
336
337 5 avio_wb32(pb, 0);
338 5 ffio_wfourcc(pb, "iacb");
339 5 avio_w8(pb, 1); // configurationVersion
340
341 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
343 return ret;
344
345 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
346 5 ffio_write_leb(pb, dyn_size);
347 5 avio_write(pb, dyn_buf, dyn_size);
348 5 av_free(dyn_buf);
349
350 5 return update_size(pb, pos);
351 }
352 #endif
353
354 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
355 {
356 avio_wb32(pb, 0x11); /* size */
357 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
358 else ffio_wfourcc(pb, "damr");
359 ffio_wfourcc(pb, "FFMP");
360 avio_w8(pb, 0); /* decoder version */
361
362 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
363 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
364 avio_w8(pb, 0x01); /* Frames per sample */
365 return 0x11;
366 }
367
368 struct eac3_info {
369 AVPacket *pkt;
370 uint8_t ec3_done;
371 uint8_t num_blocks;
372
373 /* Layout of the EC3SpecificBox */
374 /* maximum bitrate */
375 uint16_t data_rate;
376 int8_t ac3_bit_rate_code;
377 /* number of independent substreams */
378 uint8_t num_ind_sub;
379 struct {
380 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
381 uint8_t fscod;
382 /* bit stream identification 5 bits */
383 uint8_t bsid;
384 /* one bit reserved */
385 /* audio service mixing (not supported yet) 1 bit */
386 /* bit stream mode 3 bits */
387 uint8_t bsmod;
388 /* audio coding mode 3 bits */
389 uint8_t acmod;
390 /* sub woofer on 1 bit */
391 uint8_t lfeon;
392 /* 3 bits reserved */
393 /* number of dependent substreams associated with this substream 4 bits */
394 uint8_t num_dep_sub;
395 /* channel locations of the dependent substream(s), if any, 9 bits */
396 uint16_t chan_loc;
397 /* if there is no dependent substream, then one bit reserved instead */
398 } substream[1]; /* TODO: support 8 independent substreams */
399 /* indicates the decoding complexity, 8 bits */
400 uint8_t complexity_index_type_a;
401 };
402
403 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
404 {
405 5 struct eac3_info *info = track->eac3_priv;
406 PutBitContext pbc;
407 uint8_t buf[3];
408
409
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!info || !info->ec3_done) {
410 av_log(s, AV_LOG_ERROR,
411 "Cannot write moov atom before AC3 packets."
412 " Set the delay_moov flag to fix this.\n");
413 return AVERROR(EINVAL);
414 }
415
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
417 av_log(s, AV_LOG_ERROR,
418 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
419 "ISOBMFF specification in ETSI TS 102 366!\n",
420 info->substream[0].bsid);
421 return AVERROR(EINVAL);
422 }
423
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
425 av_log(s, AV_LOG_ERROR,
426 "No valid AC3 bit rate code for data rate of %d!\n",
427 info->data_rate);
428 return AVERROR(EINVAL);
429 }
430
431 5 avio_wb32(pb, 11);
432 5 ffio_wfourcc(pb, "dac3");
433
434 5 init_put_bits(&pbc, buf, sizeof(buf));
435 5 put_bits(&pbc, 2, info->substream[0].fscod);
436 5 put_bits(&pbc, 5, info->substream[0].bsid);
437 5 put_bits(&pbc, 3, info->substream[0].bsmod);
438 5 put_bits(&pbc, 3, info->substream[0].acmod);
439 5 put_bits(&pbc, 1, info->substream[0].lfeon);
440 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
441 5 put_bits(&pbc, 5, 0); // reserved
442
443 5 flush_put_bits(&pbc);
444 5 avio_write(pb, buf, sizeof(buf));
445
446 5 return 11;
447 }
448
449 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
450 {
451 1039 AC3HeaderInfo *hdr = NULL;
452 struct eac3_info *info;
453 int num_blocks, ret;
454
455
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
456
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
457 return AVERROR(ENOMEM);
458
459 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
460 }
461 1039 info = track->eac3_priv;
462
463
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
1039 if (!info->pkt && !(info->pkt = av_packet_alloc()))
464 return AVERROR(ENOMEM);
465
466
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1038 times.
1039 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
468 goto end;
469
470 /* drop the packets until we see a good one */
471
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
472 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
473 1 ret = 0;
474 } else
475 ret = AVERROR_INVALIDDATA;
476 1 goto end;
477 }
478
479 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
480 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
481 hdr->ac3_bit_rate_code);
482 1038 info->complexity_index_type_a = hdr->complexity_index_type_a;
483
484 1038 num_blocks = hdr->num_blocks;
485
486
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
487 /* AC-3 substream must be the first one */
488
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
489 ret = AVERROR(EINVAL);
490 goto end;
491 }
492
493 /* this should always be the case, given that our AC-3 parser
494 * concatenates dependent frames to their independent parent */
495
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
496
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
497 /* substream ids must be incremental */
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
499 ret = AVERROR(EINVAL);
500 goto end;
501 }
502
503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
504 //info->num_ind_sub++;
505 avpriv_request_sample(mov->fc, "Multiple independent substreams");
506 ret = AVERROR_PATCHWELCOME;
507 goto end;
508
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
509
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 hdr->substreamid == 0 && info->substream[0].bsid) {
510 1 info->ec3_done = 1;
511 1 goto concatenate;
512 }
513 } else {
514 if (hdr->substreamid != 0) {
515 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
516 ret = AVERROR_PATCHWELCOME;
517 goto end;
518 }
519 }
520
521 /* fill the info needed for the "dec3" atom */
522 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
523 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
524 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
525 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
526 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
527
528
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
529 // with AC-3 we only require the information of a single packet,
530 // so we can finish as soon as the basic values of the bit stream
531 // have been set to the track's informational structure.
532 4 info->ec3_done = 1;
533 4 goto concatenate;
534 }
535
536 /* Parse dependent substream(s), if any */
537
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
538 int cumul_size = hdr->frame_size;
539 int parent = hdr->substreamid;
540
541 while (cumul_size != pkt->size) {
542 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
543 if (ret < 0)
544 goto end;
545 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
546 ret = AVERROR(EINVAL);
547 goto end;
548 }
549 info->substream[parent].num_dep_sub++;
550 ret /= 8;
551
552 /* get the dependent stream channel map, if exists */
553 if (hdr->channel_map_present)
554 info->substream[parent].chan_loc |= (hdr->channel_map >> 5) & 0x1f;
555 else
556 info->substream[parent].chan_loc |= hdr->channel_mode;
557 cumul_size += hdr->frame_size;
558 }
559 }
560 }
561
562 1033 concatenate:
563
2/4
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
1038 if (!info->num_blocks && num_blocks == 6) {
564 1038 ret = pkt->size;
565 1038 goto end;
566 }
567 else if (info->num_blocks + num_blocks > 6) {
568 ret = AVERROR_INVALIDDATA;
569 goto end;
570 }
571
572 if (!info->num_blocks) {
573 ret = av_packet_ref(info->pkt, pkt);
574 if (!ret)
575 info->num_blocks = num_blocks;
576 goto end;
577 } else {
578 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
579 goto end;
580 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
581 info->num_blocks += num_blocks;
582 info->pkt->duration += pkt->duration;
583 if (info->num_blocks != 6)
584 goto end;
585 av_packet_unref(pkt);
586 av_packet_move_ref(pkt, info->pkt);
587 info->num_blocks = 0;
588 }
589 ret = pkt->size;
590
591 1039 end:
592 1039 av_free(hdr);
593
594 1039 return ret;
595 }
596
597 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
598 {
599 PutBitContext pbc;
600 uint8_t *buf;
601 struct eac3_info *info;
602 int size, i;
603
604
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
605 av_log(s, AV_LOG_ERROR,
606 "Cannot write moov atom before EAC3 packets parsed.\n");
607 return AVERROR(EINVAL);
608 }
609
610 1 info = track->eac3_priv;
611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
612 1 buf = av_malloc(size);
613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
614 return AVERROR(ENOMEM);
615 }
616
617 1 init_put_bits(&pbc, buf, size);
618 1 put_bits(&pbc, 13, info->data_rate);
619 1 put_bits(&pbc, 3, info->num_ind_sub);
620
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
621 1 put_bits(&pbc, 2, info->substream[i].fscod);
622 1 put_bits(&pbc, 5, info->substream[i].bsid);
623 1 put_bits(&pbc, 1, 0); /* reserved */
624 1 put_bits(&pbc, 1, 0); /* asvc */
625 1 put_bits(&pbc, 3, info->substream[i].bsmod);
626 1 put_bits(&pbc, 3, info->substream[i].acmod);
627 1 put_bits(&pbc, 1, info->substream[i].lfeon);
628 1 put_bits(&pbc, 3, 0); /* reserved */
629 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
630
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
631 1 put_bits(&pbc, 1, 0); /* reserved */
632 } else {
633 put_bits(&pbc, 9, info->substream[i].chan_loc);
634 }
635 }
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (info->complexity_index_type_a) {
637 put_bits(&pbc, 7, 0); /* reserved */
638 put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
639 put_bits(&pbc, 8, info->complexity_index_type_a);
640 }
641 1 flush_put_bits(&pbc);
642 1 size = put_bytes_output(&pbc);
643
644 1 avio_wb32(pb, size + 8);
645 1 ffio_wfourcc(pb, "dec3");
646 1 avio_write(pb, buf, size);
647
648 1 av_free(buf);
649
650 1 return size;
651 }
652
653 /**
654 * This function writes extradata "as is".
655 * Extradata must be formatted like a valid atom (with size and tag).
656 */
657 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
658 {
659 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
660 12 return track->extradata_size[track->last_stsd_index];
661 }
662
663 static int mov_write_enda_tag(AVIOContext *pb)
664 {
665 avio_wb32(pb, 10);
666 ffio_wfourcc(pb, "enda");
667 avio_wb16(pb, 1); /* little endian */
668 return 10;
669 }
670
671 2 static int mov_write_enda_tag_be(AVIOContext *pb)
672 {
673 2 avio_wb32(pb, 10);
674 2 ffio_wfourcc(pb, "enda");
675 2 avio_wb16(pb, 0); /* big endian */
676 2 return 10;
677 }
678
679 330 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
680 {
681 330 int i = 3;
682 330 avio_w8(pb, tag);
683
2/2
✓ Branch 0 taken 990 times.
✓ Branch 1 taken 330 times.
1320 for (; i > 0; i--)
684 990 avio_w8(pb, (size >> (7 * i)) | 0x80);
685 330 avio_w8(pb, size & 0x7F);
686 330 }
687
688 223 static unsigned compute_avg_bitrate(MOVTrack *track)
689 {
690 223 uint64_t size = 0;
691 int i;
692
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 183 times.
223 if (!track->track_duration)
693 40 return 0;
694
2/2
✓ Branch 0 taken 9074 times.
✓ Branch 1 taken 183 times.
9257 for (i = 0; i < track->entry; i++)
695 9074 size += track->cluster[i].size;
696 183 return size * 8 * track->timescale / track->track_duration;
697 }
698
699 struct mpeg4_bit_rate_values {
700 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
701 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
702 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
703 };
704
705 223 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
706 {
707 446 const AVPacketSideData *sd = track->st ?
708 222 av_packet_side_data_get(track->st->codecpar->coded_side_data,
709 222 track->st->codecpar->nb_coded_side_data,
710
2/2
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 1 times.
223 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
711
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 189 times.
223 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
712 223 struct mpeg4_bit_rate_values bit_rates = { 0 };
713
714 223 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
715
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 89 times.
223 if (!bit_rates.avg_bit_rate) {
716 // if the average bit rate cannot be calculated at this point, such as
717 // in the case of fragmented MP4, utilize the following values as
718 // fall-back in priority order:
719 //
720 // 1. average bit rate property
721 // 2. bit rate (usually average over the whole clip)
722 // 3. maximum bit rate property
723
724
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
134 if (props && props->avg_bitrate) {
725 3 bit_rates.avg_bit_rate = props->avg_bitrate;
726
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 122 times.
131 } else if (track->par->bit_rate) {
727 9 bit_rates.avg_bit_rate = track->par->bit_rate;
728
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
122 } else if (props && props->max_bitrate) {
729 bit_rates.avg_bit_rate = props->max_bitrate;
730 }
731 }
732
733 // (FIXME should be max rate in any 1 sec window)
734 223 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
735 bit_rates.avg_bit_rate);
736
737 // utilize values from properties if we have them available
738
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 189 times.
223 if (props) {
739 // no avg_bitrate signals that the track is VBR
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!props->avg_bitrate)
741 bit_rates.avg_bit_rate = props->avg_bitrate;
742 34 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
743 props->max_bitrate);
744 34 bit_rates.buffer_size = props->buffer_size / 8;
745 }
746
747 223 return bit_rates;
748 }
749
750 83 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
751 {
752 83 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
753 83 int64_t pos = avio_tell(pb);
754 166 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
755
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 2 times.
83 5 + track->extradata_size[track->last_stsd_index] : 0;
756
757 83 avio_wb32(pb, 0); // size
758 83 ffio_wfourcc(pb, "esds");
759 83 avio_wb32(pb, 0); // Version
760
761 // ES descriptor
762 83 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
763 83 avio_wb16(pb, track->track_id);
764 83 avio_w8(pb, 0x00); // flags (= no flags)
765
766 // DecoderConfig descriptor
767 83 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
768
769 // Object type indication
770
1/2
✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
83 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 track->par->codec_id == AV_CODEC_ID_MP3) &&
772 track->par->sample_rate > 24000)
773 avio_w8(pb, 0x6B); // 11172-3
774 else
775 83 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
776
777 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
778 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
780 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
781
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 27 times.
83 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
782 56 avio_w8(pb, 0x15); // flags (= Audiostream)
783 else
784 27 avio_w8(pb, 0x11); // flags (= Visualstream)
785
786 83 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
787 83 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
788 83 avio_wb32(pb, bit_rates.avg_bit_rate);
789
790
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 2 times.
83 if (track->extradata_size[track->last_stsd_index]) {
791 // DecoderSpecific info descriptor
792 81 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
793 81 avio_write(pb, track->extradata[track->last_stsd_index],
794 81 track->extradata_size[track->last_stsd_index]);
795 }
796
797 // SL descriptor
798 83 put_descr(pb, 0x06, 1);
799 83 avio_w8(pb, 0x02);
800 83 return update_size(pb, pos);
801 }
802
803 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
804 {
805
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
806
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
807
2/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
154 codec_id == AV_CODEC_ID_PCM_F32LE ||
808 codec_id == AV_CODEC_ID_PCM_F64LE;
809 }
810
811 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
812 {
813
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
814
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
815
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
150 codec_id == AV_CODEC_ID_PCM_F32BE ||
816 codec_id == AV_CODEC_ID_PCM_F64BE;
817 }
818
819 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
820 {
821 int ret;
822 int64_t pos = avio_tell(pb);
823 avio_wb32(pb, 0);
824 avio_wl32(pb, track->tag); // store it byteswapped
825 track->par->codec_tag = av_bswap16(track->tag >> 16);
826 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
827 return ret;
828 return update_size(pb, pos);
829 }
830
831 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
832 {
833 int ret;
834 int64_t pos = avio_tell(pb);
835 avio_wb32(pb, 0);
836 ffio_wfourcc(pb, "wfex");
837 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
838 return ret;
839 return update_size(pb, pos);
840 }
841
842 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
843 {
844 int64_t pos = avio_tell(pb);
845 avio_wb32(pb, 0);
846 ffio_wfourcc(pb, "dfLa");
847 avio_w8(pb, 0); /* version */
848 avio_wb24(pb, 0); /* flags */
849
850 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
851 if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
852 return AVERROR_INVALIDDATA;
853
854 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
855 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
856 avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
857 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
858
859 return update_size(pb, pos);
860 }
861
862 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
863 {
864 int64_t pos = avio_tell(pb);
865 int channels, channel_map;
866 avio_wb32(pb, 0);
867 ffio_wfourcc(pb, "dOps");
868 avio_w8(pb, 0); /* Version */
869 if (track->extradata_size[track->last_stsd_index] < 19) {
870 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
871 return AVERROR_INVALIDDATA;
872 }
873 /* extradata contains an Ogg OpusHead, other than byte-ordering and
874 OpusHead's preceding magic/version, OpusSpecificBox is currently
875 identical. */
876 channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
877 channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
878
879 avio_w8(pb, channels); /* OuputChannelCount */
880 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
881 avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
882 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
883 avio_w8(pb, channel_map); /* ChannelMappingFamily */
884 /* Write the rest of the header out without byte-swapping. */
885 if (channel_map) {
886 if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
887 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
888 return AVERROR_INVALIDDATA;
889 }
890 avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
891 }
892
893 return update_size(pb, pos);
894 }
895
896 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
897 {
898 int64_t pos = avio_tell(pb);
899 int length;
900 avio_wb32(pb, 0);
901 ffio_wfourcc(pb, "dmlp");
902
903 if (track->extradata_size[track->last_stsd_index] < 20) {
904 av_log(s, AV_LOG_ERROR,
905 "Cannot write moov atom before TrueHD packets."
906 " Set the delay_moov flag to fix this.\n");
907 return AVERROR(EINVAL);
908 }
909
910 length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
911 if (length < 20 || length > track->extradata_size[track->last_stsd_index])
912 return AVERROR_INVALIDDATA;
913
914 // Only TrueHD is supported
915 if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
916 return AVERROR_INVALIDDATA;
917
918 avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
919 avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
920 avio_wb32(pb, 0); /* reserved */
921
922 return update_size(pb, pos);
923 }
924
925 69 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
926 {
927 69 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
928 69 AVChannelLayout ch_layout = { 0 };
929 int64_t pos;
930 int ambisonic_order, ambi_channels, non_diegetic_channels;
931 int i, ret;
932
933
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if (!str)
934 69 return 0;
935
936 ret = av_channel_layout_from_string(&ch_layout, str->value);
937 if (ret < 0) {
938 if (ret == AVERROR(EINVAL)) {
939 invalid:
940 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
941 ret = 0;
942 }
943 av_channel_layout_uninit(&ch_layout);
944 return ret;
945 }
946
947 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
948 goto invalid;
949
950 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
951 if (ambisonic_order < 0)
952 goto invalid;
953
954 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
955 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
956 if (non_diegetic_channels &&
957 (non_diegetic_channels != 2 ||
958 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
959 goto invalid;
960
961 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
962
963 pos = avio_tell(pb);
964
965 avio_wb32(pb, 0); // Size
966 ffio_wfourcc(pb, "SA3D");
967 avio_w8(pb, 0); // version
968 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
969 avio_wb32(pb, ambisonic_order); // ambisonic_order
970 avio_w8(pb, 0); // ambisonic_channel_ordering
971 avio_w8(pb, 0); // ambisonic_normalization
972 avio_wb32(pb, ch_layout.nb_channels); // num_channels
973 for (i = 0; i < ambi_channels; i++)
974 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
975 for (; i < ch_layout.nb_channels; i++)
976 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
977
978 av_channel_layout_uninit(&ch_layout);
979
980 return update_size(pb, pos);
981 }
982
983 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
984 {
985 uint32_t layout_tag, bitmap, *channel_desc;
986 40 int64_t pos = avio_tell(pb);
987 int num_desc, ret;
988
989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
990 return 0;
991
992 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
993 &bitmap, &channel_desc);
994
995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
996 if (ret == AVERROR(ENOSYS)) {
997 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
998 "lack of channel information\n");
999 ret = 0;
1000 }
1001
1002 return ret;
1003 }
1004
1005
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
40 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1007 1 channel_desc = av_malloc(sizeof(*channel_desc));
1008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1009 return AVERROR(ENOMEM);
1010
1011 1 layout_tag = 0;
1012 1 bitmap = 0;
1013 1 *channel_desc = 3; // channel label "Center"
1014 }
1015
1016
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1017
1018 40 avio_wb32(pb, 0); // Size
1019 40 ffio_wfourcc(pb, "chan"); // Type
1020 40 avio_w8(pb, 0); // Version
1021 40 avio_wb24(pb, 0); // Flags
1022 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1023 40 avio_wb32(pb, bitmap); // mChannelBitmap
1024 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1025
1026
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1027 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1028 3 avio_wb32(pb, 0); // mChannelFlags
1029 3 avio_wl32(pb, 0); // mCoordinates[0]
1030 3 avio_wl32(pb, 0); // mCoordinates[1]
1031 3 avio_wl32(pb, 0); // mCoordinates[2]
1032 }
1033
1034 40 av_free(channel_desc);
1035
1036 40 return update_size(pb, pos);
1037 }
1038
1039 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1040 {
1041 15 int64_t pos = avio_tell(pb);
1042
1043 15 avio_wb32(pb, 0); /* size */
1044 15 ffio_wfourcc(pb, "wave");
1045
1046
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1047 15 avio_wb32(pb, 12); /* size */
1048 15 ffio_wfourcc(pb, "frma");
1049 15 avio_wl32(pb, track->tag);
1050 }
1051
1052
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1053 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1054 3 avio_wb32(pb, 12); /* size */
1055 3 ffio_wfourcc(pb, "mp4a");
1056 3 avio_wb32(pb, 0);
1057 3 mov_write_esds_tag(pb, track);
1058
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1059 mov_write_enda_tag(pb);
1060
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1061 2 mov_write_enda_tag_be(pb);
1062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1063 mov_write_amr_tag(pb, track);
1064
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1065 1 mov_write_ac3_tag(s, pb, track);
1066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1067 mov_write_eac3_tag(s, pb, track);
1068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1069 track->par->codec_id == AV_CODEC_ID_QDM2) {
1070 9 mov_write_extradata_tag(pb, track);
1071 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1072 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1073 mov_write_ms_tag(s, pb, track);
1074 }
1075
1076 15 avio_wb32(pb, 8); /* size */
1077 15 avio_wb32(pb, 0); /* null tag */
1078
1079 15 return update_size(pb, pos);
1080 }
1081
1082 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1083 {
1084 uint8_t *unescaped;
1085 const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1086 track->extradata_size[track->last_stsd_index];
1087 int unescaped_size, seq_found = 0;
1088 int level = 0, interlace = 0;
1089 int packet_seq = track->vc1_info.packet_seq;
1090 int packet_entry = track->vc1_info.packet_entry;
1091 int slices = track->vc1_info.slices;
1092 PutBitContext pbc;
1093
1094 if (track->start_dts == AV_NOPTS_VALUE) {
1095 /* No packets written yet, vc1_info isn't authoritative yet. */
1096 /* Assume inline sequence and entry headers. */
1097 packet_seq = packet_entry = 1;
1098 av_log(NULL, AV_LOG_WARNING,
1099 "moov atom written before any packets, unable to write correct "
1100 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1101 }
1102
1103 unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1104 if (!unescaped)
1105 return AVERROR(ENOMEM);
1106 start = find_next_marker(track->extradata[track->last_stsd_index], end);
1107 for (next = start; next < end; start = next) {
1108 GetBitContext gb;
1109 int size;
1110 next = find_next_marker(start + 4, end);
1111 size = next - start - 4;
1112 if (size <= 0)
1113 continue;
1114 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1115 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1116 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1117 int profile = get_bits(&gb, 2);
1118 if (profile != PROFILE_ADVANCED) {
1119 av_free(unescaped);
1120 return AVERROR(ENOSYS);
1121 }
1122 seq_found = 1;
1123 level = get_bits(&gb, 3);
1124 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1125 * width, height */
1126 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1127 skip_bits(&gb, 1); /* broadcast */
1128 interlace = get_bits1(&gb);
1129 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1130 }
1131 }
1132 if (!seq_found) {
1133 av_free(unescaped);
1134 return AVERROR(ENOSYS);
1135 }
1136
1137 init_put_bits(&pbc, buf, 7);
1138 /* VC1DecSpecStruc */
1139 put_bits(&pbc, 4, 12); /* profile - advanced */
1140 put_bits(&pbc, 3, level);
1141 put_bits(&pbc, 1, 0); /* reserved */
1142 /* VC1AdvDecSpecStruc */
1143 put_bits(&pbc, 3, level);
1144 put_bits(&pbc, 1, 0); /* cbr */
1145 put_bits(&pbc, 6, 0); /* reserved */
1146 put_bits(&pbc, 1, !interlace); /* no interlace */
1147 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1148 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1149 put_bits(&pbc, 1, !slices); /* no slice code */
1150 put_bits(&pbc, 1, 0); /* no bframe */
1151 put_bits(&pbc, 1, 0); /* reserved */
1152
1153 /* framerate */
1154 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1155 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1156 else
1157 put_bits32(&pbc, 0xffffffff);
1158
1159 flush_put_bits(&pbc);
1160
1161 av_free(unescaped);
1162
1163 return 0;
1164 }
1165
1166 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1167 {
1168 uint8_t buf[7] = { 0 };
1169 int ret;
1170
1171 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1172 return ret;
1173
1174 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1175 ffio_wfourcc(pb, "dvc1");
1176 avio_write(pb, buf, sizeof(buf));
1177 avio_write(pb, track->extradata[track->last_stsd_index],
1178 track->extradata_size[track->last_stsd_index]);
1179
1180 return 0;
1181 }
1182
1183 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1184 {
1185 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1186 4 ffio_wfourcc(pb, "glbl");
1187 4 avio_write(pb, track->extradata[track->last_stsd_index],
1188 4 track->extradata_size[track->last_stsd_index]);
1189 4 return 8 + track->extradata_size[track->last_stsd_index];
1190 }
1191
1192 /**
1193 * Compute flags for 'lpcm' tag.
1194 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1195 */
1196 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1197 {
1198
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 switch (codec_id) {
1199 case AV_CODEC_ID_PCM_F32BE:
1200 case AV_CODEC_ID_PCM_F64BE:
1201 return 11;
1202 case AV_CODEC_ID_PCM_F32LE:
1203 case AV_CODEC_ID_PCM_F64LE:
1204 return 9;
1205 case AV_CODEC_ID_PCM_U8:
1206 return 10;
1207 case AV_CODEC_ID_PCM_S16BE:
1208 case AV_CODEC_ID_PCM_S24BE:
1209 case AV_CODEC_ID_PCM_S32BE:
1210 return 14;
1211 case AV_CODEC_ID_PCM_S8:
1212 case AV_CODEC_ID_PCM_S16LE:
1213 case AV_CODEC_ID_PCM_S24LE:
1214 case AV_CODEC_ID_PCM_S32LE:
1215 return 12;
1216 8 default:
1217 8 return 0;
1218 }
1219 }
1220
1221 25581 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1222 {
1223 int64_t next_dts;
1224
1225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25581 times.
25581 if (cluster_idx >= track->entry)
1226 return 0;
1227
1228
2/2
✓ Branch 0 taken 664 times.
✓ Branch 1 taken 24917 times.
25581 if (cluster_idx + 1 == track->entry)
1229 664 next_dts = track->track_duration + track->start_dts;
1230 else
1231 24917 next_dts = track->cluster[cluster_idx + 1].dts;
1232
1233 25581 next_dts -= track->cluster[cluster_idx].dts;
1234
1235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25581 times.
25581 av_assert0(next_dts >= 0);
1236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25581 times.
25581 av_assert0(next_dts <= INT_MAX);
1237
1238 25581 return next_dts;
1239 }
1240
1241 4 static int get_samples_per_packet(MOVTrack *track)
1242 {
1243 int i, first_duration;
1244
1245 /* use 1 for raw PCM */
1246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1247 return 1;
1248
1249 /* check to see if duration is constant for all clusters */
1250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1251 return 0;
1252 4 first_duration = get_cluster_duration(track, 0);
1253
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1254
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1255 4 return 0;
1256 }
1257 return first_duration;
1258 }
1259
1260 140 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1261 {
1262 140 int64_t pos = avio_tell(pb);
1263 140 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1264
3/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
140 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1265
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 !bit_rates.buffer_size)
1266 // no useful data to be written, skip
1267 81 return 0;
1268
1269 59 avio_wb32(pb, 0); /* size */
1270 59 ffio_wfourcc(pb, "btrt");
1271
1272 59 avio_wb32(pb, bit_rates.buffer_size);
1273 59 avio_wb32(pb, bit_rates.max_bit_rate);
1274 59 avio_wb32(pb, bit_rates.avg_bit_rate);
1275
1276 59 return update_size(pb, pos);
1277 }
1278
1279 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1280 {
1281 7 int64_t pos = avio_tell(pb);
1282 7 int config = 0;
1283 int ret;
1284 7 uint8_t *speaker_pos = NULL;
1285 7 const AVChannelLayout *layout = &track->par->ch_layout;
1286
1287 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1288
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
7 if (ret || !config) {
1289 4 config = 0;
1290 4 speaker_pos = av_malloc(layout->nb_channels);
1291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1292 return AVERROR(ENOMEM);
1293 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1294 4 speaker_pos, layout->nb_channels);
1295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1296 char buf[128] = {0};
1297
1298 av_freep(&speaker_pos);
1299 av_channel_layout_describe(layout, buf, sizeof(buf));
1300 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1301 return ret;
1302 }
1303 }
1304
1305 7 avio_wb32(pb, 0); /* size */
1306 7 ffio_wfourcc(pb, "chnl");
1307 7 avio_wb32(pb, 0); /* version & flags */
1308
1309 7 avio_w8(pb, 1); /* stream_structure */
1310 7 avio_w8(pb, config);
1311
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1312 3 avio_wb64(pb, 0);
1313 } else {
1314 4 avio_write(pb, speaker_pos, layout->nb_channels);
1315 4 av_freep(&speaker_pos);
1316 }
1317
1318 7 return update_size(pb, pos);
1319 }
1320
1321 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1322 {
1323 9 int64_t pos = avio_tell(pb);
1324 int format_flags;
1325 int sample_size;
1326
1327 9 avio_wb32(pb, 0); /* size */
1328 9 ffio_wfourcc(pb, "pcmC");
1329 9 avio_wb32(pb, 0); /* version & flags */
1330
1331 /* 0x01: indicates little-endian format */
1332 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1333
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1335
2/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1336 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1337 9 avio_w8(pb, format_flags);
1338 9 sample_size = track->par->bits_per_raw_sample;
1339
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1340 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1342 9 avio_w8(pb, sample_size);
1343
1344 9 return update_size(pb, pos);
1345 }
1346
1347 112 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1348 {
1349 112 int64_t pos = avio_tell(pb);
1350 112 int version = 0;
1351 112 uint32_t tag = track->tag;
1352 112 int ret = 0;
1353
1354
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
112 if (track->mode == MODE_MOV) {
1355
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
40 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1356
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1357 tag = AV_RL32("lpcm");
1358 4 version = 2;
1359
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
62 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1360 26 mov_pcm_be_gt16(track->par->codec_id) ||
1361
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1362
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1364 12 version = 1;
1365 }
1366 }
1367
1368 112 avio_wb32(pb, 0); /* size */
1369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (mov->encryption_scheme != MOV_ENC_NONE) {
1370 ffio_wfourcc(pb, "enca");
1371 } else {
1372 112 avio_wl32(pb, tag); // store it byteswapped
1373 }
1374 112 avio_wb32(pb, 0); /* Reserved */
1375 112 avio_wb16(pb, 0); /* Reserved */
1376 112 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1377
1378 /* SoundDescription */
1379 112 avio_wb16(pb, version); /* Version */
1380 112 avio_wb16(pb, 0); /* Revision level */
1381 112 avio_wb32(pb, 0); /* Reserved */
1382
1383
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 108 times.
112 if (version == 2) {
1384 4 avio_wb16(pb, 3);
1385 4 avio_wb16(pb, 16);
1386 4 avio_wb16(pb, 0xfffe);
1387 4 avio_wb16(pb, 0);
1388 4 avio_wb32(pb, 0x00010000);
1389 4 avio_wb32(pb, 72);
1390 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1391 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1392 4 avio_wb32(pb, 0x7F000000);
1393 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1394 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1395 4 avio_wb32(pb, track->sample_size);
1396 4 avio_wb32(pb, get_samples_per_packet(track));
1397 } else {
1398
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 72 times.
108 if (track->mode == MODE_MOV) {
1399 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1400
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1401
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1402 1 avio_wb16(pb, 8); /* bits per sample */
1403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1404 avio_wb16(pb, track->par->bits_per_coded_sample);
1405 else
1406 35 avio_wb16(pb, 16);
1407
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1408 } else { /* reserved for mp4/3gp */
1409
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
139 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1410 67 0 : track->par->ch_layout.nb_channels);
1411
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
72 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 track->par->codec_id == AV_CODEC_ID_ALAC) {
1413 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1414 } else {
1415 67 avio_wb16(pb, 16);
1416 }
1417 72 avio_wb16(pb, 0);
1418 }
1419
1420 108 avio_wb16(pb, 0); /* packet size (= 0) */
1421
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 103 times.
108 if (track->tag == MKTAG('i','a','m','f'))
1422 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1424 avio_wb16(pb, 48000);
1425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1426 avio_wb32(pb, track->par->sample_rate);
1427 else
1428
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
206 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1429 103 track->par->sample_rate : 0);
1430
1431
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1432 108 avio_wb16(pb, 0); /* Reserved */
1433 }
1434
1435
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 100 times.
112 if (version == 1) { /* SoundDescription V1 extended info */
1436
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
24 if (mov_pcm_le_gt16(track->par->codec_id) ||
1437 12 mov_pcm_be_gt16(track->par->codec_id))
1438 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1439 else
1440 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1441 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1442 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1443 12 avio_wb32(pb, 2); /* Bytes per sample */
1444 }
1445
1446
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
112 if (track->mode == MODE_MOV &&
1447
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1448
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1449
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1450
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1451
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1452
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1453
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1454
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1455
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
54 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1456
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1457 15 ret = mov_write_wave_tag(s, pb, track);
1458
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 44 times.
97 else if (track->tag == MKTAG('m','p','4','a'))
1459 53 ret = mov_write_esds_tag(pb, track);
1460 #if CONFIG_IAMFENC
1461
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 39 times.
44 else if (track->tag == MKTAG('i','a','m','f'))
1462 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1463 #endif
1464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1465 ret = mov_write_amr_tag(pb, track);
1466
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1467 4 ret = mov_write_ac3_tag(s, pb, track);
1468
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1469 1 ret = mov_write_eac3_tag(s, pb, track);
1470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1471 ret = mov_write_extradata_tag(pb, track);
1472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1473 ret = mov_write_wfex_tag(s, pb, track);
1474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1475 ret = mov_write_dfla_tag(pb, track);
1476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1477 ret = mov_write_dops_tag(s, pb, track);
1478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1479 ret = mov_write_dmlp_tag(s, pb, track);
1480
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
34 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1481
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1482 7 ret = mov_write_chnl_tag(s, pb, track);
1483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1484 return ret;
1485 9 ret = mov_write_pcmc_tag(s, pb, track);
1486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1487 ret = mov_write_glbl_tag(pb, track);
1488
1489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (ret < 0)
1490 return ret;
1491
1492
3/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
112 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1493
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
69 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1494 return ret;
1495 }
1496
1497
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
112 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1498
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1499 return ret;
1500 }
1501
1502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (mov->encryption_scheme != MOV_ENC_NONE
1503 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1504 return ret;
1505 }
1506
1507
3/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
181 if (mov->write_btrt &&
1508 69 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1509 return ret;
1510
1511 112 ret = update_size(pb, pos);
1512 112 return ret;
1513 }
1514
1515 static int mov_write_d263_tag(AVIOContext *pb)
1516 {
1517 avio_wb32(pb, 0xf); /* size */
1518 ffio_wfourcc(pb, "d263");
1519 ffio_wfourcc(pb, "FFMP");
1520 avio_w8(pb, 0); /* decoder version */
1521 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1522 avio_w8(pb, 0xa); /* level */
1523 avio_w8(pb, 0); /* profile */
1524 return 0xf;
1525 }
1526
1527 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1528 {
1529 1 int64_t pos = avio_tell(pb);
1530
1531 1 avio_wb32(pb, 0);
1532 1 ffio_wfourcc(pb, "av1C");
1533 1 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1534 1 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1535 1 return update_size(pb, pos);
1536 }
1537
1538 55 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1539 {
1540 55 int64_t pos = avio_tell(pb);
1541
1542 55 avio_wb32(pb, 0);
1543 55 ffio_wfourcc(pb, "avcC");
1544 55 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1545 55 track->extradata_size[track->last_stsd_index]);
1546 55 return update_size(pb, pos);
1547 }
1548
1549 /* AVS3 Intelligent Media Coding
1550 * Information Technology - Intelligent Media Coding
1551 * Part 6: Intelligent Media Format
1552 */
1553 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1554 {
1555 if (len < 4)
1556 return AVERROR_INVALIDDATA;
1557
1558 if (data[0] == 1) {
1559 // In Avs3DecoderConfigurationRecord format
1560 avio_write(pb, data, len);
1561 return 0;
1562 }
1563
1564 avio_w8(pb, 1); // version
1565 avio_wb16(pb, len); // sequence_header_length
1566 avio_write(pb, data, len); // sequence_header
1567 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1568
1569 return 0;
1570 }
1571
1572 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1573 {
1574 int64_t pos = avio_tell(pb);
1575 avio_wb32(pb, 0);
1576 ffio_wfourcc(pb, "av3c");
1577 mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1578 track->extradata_size[track->last_stsd_index]);
1579 return update_size(pb, pos);
1580 }
1581
1582 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1583 {
1584 int64_t pos = avio_tell(pb);
1585
1586 avio_wb32(pb, 0);
1587 ffio_wfourcc(pb, "vpcC");
1588 ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1589 track->extradata_size[track->last_stsd_index], track->par);
1590 return update_size(pb, pos);
1591 }
1592
1593 3 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1594 {
1595 3 int64_t pos = avio_tell(pb);
1596
1597 3 avio_wb32(pb, 0);
1598 3 ffio_wfourcc(pb, "hvcC");
1599
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1600 1 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1601 1 track->extradata_size[track->last_stsd_index], 1, s);
1602 else
1603 2 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1604 2 track->extradata_size[track->last_stsd_index], 0, s);
1605 3 return update_size(pb, pos);
1606 }
1607
1608 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1609 {
1610 1 int64_t pos = avio_tell(pb);
1611 int ret;
1612
1613 1 avio_wb32(pb, 0);
1614 1 ffio_wfourcc(pb, "lhvC");
1615
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1616 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1617 1 track->extradata_size[track->last_stsd_index], 1, s);
1618 else
1619 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1620 track->extradata_size[track->last_stsd_index], 0, s);
1621
1622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1623 avio_seek(pb, pos, SEEK_SET);
1624 return ret;
1625 }
1626
1627 1 return update_size(pb, pos);
1628 }
1629
1630 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1631 {
1632 1 int64_t pos = avio_tell(pb);
1633
1634 1 avio_wb32(pb, 0);
1635 1 ffio_wfourcc(pb, "evcC");
1636
1637
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1638 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1639 1 track->extradata_size[track->last_stsd_index], 1);
1640 else
1641 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1642 track->extradata_size[track->last_stsd_index], 0);
1643
1644 1 return update_size(pb, pos);
1645 }
1646
1647 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1648 {
1649 1 int64_t pos = avio_tell(pb);
1650
1651 1 avio_wb32(pb, 0);
1652 1 ffio_wfourcc(pb, "vvcC");
1653
1654 1 avio_w8 (pb, 0); /* version */
1655 1 avio_wb24(pb, 0); /* flags */
1656
1657
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1658 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1659 1 track->extradata_size[track->last_stsd_index], 1);
1660 else
1661 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1662 track->extradata_size[track->last_stsd_index], 0);
1663 1 return update_size(pb, pos);
1664 }
1665
1666 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1667 {
1668 1 int64_t pos = avio_tell(pb);
1669
1670 1 avio_wb32(pb, 0);
1671 1 ffio_wfourcc(pb, "apvC");
1672
1673 1 avio_w8 (pb, 0); /* version */
1674 1 avio_wb24(pb, 0); /* flags */
1675
1676 1 ff_isom_write_apvc(pb, track->apv, s);
1677
1678 1 return update_size(pb, pos);
1679 }
1680
1681 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1682 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1683 {
1684 int interlaced;
1685 int cid;
1686 23 int display_width = track->par->width;
1687
1688
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) {
1689
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) {
1690 /* looks like a DNxHD bit stream */
1691 23 interlaced = (track->extradata[track->last_stsd_index][5] & 2);
1692 23 cid = AV_RB32(track->extradata[track->last_stsd_index] + 0x28);
1693 } else {
1694 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1695 return 0;
1696 }
1697 } else {
1698 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1699 return 0;
1700 }
1701
1702 23 avio_wb32(pb, 24); /* size */
1703 23 ffio_wfourcc(pb, "ACLR");
1704 23 ffio_wfourcc(pb, "ACLR");
1705 23 ffio_wfourcc(pb, "0001");
1706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1707 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1708 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1709 } else { /* Full range (0-255) */
1710 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1711 }
1712 23 avio_wb32(pb, 0); /* unknown */
1713
1714
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1715 12 avio_wb32(pb, 32);
1716 12 ffio_wfourcc(pb, "ADHR");
1717 12 ffio_wfourcc(pb, "0001");
1718 12 avio_wb32(pb, cid);
1719 12 avio_wb32(pb, 0); /* unknown */
1720 12 avio_wb32(pb, 1); /* unknown */
1721 12 avio_wb32(pb, 0); /* unknown */
1722 12 avio_wb32(pb, 0); /* unknown */
1723 12 return 0;
1724 }
1725
1726 11 avio_wb32(pb, 24); /* size */
1727 11 ffio_wfourcc(pb, "APRG");
1728 11 ffio_wfourcc(pb, "APRG");
1729 11 ffio_wfourcc(pb, "0001");
1730 11 avio_wb32(pb, 1); /* unknown */
1731 11 avio_wb32(pb, 0); /* unknown */
1732
1733 11 avio_wb32(pb, 120); /* size */
1734 11 ffio_wfourcc(pb, "ARES");
1735 11 ffio_wfourcc(pb, "ARES");
1736 11 ffio_wfourcc(pb, "0001");
1737 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1739 && track->par->sample_aspect_ratio.den > 0)
1740 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1741 11 avio_wb32(pb, display_width);
1742 /* values below are based on samples created with quicktime and avid codecs */
1743
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1744 11 avio_wb32(pb, track->par->height / 2);
1745 11 avio_wb32(pb, 2); /* unknown */
1746 11 avio_wb32(pb, 0); /* unknown */
1747 11 avio_wb32(pb, 4); /* unknown */
1748 } else {
1749 avio_wb32(pb, track->par->height);
1750 avio_wb32(pb, 1); /* unknown */
1751 avio_wb32(pb, 0); /* unknown */
1752 if (track->par->height == 1080)
1753 avio_wb32(pb, 5); /* unknown */
1754 else
1755 avio_wb32(pb, 6); /* unknown */
1756 }
1757 /* padding */
1758 11 ffio_fill(pb, 0, 10 * 8);
1759
1760 11 return 0;
1761 }
1762
1763 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1764 {
1765 avio_wb32(pb, 12);
1766 ffio_wfourcc(pb, "DpxE");
1767 if (track->extradata_size[track->last_stsd_index] >= 12 &&
1768 !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1769 avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1770 } else {
1771 avio_wb32(pb, 1);
1772 }
1773 return 0;
1774 }
1775
1776 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1777 {
1778 int tag;
1779
1780
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1781
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1782
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');
1783 1 else tag = MKTAG('d','v','c',' ');
1784 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1785 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1786 else tag = MKTAG('d','v','p','p');
1787 } else if (track->par->height == 720) { /* HD 720 line */
1788 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1789 else tag = MKTAG('d','v','h','p');
1790 } else if (track->par->height == 1080) { /* HD 1080 line */
1791 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1792 else tag = MKTAG('d','v','h','6');
1793 } else {
1794 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1795 return 0;
1796 }
1797
1798 1 return tag;
1799 }
1800
1801 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1802 {
1803 3 AVRational rational_framerate = st->avg_frame_rate;
1804 3 int rate = 0;
1805
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1806 3 rate = av_q2d(rational_framerate);
1807 3 return rate;
1808 }
1809
1810 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1811 {
1812 1 int tag = track->par->codec_tag;
1813 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1814 1 AVStream *st = track->st;
1815 1 int rate = defined_frame_rate(s, st);
1816
1817
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1818 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1819
1820
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1821
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) {
1822 if (!interlaced) {
1823 if (rate == 24) tag = MKTAG('x','d','v','4');
1824 else if (rate == 25) tag = MKTAG('x','d','v','5');
1825 else if (rate == 30) tag = MKTAG('x','d','v','1');
1826 else if (rate == 50) tag = MKTAG('x','d','v','a');
1827 else if (rate == 60) tag = MKTAG('x','d','v','9');
1828 }
1829
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) {
1830 if (!interlaced) {
1831 if (rate == 24) tag = MKTAG('x','d','v','6');
1832 else if (rate == 25) tag = MKTAG('x','d','v','7');
1833 else if (rate == 30) tag = MKTAG('x','d','v','8');
1834 } else {
1835 if (rate == 25) tag = MKTAG('x','d','v','3');
1836 else if (rate == 30) tag = MKTAG('x','d','v','2');
1837 }
1838
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) {
1839 if (!interlaced) {
1840 if (rate == 24) tag = MKTAG('x','d','v','d');
1841 else if (rate == 25) tag = MKTAG('x','d','v','e');
1842 else if (rate == 30) tag = MKTAG('x','d','v','f');
1843 } else {
1844 if (rate == 25) tag = MKTAG('x','d','v','c');
1845 else if (rate == 30) tag = MKTAG('x','d','v','b');
1846 }
1847 }
1848 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1849 if (track->par->width == 1280 && track->par->height == 720) {
1850 if (!interlaced) {
1851 if (rate == 24) tag = MKTAG('x','d','5','4');
1852 else if (rate == 25) tag = MKTAG('x','d','5','5');
1853 else if (rate == 30) tag = MKTAG('x','d','5','1');
1854 else if (rate == 50) tag = MKTAG('x','d','5','a');
1855 else if (rate == 60) tag = MKTAG('x','d','5','9');
1856 }
1857 } else if (track->par->width == 1920 && track->par->height == 1080) {
1858 if (!interlaced) {
1859 if (rate == 24) tag = MKTAG('x','d','5','d');
1860 else if (rate == 25) tag = MKTAG('x','d','5','e');
1861 else if (rate == 30) tag = MKTAG('x','d','5','f');
1862 } else {
1863 if (rate == 25) tag = MKTAG('x','d','5','c');
1864 else if (rate == 30) tag = MKTAG('x','d','5','b');
1865 }
1866 }
1867 }
1868
1869 1 return tag;
1870 }
1871
1872 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1873 {
1874 2 int tag = track->par->codec_tag;
1875 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1876 2 AVStream *st = track->st;
1877 2 int rate = defined_frame_rate(s, st);
1878
1879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1880 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1881
1882
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
1883
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
1884 2 return tag;
1885
1886 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1887 if (track->par->width == 960 && track->par->height == 720) {
1888 if (!interlaced) {
1889 if (rate == 24) tag = MKTAG('a','i','5','p');
1890 else if (rate == 25) tag = MKTAG('a','i','5','q');
1891 else if (rate == 30) tag = MKTAG('a','i','5','p');
1892 else if (rate == 50) tag = MKTAG('a','i','5','q');
1893 else if (rate == 60) tag = MKTAG('a','i','5','p');
1894 }
1895 } else if (track->par->width == 1440 && track->par->height == 1080) {
1896 if (!interlaced) {
1897 if (rate == 24) tag = MKTAG('a','i','5','3');
1898 else if (rate == 25) tag = MKTAG('a','i','5','2');
1899 else if (rate == 30) tag = MKTAG('a','i','5','3');
1900 } else {
1901 if (rate == 50) tag = MKTAG('a','i','5','5');
1902 else if (rate == 60) tag = MKTAG('a','i','5','6');
1903 }
1904 }
1905 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1906 if (track->par->width == 1280 && track->par->height == 720) {
1907 if (!interlaced) {
1908 if (rate == 24) tag = MKTAG('a','i','1','p');
1909 else if (rate == 25) tag = MKTAG('a','i','1','q');
1910 else if (rate == 30) tag = MKTAG('a','i','1','p');
1911 else if (rate == 50) tag = MKTAG('a','i','1','q');
1912 else if (rate == 60) tag = MKTAG('a','i','1','p');
1913 }
1914 } else if (track->par->width == 1920 && track->par->height == 1080) {
1915 if (!interlaced) {
1916 if (rate == 24) tag = MKTAG('a','i','1','3');
1917 else if (rate == 25) tag = MKTAG('a','i','1','2');
1918 else if (rate == 30) tag = MKTAG('a','i','1','3');
1919 } else {
1920 if (rate == 25) tag = MKTAG('a','i','1','5');
1921 else if (rate == 50) tag = MKTAG('a','i','1','5');
1922 else if (rate == 60) tag = MKTAG('a','i','1','6');
1923 }
1924 } else if ( track->par->width == 4096 && track->par->height == 2160
1925 || track->par->width == 3840 && track->par->height == 2160
1926 || track->par->width == 2048 && track->par->height == 1080) {
1927 tag = MKTAG('a','i','v','x');
1928 }
1929 }
1930
1931 return tag;
1932 }
1933
1934 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1935 {
1936 int tag = track->par->codec_tag;
1937
1938 if (!tag)
1939 tag = MKTAG('e', 'v', 'c', '1');
1940
1941 return tag;
1942 }
1943
1944 static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
1945 {
1946 int tag = track->par->codec_tag;
1947
1948 if (!tag)
1949 tag = MKTAG('a', 'p', 'v', '1');
1950
1951 return tag;
1952 }
1953
1954
1955 static const struct {
1956 enum AVPixelFormat pix_fmt;
1957 uint32_t tag;
1958 unsigned bps;
1959 } mov_pix_fmt_tags[] = {
1960 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1961 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1962 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1963 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
1964 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
1965 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
1966 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1967 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1968 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1969 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1970 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1971 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1972 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1973 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1974 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1975 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1976 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1977 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1978 };
1979
1980 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1981 {
1982 23 int tag = MKTAG('A','V','d','n');
1983
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1984
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1985 12 tag = MKTAG('A','V','d','h');
1986 23 return tag;
1987 }
1988
1989 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1990 {
1991 17 int tag = track->par->codec_tag;
1992 int i;
1993 enum AVPixelFormat pix_fmt;
1994
1995
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++) {
1996
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1997 17 tag = mov_pix_fmt_tags[i].tag;
1998 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1999
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2000 5 break;
2001 }
2002 }
2003
2004 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2005 17 track->par->bits_per_coded_sample);
2006
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2008 track->par->format != AV_PIX_FMT_GRAY8 &&
2009 track->par->format != AV_PIX_FMT_NONE)
2010 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2011 av_get_pix_fmt_name(track->par->format));
2012 17 return tag;
2013 }
2014
2015 167 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2016 {
2017 167 unsigned int tag = track->par->codec_tag;
2018
2019 // "rtp " is used to distinguish internally created RTP-hint tracks
2020 // (with rtp_ctx) from other tracks.
2021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (tag == MKTAG('r','t','p',' '))
2022 tag = 0;
2023
3/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✓ Branch 3 taken 36 times.
167 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
2024
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 1 times.
131 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2025
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 17 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2026
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 track->par->codec_id == AV_CODEC_ID_H263 ||
2027
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2 times.
113 track->par->codec_id == AV_CODEC_ID_H264 ||
2028
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 23 times.
111 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2029
4/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 69 times.
175 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
2030 87 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2031
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2032 1 tag = mov_get_dv_codec_tag(s, track);
2033
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2034 17 tag = mov_get_rawvideo_codec_tag(s, track);
2035
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2036 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2037
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2038 2 tag = mov_get_h264_codec_tag(s, track);
2039
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2040 tag = mov_get_evc_codec_tag(s, track);
2041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2042 tag = mov_get_apv_codec_tag(s, track);
2043
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2044 23 tag = mov_get_dnxhd_codec_tag(s, track);
2045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2046 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2047 if (!tag) { // if no mac fcc found, try with Microsoft tags
2048 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2049 if (tag)
2050 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2051 "the file may be unplayable!\n");
2052 }
2053
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2054 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2056 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2057 if (ms_tag) {
2058 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2059 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2060 "the file may be unplayable!\n");
2061 }
2062 }
2063 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2064 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2065 }
2066
2067 167 return tag;
2068 }
2069
2070 static const AVCodecTag codec_cover_image_tags[] = {
2071 { AV_CODEC_ID_MJPEG, 0xD },
2072 { AV_CODEC_ID_PNG, 0xE },
2073 { AV_CODEC_ID_BMP, 0x1B },
2074 { AV_CODEC_ID_NONE, 0 },
2075 };
2076
2077 100 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2078 unsigned int tag, int codec_id)
2079 {
2080 int i;
2081
2082 /**
2083 * Check that tag + id is in the table
2084 */
2085
2/4
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
100 for (i = 0; tags && tags[i]; i++) {
2086 100 const AVCodecTag *codec_tags = tags[i];
2087
1/2
✓ Branch 0 taken 1435 times.
✗ Branch 1 not taken.
1435 while (codec_tags->id != AV_CODEC_ID_NONE) {
2088
2/2
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 1318 times.
1435 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2089
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 17 times.
117 codec_tags->id == codec_id)
2090 100 return codec_tags->tag;
2091 1335 codec_tags++;
2092 }
2093 }
2094 return 0;
2095 }
2096
2097 269 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2098 {
2099
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 267 times.
269 if (is_cover_image(track->st))
2100 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2101
2102
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 266 times.
267 if (track->mode == MODE_IPOD)
2103
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") &&
2104
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2105 1 !av_match_ext(s->url, "m4b"))
2106 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2107 "Quicktime/Ipod might not play the file\n");
2108
2109
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 100 times.
267 if (track->mode == MODE_MOV) {
2110 167 return mov_get_codec_tag(s, track);
2111 } else
2112 100 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2113 100 track->par->codec_id);
2114 }
2115
2116 /** Write uuid atom.
2117 * Needed to make file play in iPods running newest firmware
2118 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2119 */
2120 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2121 {
2122 avio_wb32(pb, 28);
2123 ffio_wfourcc(pb, "uuid");
2124 avio_wb32(pb, 0x6b6840f2);
2125 avio_wb32(pb, 0x5f244fc5);
2126 avio_wb32(pb, 0xba39a51b);
2127 avio_wb32(pb, 0xcf0323f3);
2128 avio_wb32(pb, 0x0);
2129 return 28;
2130 }
2131
2132 static const uint16_t fiel_data[] = {
2133 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2134 };
2135
2136 97 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2137 {
2138 97 unsigned mov_field_order = 0;
2139
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2140 97 mov_field_order = fiel_data[field_order];
2141 else
2142 return 0;
2143 97 avio_wb32(pb, 10);
2144 97 ffio_wfourcc(pb, "fiel");
2145 97 avio_wb16(pb, mov_field_order);
2146 97 return 10;
2147 }
2148
2149 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2150 {
2151 4 MOVMuxContext *mov = s->priv_data;
2152 4 int ret = AVERROR_BUG;
2153 4 int64_t pos = avio_tell(pb);
2154 4 avio_wb32(pb, 0); /* size */
2155 4 avio_wl32(pb, track->tag); // store it byteswapped
2156 4 avio_wb32(pb, 0); /* Reserved */
2157 4 avio_wb16(pb, 0); /* Reserved */
2158 4 avio_wb16(pb, 1); /* Data-reference index */
2159
2160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2161 mov_write_esds_tag(pb, track);
2162
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2163
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
2164 1 case MOV_ISMV_TTML_TAG:
2165 // ISMV dfxp requires no extradata.
2166 2 break;
2167 1 case MOV_MP4_TTML_TAG:
2168 // As specified in 14496-30, XMLSubtitleSampleEntry
2169 // Namespace
2170 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2171 // Empty schema_location
2172 1 avio_w8(pb, 0);
2173 // Empty auxiliary_mime_types
2174 1 avio_w8(pb, 0);
2175 1 break;
2176 default:
2177 av_log(NULL, AV_LOG_ERROR,
2178 "Unknown codec tag '%s' utilized for TTML stream with "
2179 "index %d (track id %d)!\n",
2180 av_fourcc2str(track->par->codec_tag), track->st->index,
2181 track->track_id);
2182 return AVERROR(EINVAL);
2183 }
2184
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2185 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2186
2187
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
8 if (mov->write_btrt &&
2188 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2189 return ret;
2190
2191 4 return update_size(pb, pos);
2192 }
2193
2194 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2195 {
2196 int8_t stereo_mode;
2197
2198 if (stereo_3d->flags != 0) {
2199 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2200 return 0;
2201 }
2202
2203 switch (stereo_3d->type) {
2204 case AV_STEREO3D_2D:
2205 stereo_mode = 0;
2206 break;
2207 case AV_STEREO3D_TOPBOTTOM:
2208 stereo_mode = 1;
2209 break;
2210 case AV_STEREO3D_SIDEBYSIDE:
2211 stereo_mode = 2;
2212 break;
2213 default:
2214 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2215 return 0;
2216 }
2217 avio_wb32(pb, 13); /* size */
2218 ffio_wfourcc(pb, "st3d");
2219 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2220 avio_w8(pb, stereo_mode);
2221 return 13;
2222 }
2223
2224 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2225 {
2226 int64_t sv3d_pos, svhd_pos, proj_pos;
2227 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2228
2229 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2230 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2231 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2232 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2233 return 0;
2234 }
2235
2236 sv3d_pos = avio_tell(pb);
2237 avio_wb32(pb, 0); /* size */
2238 ffio_wfourcc(pb, "sv3d");
2239
2240 svhd_pos = avio_tell(pb);
2241 avio_wb32(pb, 0); /* size */
2242 ffio_wfourcc(pb, "svhd");
2243 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2244 avio_put_str(pb, metadata_source);
2245 update_size(pb, svhd_pos);
2246
2247 proj_pos = avio_tell(pb);
2248 avio_wb32(pb, 0); /* size */
2249 ffio_wfourcc(pb, "proj");
2250
2251 avio_wb32(pb, 24); /* size */
2252 ffio_wfourcc(pb, "prhd");
2253 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2254 avio_wb32(pb, spherical_mapping->yaw);
2255 avio_wb32(pb, spherical_mapping->pitch);
2256 avio_wb32(pb, spherical_mapping->roll);
2257
2258 switch (spherical_mapping->projection) {
2259 case AV_SPHERICAL_EQUIRECTANGULAR:
2260 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2261 avio_wb32(pb, 28); /* size */
2262 ffio_wfourcc(pb, "equi");
2263 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2264 avio_wb32(pb, spherical_mapping->bound_top);
2265 avio_wb32(pb, spherical_mapping->bound_bottom);
2266 avio_wb32(pb, spherical_mapping->bound_left);
2267 avio_wb32(pb, spherical_mapping->bound_right);
2268 break;
2269 case AV_SPHERICAL_CUBEMAP:
2270 avio_wb32(pb, 20); /* size */
2271 ffio_wfourcc(pb, "cbmp");
2272 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2273 avio_wb32(pb, 0); /* layout */
2274 avio_wb32(pb, spherical_mapping->padding); /* padding */
2275 break;
2276 }
2277 update_size(pb, proj_pos);
2278
2279 return update_size(pb, sv3d_pos);
2280 }
2281
2282 5 static inline int64_t rescale_rational(AVRational q, int b)
2283 {
2284 5 return av_rescale(q.num, b, q.den);
2285 }
2286
2287 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2288 const AVStereo3D *stereo3d)
2289 {
2290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2291 return;
2292
2293 1 avio_wb32(pb, 12); /* size */
2294 1 ffio_wfourcc(pb, "hfov");
2295 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2296 }
2297
2298 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2299 const AVSphericalMapping *spherical_mapping)
2300 {
2301 1 avio_wb32(pb, 24); /* size */
2302 1 ffio_wfourcc(pb, "proj");
2303 1 avio_wb32(pb, 16); /* size */
2304 1 ffio_wfourcc(pb, "prji");
2305 1 avio_wb32(pb, 0); /* version + flags */
2306
2307
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) {
2308 1 case AV_SPHERICAL_RECTILINEAR:
2309 1 ffio_wfourcc(pb, "rect");
2310 1 break;
2311 case AV_SPHERICAL_EQUIRECTANGULAR:
2312 ffio_wfourcc(pb, "equi");
2313 break;
2314 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2315 ffio_wfourcc(pb, "hequ");
2316 break;
2317 case AV_SPHERICAL_FISHEYE:
2318 ffio_wfourcc(pb, "fish");
2319 break;
2320 default:
2321 av_assert0(0);
2322 }
2323 1 }
2324
2325 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2326 const AVStereo3D *stereo3d)
2327 {
2328 1 int64_t pos = avio_tell(pb);
2329 1 int view = 0;
2330
2331 1 avio_wb32(pb, 0); /* size */
2332 1 ffio_wfourcc(pb, "eyes");
2333
2334 // stri is mandatory
2335 1 avio_wb32(pb, 13); /* size */
2336 1 ffio_wfourcc(pb, "stri");
2337 1 avio_wb32(pb, 0); /* version + flags */
2338
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2339 case AV_STEREO3D_VIEW_LEFT:
2340 view |= 1 << 0;
2341 break;
2342 case AV_STEREO3D_VIEW_RIGHT:
2343 view |= 1 << 1;
2344 break;
2345 1 case AV_STEREO3D_VIEW_PACKED:
2346 1 view |= (1 << 0) | (1 << 1);
2347 1 break;
2348 }
2349 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2350 1 avio_w8(pb, view);
2351
2352 // hero is optional
2353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2354 avio_wb32(pb, 13); /* size */
2355 ffio_wfourcc(pb, "hero");
2356 avio_wb32(pb, 0); /* version + flags */
2357 avio_w8(pb, stereo3d->primary_eye);
2358 }
2359
2360 // it's not clear if cams is mandatory or optional
2361
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2362 1 avio_wb32(pb, 24); /* size */
2363 1 ffio_wfourcc(pb, "cams");
2364 1 avio_wb32(pb, 16); /* size */
2365 1 ffio_wfourcc(pb, "blin");
2366 1 avio_wb32(pb, 0); /* version + flags */
2367 1 avio_wb32(pb, stereo3d->baseline);
2368 }
2369
2370 // it's not clear if cmfy is mandatory or optional
2371
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2372 1 avio_wb32(pb, 24); /* size */
2373 1 ffio_wfourcc(pb, "cmfy");
2374 1 avio_wb32(pb, 16); /* size */
2375 1 ffio_wfourcc(pb, "dadj");
2376 1 avio_wb32(pb, 0); /* version + flags */
2377 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2378 }
2379
2380 1 return update_size(pb, pos);
2381 }
2382
2383 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2384 const AVStereo3D *stereo3d,
2385 const AVSphericalMapping *spherical_mapping)
2386 {
2387 int64_t pos;
2388
2389
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2391 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2392 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2393 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2394 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2395 spherical_mapping->projection);
2396 spherical_mapping = NULL;
2397 }
2398
2399
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2400
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2402 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2403 !stereo3d->baseline &&
2404 !stereo3d->horizontal_disparity_adjustment.num))) {
2405 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2406 stereo3d = NULL;
2407 }
2408
2409
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2410 return 0;
2411
2412 1 pos = avio_tell(pb);
2413 1 avio_wb32(pb, 0); /* size */
2414 1 ffio_wfourcc(pb, "vexu");
2415
2416
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2417 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2418
2419
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2420 1 mov_write_eyes_tag(s, pb, stereo3d);
2421
2422 1 return update_size(pb, pos);
2423 }
2424
2425 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2426 {
2427 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2428
2429 avio_wb32(pb, 32); /* size = 8 + 24 */
2430 if (dovi->dv_profile > 10)
2431 ffio_wfourcc(pb, "dvwC");
2432 else if (dovi->dv_profile > 7)
2433 ffio_wfourcc(pb, "dvvC");
2434 else
2435 ffio_wfourcc(pb, "dvcC");
2436
2437 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2438 avio_write(pb, buf, sizeof(buf));
2439
2440 return 32; /* 8 + 24 */
2441 }
2442
2443 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2444 uint32_t top, uint32_t bottom,
2445 uint32_t left, uint32_t right)
2446 {
2447 5 uint32_t cropped_width = track->par->width - left - right;
2448 5 uint32_t cropped_height = track->height - top - bottom;
2449 AVRational horizOff =
2450 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2451 5 (AVRational) { left, 1 });
2452 AVRational vertOff =
2453 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2454 5 (AVRational) { top, 1 });
2455
2456 5 avio_wb32(pb, 40);
2457 5 ffio_wfourcc(pb, "clap");
2458 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2459 5 avio_wb32(pb, 1); /* apertureWidthD */
2460 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2461 5 avio_wb32(pb, 1); /* apertureHeightD */
2462
2463 5 avio_wb32(pb, -horizOff.num);
2464 5 avio_wb32(pb, horizOff.den);
2465 5 avio_wb32(pb, -vertOff.num);
2466 5 avio_wb32(pb, vertOff.den);
2467
2468 5 return 40;
2469 }
2470
2471 11 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2472 {
2473 AVRational sar;
2474 11 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2475 11 track->par->sample_aspect_ratio.den, INT_MAX);
2476
2477 11 avio_wb32(pb, 16);
2478 11 ffio_wfourcc(pb, "pasp");
2479 11 avio_wb32(pb, sar.num);
2480 11 avio_wb32(pb, sar.den);
2481 11 return 16;
2482 }
2483
2484 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2485 {
2486 uint32_t gama = 0;
2487 if (gamma <= 0.0)
2488 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2489 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2490
2491 if (gamma > 1e-6) {
2492 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2493 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2494
2495 av_assert0(track->mode == MODE_MOV);
2496 avio_wb32(pb, 12);
2497 ffio_wfourcc(pb, "gama");
2498 avio_wb32(pb, gama);
2499 return 12;
2500 } else {
2501 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2502 }
2503 return 0;
2504 }
2505
2506 10 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2507 {
2508 10 int64_t pos = avio_tell(pb);
2509
2510 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2511 // Ref (MP4): ISO/IEC 14496-12:2012
2512
2513
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if (prefer_icc) {
2514 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2515 4 track->st->codecpar->nb_coded_side_data,
2516 AV_PKT_DATA_ICC_PROFILE);
2517
2518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2519 avio_wb32(pb, 12 + sd->size);
2520 ffio_wfourcc(pb, "colr");
2521 ffio_wfourcc(pb, "prof");
2522 avio_write(pb, sd->data, sd->size);
2523 return 12 + sd->size;
2524 }
2525 else {
2526 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2527 }
2528 }
2529
2530 /* We should only ever be called for MOV, MP4 and AVIF. */
2531
3/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2532 track->mode == MODE_AVIF);
2533
2534 10 avio_wb32(pb, 0); /* size */
2535 10 ffio_wfourcc(pb, "colr");
2536
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
10 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2537 2 ffio_wfourcc(pb, "nclx");
2538 else
2539 8 ffio_wfourcc(pb, "nclc");
2540 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2541 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2542 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2543 10 avio_wb16(pb, track->par->color_primaries);
2544 10 avio_wb16(pb, track->par->color_trc);
2545 10 avio_wb16(pb, track->par->color_space);
2546
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
10 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2547 2 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2548 2 avio_w8(pb, full_range << 7);
2549 }
2550
2551 10 return update_size(pb, pos);
2552 }
2553
2554 207 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2555 {
2556 const AVPacketSideData *side_data;
2557 const AVContentLightMetadata *content_light_metadata;
2558
2559 207 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2560 207 track->st->codecpar->nb_coded_side_data,
2561 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2562
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 if (!side_data) {
2563 207 return 0;
2564 }
2565 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2566
2567 avio_wb32(pb, 12); // size
2568 ffio_wfourcc(pb, "clli");
2569 avio_wb16(pb, content_light_metadata->MaxCLL);
2570 avio_wb16(pb, content_light_metadata->MaxFALL);
2571 return 12;
2572 }
2573
2574 207 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2575 {
2576 207 const int chroma_den = 50000;
2577 207 const int luma_den = 10000;
2578 const AVPacketSideData *side_data;
2579 207 const AVMasteringDisplayMetadata *metadata = NULL;
2580
2581 207 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2582 207 track->st->codecpar->nb_coded_side_data,
2583 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 if (side_data)
2585 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2586
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
207 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2587 207 return 0;
2588 }
2589
2590 avio_wb32(pb, 32); // size
2591 ffio_wfourcc(pb, "mdcv");
2592 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2593 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2594 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2595 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2596 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2597 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2598 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2599 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2600 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2601 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2602 return 32;
2603 }
2604
2605 207 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2606 {
2607 207 const int illuminance_den = 10000;
2608 207 const int ambient_den = 50000;
2609 const AVPacketSideData *side_data;
2610 const AVAmbientViewingEnvironment *ambient;
2611
2612
2613 207 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2614 207 track->st->codecpar->nb_coded_side_data,
2615 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2616
2617
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 1 times.
207 if (!side_data)
2618 206 return 0;
2619
2620 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2621
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)
2622 return 0;
2623
2624 1 avio_wb32(pb, 16); // size
2625 1 ffio_wfourcc(pb, "amve");
2626 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2627 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2628 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2629 1 return 16;
2630 }
2631
2632 212 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2633 {
2634 AVDictionaryEntry *encoder;
2635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2636
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
211 || (track->par->width == 1440 && track->par->height == 1080)
2637
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 211 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 198 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
424 || (track->par->width == 1920 && track->par->height == 1080);
2638
2639
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 if ((track->mode == MODE_AVIF ||
2640
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 140 times.
212 track->mode == MODE_MOV ||
2641
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 151 times.
✓ Branch 3 taken 56 times.
279 track->mode == MODE_MP4) &&
2642 207 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2643 151 av_strlcpy(compressor_name, encoder->value, 32);
2644
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
61 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2645 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2646 AVStream *st = track->st;
2647 int rate = defined_frame_rate(NULL, st);
2648 av_strlcatf(compressor_name, len, "XDCAM");
2649 if (track->par->format == AV_PIX_FMT_YUV422P) {
2650 av_strlcatf(compressor_name, len, " HD422");
2651 } else if(track->par->width == 1440) {
2652 av_strlcatf(compressor_name, len, " HD");
2653 } else
2654 av_strlcatf(compressor_name, len, " EX");
2655
2656 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2657
2658 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2659 }
2660 212 }
2661
2662 static int mov_write_ccst_tag(AVIOContext *pb)
2663 {
2664 int64_t pos = avio_tell(pb);
2665 // Write sane defaults:
2666 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2667 // intra_pred_used = 1 : intra prediction may or may not be used.
2668 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2669 // reference images can be used.
2670 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2671 (1 << 6) | /* intra_pred_used */
2672 (15 << 2); /* max_ref_per_pic */
2673 avio_wb32(pb, 0); /* size */
2674 ffio_wfourcc(pb, "ccst");
2675 avio_wb32(pb, 0); /* Version & flags */
2676 avio_w8(pb, ccstValue);
2677 avio_wb24(pb, 0); /* reserved */
2678 return update_size(pb, pos);
2679 }
2680
2681 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2682 {
2683 int64_t pos = avio_tell(pb);
2684 avio_wb32(pb, 0); /* size */
2685 ffio_wfourcc(pb, aux_type);
2686 avio_wb32(pb, 0); /* Version & flags */
2687 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2688 return update_size(pb, pos);
2689 }
2690
2691 212 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2692 {
2693 212 int ret = AVERROR_BUG;
2694 212 int64_t pos = avio_tell(pb);
2695 const AVPacketSideData *sd;
2696 212 char compressor_name[32] = { 0 };
2697 212 int avid = 0;
2698
2699
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)
2700
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
212 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2701
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
212 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2702
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
212 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2703
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
212 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2704 #if FF_API_V408_CODECID
2705
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 || track->par->codec_id == AV_CODEC_ID_V308
2706
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 || track->par->codec_id == AV_CODEC_ID_V408
2707
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 || track->par->codec_id == AV_CODEC_ID_V410
2708 #endif
2709
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 208 times.
424 || track->par->codec_id == AV_CODEC_ID_V210);
2710
2711 212 avio_wb32(pb, 0); /* size */
2712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (mov->encryption_scheme != MOV_ENC_NONE) {
2713 ffio_wfourcc(pb, "encv");
2714 } else {
2715 212 avio_wl32(pb, track->tag); // store it byteswapped
2716 }
2717 212 avio_wb32(pb, 0); /* Reserved */
2718 212 avio_wb16(pb, 0); /* Reserved */
2719 212 avio_wb16(pb, 1); /* Data-reference index */
2720
2721
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 208 times.
212 if (uncompressed_ycbcr) {
2722 4 avio_wb16(pb, 2); /* Codec stream version */
2723 } else {
2724 208 avio_wb16(pb, 0); /* Codec stream version */
2725 }
2726 212 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2727
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 72 times.
212 if (track->mode == MODE_MOV) {
2728 140 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2729
3/4
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
140 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2730 17 avio_wb32(pb, 0); /* Temporal Quality */
2731 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2732 } else {
2733 123 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2734 123 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2735 }
2736 } else {
2737 72 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2738 }
2739 212 avio_wb16(pb, track->par->width); /* Video width */
2740 212 avio_wb16(pb, track->height); /* Video height */
2741 212 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2742 212 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2743 212 avio_wb32(pb, 0); /* Data size (= 0) */
2744 212 avio_wb16(pb, 1); /* Frame count (= 1) */
2745
2746 212 find_compressor(compressor_name, 32, track);
2747 212 avio_w8(pb, strlen(compressor_name));
2748 212 avio_write(pb, compressor_name, 31);
2749
2750
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 72 times.
212 if (track->mode == MODE_MOV &&
2751
2/4
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 140 times.
140 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2752 avio_wb16(pb, 0x18);
2753
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 107 times.
212 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2754 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2755
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2756 else
2757 179 avio_wb16(pb, 0x18); /* Reserved */
2758
2759
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 135 times.
217 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2760 int pal_size, i;
2761 5 avio_wb16(pb, 0); /* Color table ID */
2762 5 avio_wb32(pb, 0); /* Color table seed */
2763 5 avio_wb16(pb, 0x8000); /* Color table flags */
2764
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)
2765 return AVERROR(EINVAL);
2766 5 pal_size = 1 << track->par->bits_per_coded_sample;
2767 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2768
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2769 1040 uint32_t rgb = track->palette[i];
2770 1040 uint16_t r = (rgb >> 16) & 0xff;
2771 1040 uint16_t g = (rgb >> 8) & 0xff;
2772 1040 uint16_t b = rgb & 0xff;
2773 1040 avio_wb16(pb, 0);
2774 1040 avio_wb16(pb, (r << 8) | r);
2775 1040 avio_wb16(pb, (g << 8) | g);
2776 1040 avio_wb16(pb, (b << 8) | b);
2777 }
2778 } else
2779 207 avio_wb16(pb, 0xffff); /* Reserved */
2780
2781
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 185 times.
212 if (track->tag == MKTAG('m','p','4','v'))
2782 27 mov_write_esds_tag(pb, track);
2783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 else if (track->par->codec_id == AV_CODEC_ID_H263)
2784 mov_write_d263_tag(pb);
2785
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 3 times.
185 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
182 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2787 3 mov_write_extradata_tag(pb, track);
2788 3 avio_wb32(pb, 0);
2789
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 159 times.
182 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2790 23 mov_write_avid_tag(pb, track);
2791 23 avid = 1;
2792
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 156 times.
159 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2793 3 mov_write_hvcc_tag(mov->fc, pb, track);
2794
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2795 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2797 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2798 }
2799
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 155 times.
156 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2800 1 mov_write_vvcc_tag(pb, track);
2801
16/30
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 55 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 55 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 55 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 55 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 55 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 55 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 55 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 55 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 55 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 55 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 55 times.
✗ Branch 29 not taken.
155 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2802 55 mov_write_avcc_tag(pb, track);
2803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (track->mode == MODE_IPOD)
2804 mov_write_uuid_tag_ipod(pb);
2805 }
2806
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2807 1 mov_write_evcc_tag(pb, track);
2808
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 98 times.
99 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2809 1 mov_write_apvc_tag(mov->fc, pb, track);
2810
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2811 mov_write_vpcc_tag(mov->fc, pb, track);
2812
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97 times.
98 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2813 1 mov_write_av1c_tag(pb, track);
2814
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)
2815 mov_write_dvc1_tag(pb, track);
2816
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2817
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2818 /* Don't write any potential extradata here - the cropping
2819 * is signalled via the normal width/height fields. */
2820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2821 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2822 mov_write_dpxe_tag(pb, track);
2823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2824 mov_write_av3c_tag(pb, track);
2825
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
2826 4 mov_write_glbl_tag(pb, track);
2827
2828
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 55 times.
212 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2829
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 25 times.
157 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2830
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 23 times.
132 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2831 109 int field_order = track->par->field_order;
2832
2833
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 12 times.
109 if (field_order != AV_FIELD_UNKNOWN)
2834 97 mov_write_fiel_tag(pb, track, field_order);
2835 }
2836
2837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2838 if (track->mode == MODE_MOV)
2839 mov_write_gama_tag(s, pb, track, mov->gamma);
2840 else
2841 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2842 }
2843
5/6
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 67 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
419 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2844 420 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2845
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
213 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2846
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2847
5/6
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 197 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 197 times.
404 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2848 197 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2849 AV_PKT_DATA_ICC_PROFILE)) {
2850
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 6 times.
10 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2851 10 mov_write_colr_tag(pb, track, prefer_icc);
2852 }
2853
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2854 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2855 }
2856
2857
4/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 5 times.
212 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2858 207 mov_write_clli_tag(pb, track);
2859 207 mov_write_mdcv_tag(pb, track);
2860 207 mov_write_amve_tag(pb, track);
2861 }
2862
2863
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
212 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2864 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2865 track->st->codecpar->nb_coded_side_data,
2866 AV_PKT_DATA_STEREO3D);
2867 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2868 track->st->codecpar->nb_coded_side_data,
2869 AV_PKT_DATA_SPHERICAL);
2870 if (stereo_3d)
2871 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2872 if (spherical_mapping)
2873 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2874 }
2875
2876
4/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 5 times.
212 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2878 140 const AVStereo3D *stereo3d = NULL;
2879 140 const AVSphericalMapping *spherical_mapping = NULL;
2880
2881 140 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2882 140 track->st->codecpar->nb_coded_side_data,
2883 AV_PKT_DATA_STEREO3D);
2884
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (sd)
2885 1 stereo3d = (AVStereo3D *)sd->data;
2886
2887 140 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2888 140 track->st->codecpar->nb_coded_side_data,
2889 AV_PKT_DATA_SPHERICAL);
2890
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (sd)
2891 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2892
2893
3/4
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
140 if (stereo3d || spherical_mapping)
2894 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2895
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 if (stereo3d)
2896 1 mov_write_hfov_tag(s, pb, stereo3d);
2897 }
2898
2899
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 145 times.
212 if (track->mode == MODE_MP4) {
2900 67 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2901 67 track->st->codecpar->nb_coded_side_data,
2902 AV_PKT_DATA_DOVI_CONF);
2903
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
67 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2904 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 } else if (dovi) {
2906 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2907 }
2908 }
2909
2910
3/4
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 201 times.
212 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2911 11 mov_write_pasp_tag(pb, track);
2912 }
2913
2914 212 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2915 212 track->st->codecpar->nb_coded_side_data,
2916 AV_PKT_DATA_FRAME_CROPPING);
2917
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 211 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
213 if (sd && sd->size >= sizeof(uint32_t) * 4) {
2918 1 uint64_t top = AV_RL32(sd->data + 0);
2919 1 uint64_t bottom = AV_RL32(sd->data + 4);
2920 1 uint64_t left = AV_RL32(sd->data + 8);
2921 1 uint64_t right = AV_RL32(sd->data + 12);
2922
2923
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2925 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2926 return AVERROR(EINVAL);
2927 }
2928
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)
2929 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2930
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 207 times.
211 } else if (uncompressed_ycbcr)
2931 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2932
2933
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (mov->encryption_scheme != MOV_ENC_NONE) {
2934 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2935 }
2936
2937
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
279 if (mov->write_btrt &&
2938 67 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2939 return ret;
2940
2941 /* extra padding for avid stsd */
2942 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2943
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 189 times.
212 if (avid)
2944 23 avio_wb32(pb, 0);
2945
2946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (track->mode == MODE_AVIF) {
2947 mov_write_ccst_tag(pb);
2948 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2949 mov_write_aux_tag(pb, "auxi");
2950 }
2951
2952 212 return update_size(pb, pos);
2953 }
2954
2955 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2956 {
2957 2 int64_t pos = avio_tell(pb);
2958 2 avio_wb32(pb, 0); /* size */
2959 2 ffio_wfourcc(pb, "rtp ");
2960 2 avio_wb32(pb, 0); /* Reserved */
2961 2 avio_wb16(pb, 0); /* Reserved */
2962 2 avio_wb16(pb, 1); /* Data-reference index */
2963
2964 2 avio_wb16(pb, 1); /* Hint track version */
2965 2 avio_wb16(pb, 1); /* Highest compatible version */
2966 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2967
2968 2 avio_wb32(pb, 12); /* size */
2969 2 ffio_wfourcc(pb, "tims");
2970 2 avio_wb32(pb, track->timescale);
2971
2972 2 return update_size(pb, pos);
2973 }
2974
2975 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2976 {
2977 2 uint64_t str_size =strlen(reel_name);
2978 2 int64_t pos = avio_tell(pb);
2979
2980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2981 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2982 avio_wb16(pb, 0);
2983 return AVERROR(EINVAL);
2984 }
2985
2986 2 avio_wb32(pb, 0); /* size */
2987 2 ffio_wfourcc(pb, "name"); /* Data format */
2988 2 avio_wb16(pb, str_size); /* string size */
2989 2 avio_wb16(pb, track->language); /* langcode */
2990 2 avio_write(pb, reel_name, str_size); /* reel name */
2991 2 return update_size(pb,pos);
2992 }
2993
2994 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2995 {
2996 13 int64_t pos = avio_tell(pb);
2997 #if 1
2998 int frame_duration;
2999 int nb_frames;
3000 13 AVDictionaryEntry *t = NULL;
3001
3002
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) {
3003 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3004 return AVERROR(EINVAL);
3005 } else {
3006 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3007
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);
3008 }
3009
3010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3011 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3012 return AVERROR(EINVAL);
3013 }
3014
3015 13 avio_wb32(pb, 0); /* size */
3016 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3017 13 avio_wb32(pb, 0); /* Reserved */
3018 13 avio_wb32(pb, 1); /* Data reference index */
3019 13 avio_wb32(pb, 0); /* Flags */
3020 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3021 13 avio_wb32(pb, track->timescale); /* Timescale */
3022 13 avio_wb32(pb, frame_duration); /* Frame duration */
3023 13 avio_w8(pb, nb_frames); /* Number of frames */
3024 13 avio_w8(pb, 0); /* Reserved */
3025
3026 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3027
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)
3028 2 mov_write_source_reference_tag(pb, track, t->value);
3029 else
3030 11 avio_wb16(pb, 0); /* zero size */
3031 #else
3032
3033 avio_wb32(pb, 0); /* size */
3034 ffio_wfourcc(pb, "tmcd"); /* Data format */
3035 avio_wb32(pb, 0); /* Reserved */
3036 avio_wb32(pb, 1); /* Data reference index */
3037 if (track->par->extradata_size)
3038 avio_write(pb, track->par->extradata, track->par->extradata_size);
3039 #endif
3040 13 return update_size(pb, pos);
3041 }
3042
3043 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3044 {
3045 1 int64_t pos = avio_tell(pb);
3046 1 avio_wb32(pb, 0); /* size */
3047 1 ffio_wfourcc(pb, "gpmd");
3048 1 avio_wb32(pb, 0); /* Reserved */
3049 1 avio_wb16(pb, 0); /* Reserved */
3050 1 avio_wb16(pb, 1); /* Data-reference index */
3051 1 avio_wb32(pb, 0); /* Reserved */
3052 1 return update_size(pb, pos);
3053 }
3054
3055 343 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3056 {
3057 343 int64_t pos = avio_tell(pb);
3058 343 int ret = 0;
3059 343 avio_wb32(pb, 0); /* size */
3060 343 ffio_wfourcc(pb, "stsd");
3061 343 avio_wb32(pb, 0); /* version & flags */
3062 343 avio_wb32(pb, track->stsd_count);
3063
3064 343 int stsd_index_back = track->last_stsd_index;
3065 343 for (track->last_stsd_index = 0;
3066
2/2
✓ Branch 0 taken 344 times.
✓ Branch 1 taken 343 times.
687 track->last_stsd_index < track->stsd_count;
3067 344 track->last_stsd_index++) {
3068
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 132 times.
344 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3069 212 ret = mov_write_video_tag(s, pb, mov, track);
3070
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 20 times.
132 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3071 112 ret = mov_write_audio_tag(s, pb, mov, track);
3072
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3073 4 ret = mov_write_subtitle_tag(s, pb, track);
3074
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3075 2 ret = mov_write_rtp_tag(pb, track);
3076
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3077 13 ret = mov_write_tmcd_tag(pb, track);
3078
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3079 1 ret = mov_write_gpmd_tag(pb, track);
3080
3081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344 times.
344 if (ret < 0)
3082 return ret;
3083 }
3084
3085 343 track->last_stsd_index = stsd_index_back;
3086
3087 343 return update_size(pb, pos);
3088 }
3089
3090 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3091 {
3092 9 MOVMuxContext *mov = s->priv_data;
3093 MOVCtts *ctts_entries;
3094 9 uint32_t entries = 0;
3095 uint32_t atom_size;
3096 int i;
3097
3098 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3100 return AVERROR(ENOMEM);
3101 9 ctts_entries[0].count = 1;
3102 9 ctts_entries[0].offset = track->cluster[0].cts;
3103
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3104
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3105 130 ctts_entries[entries].count++; /* compress */
3106 } else {
3107 421 entries++;
3108 421 ctts_entries[entries].offset = track->cluster[i].cts;
3109 421 ctts_entries[entries].count = 1;
3110 }
3111 }
3112 9 entries++; /* last one */
3113 9 atom_size = 16 + (entries * 8);
3114 9 avio_wb32(pb, atom_size); /* size */
3115 9 ffio_wfourcc(pb, "ctts");
3116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3117 avio_w8(pb, 1); /* version */
3118 else
3119 9 avio_w8(pb, 0); /* version */
3120 9 avio_wb24(pb, 0); /* flags */
3121 9 avio_wb32(pb, entries); /* entry count */
3122
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3123 430 avio_wb32(pb, ctts_entries[i].count);
3124 430 avio_wb32(pb, ctts_entries[i].offset);
3125 }
3126 9 av_free(ctts_entries);
3127 9 return atom_size;
3128 }
3129
3130 /* Time to sample atom */
3131 343 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3132 {
3133 343 MOVStts *stts_entries = NULL;
3134 343 uint32_t entries = -1;
3135 uint32_t atom_size;
3136 int i;
3137
3138
4/4
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 231 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 77 times.
343 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3139 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3141 return AVERROR(ENOMEM);
3142 35 stts_entries[0].count = track->sample_count;
3143 35 stts_entries[0].duration = 1;
3144 35 entries = 1;
3145 } else {
3146
2/2
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 93 times.
308 if (track->entry) {
3147 215 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 215 times.
215 if (!stts_entries)
3149 return AVERROR(ENOMEM);
3150 }
3151
2/2
✓ Branch 0 taken 12216 times.
✓ Branch 1 taken 308 times.
12524 for (i = 0; i < track->entry; i++) {
3152 12216 int duration = get_cluster_duration(track, i);
3153 #if CONFIG_IAMFENC
3154
3/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 12166 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
12216 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3155 duration = av_rescale(duration, 48000, track->par->sample_rate);
3156 #endif
3157
4/4
✓ Branch 0 taken 12001 times.
✓ Branch 1 taken 215 times.
✓ Branch 2 taken 11598 times.
✓ Branch 3 taken 403 times.
12216 if (i && duration == stts_entries[entries].duration) {
3158 11598 stts_entries[entries].count++; /* compress */
3159 } else {
3160 618 entries++;
3161 618 stts_entries[entries].duration = duration;
3162 618 stts_entries[entries].count = 1;
3163 }
3164 }
3165 308 entries++; /* last one */
3166 }
3167 343 atom_size = 16 + (entries * 8);
3168 343 avio_wb32(pb, atom_size); /* size */
3169 343 ffio_wfourcc(pb, "stts");
3170 343 avio_wb32(pb, 0); /* version & flags */
3171 343 avio_wb32(pb, entries); /* entry count */
3172
2/2
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 343 times.
996 for (i = 0; i < entries; i++) {
3173 653 avio_wb32(pb, stts_entries[i].count);
3174 653 avio_wb32(pb, stts_entries[i].duration);
3175 }
3176 343 av_free(stts_entries);
3177 343 return atom_size;
3178 }
3179
3180 343 static int mov_write_dref_tag(AVIOContext *pb)
3181 {
3182 343 avio_wb32(pb, 28); /* size */
3183 343 ffio_wfourcc(pb, "dref");
3184 343 avio_wb32(pb, 0); /* version & flags */
3185 343 avio_wb32(pb, 1); /* entry count */
3186
3187 343 avio_wb32(pb, 0xc); /* size */
3188 //FIXME add the alis and rsrc atom
3189 343 ffio_wfourcc(pb, "url ");
3190 343 avio_wb32(pb, 1); /* version & flags */
3191
3192 343 return 28;
3193 }
3194
3195 55 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3196 {
3197 struct sgpd_entry {
3198 int count;
3199 int16_t roll_distance;
3200 int group_description_index;
3201 };
3202
3203 55 struct sgpd_entry *sgpd_entries = NULL;
3204 55 int entries = -1;
3205 55 int group = 0;
3206 int i, j;
3207
3208 55 const int OPUS_SEEK_PREROLL_MS = 80;
3209 55 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3210 55 (AVRational){1, 1000},
3211 55 (AVRational){1, 48000});
3212
3213
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 12 times.
55 if (!track->entry)
3214 43 return 0;
3215
3216 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3218 return AVERROR(ENOMEM);
3219
3220
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3221
3222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3223 for (i = 0; i < track->entry; i++) {
3224 int roll_samples_remaining = roll_samples;
3225 int distance = 0;
3226 for (j = i - 1; j >= 0; j--) {
3227 roll_samples_remaining -= get_cluster_duration(track, j);
3228 distance++;
3229 if (roll_samples_remaining <= 0)
3230 break;
3231 }
3232 /* We don't have enough preceding samples to compute a valid
3233 roll_distance here, so this sample can't be independently
3234 decoded. */
3235 if (roll_samples_remaining > 0)
3236 distance = 0;
3237 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3238 if (distance > 32)
3239 return AVERROR_INVALIDDATA;
3240 if (i && distance == sgpd_entries[entries].roll_distance) {
3241 sgpd_entries[entries].count++;
3242 } else {
3243 entries++;
3244 sgpd_entries[entries].count = 1;
3245 sgpd_entries[entries].roll_distance = distance;
3246 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3247 }
3248 }
3249 } else {
3250 12 entries++;
3251 12 sgpd_entries[entries].count = track->sample_count;
3252 12 sgpd_entries[entries].roll_distance = 1;
3253 12 sgpd_entries[entries].group_description_index = ++group;
3254 }
3255 12 entries++;
3256
3257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3258 av_free(sgpd_entries);
3259 return 0;
3260 }
3261
3262 /* Write sgpd tag */
3263 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3264 12 ffio_wfourcc(pb, "sgpd");
3265 12 avio_wb32(pb, 1 << 24); /* fullbox */
3266 12 ffio_wfourcc(pb, "roll");
3267 12 avio_wb32(pb, 2); /* default_length */
3268 12 avio_wb32(pb, group); /* entry_count */
3269
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3270
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3271 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3272 }
3273 }
3274
3275 /* Write sbgp tag */
3276 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3277 12 ffio_wfourcc(pb, "sbgp");
3278 12 avio_wb32(pb, 0); /* fullbox */
3279 12 ffio_wfourcc(pb, "roll");
3280 12 avio_wb32(pb, entries); /* entry_count */
3281
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3282 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3283 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3284 }
3285
3286 12 av_free(sgpd_entries);
3287 12 return 0;
3288 }
3289
3290 343 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3291 {
3292 343 int64_t pos = avio_tell(pb);
3293 343 int ret = 0;
3294
3295 343 avio_wb32(pb, 0); /* size */
3296 343 ffio_wfourcc(pb, "stbl");
3297
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 343 times.
343 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3298 return ret;
3299 343 mov_write_stts_tag(pb, track);
3300
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 211 times.
343 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3301
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3302
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3303
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
132 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3304
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 130 times.
132 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3305
4/4
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 104 times.
213 track->has_keyframes && track->has_keyframes < track->entry)
3306 59 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3307
5/6
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 208 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
343 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3308 3 mov_write_sdtp_tag(pb, track);
3309
3/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 189 times.
343 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3310 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3311
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 132 times.
343 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3312
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 22 times.
211 track->flags & MOV_TRACK_CTTS && track->entry) {
3313
3314
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3315 return ret;
3316 }
3317 343 mov_write_stsc_tag(pb, track);
3318 343 mov_write_stsz_tag(pb, track);
3319 343 mov_write_stco_tag(pb, track);
3320
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
343 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3321 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3322 }
3323
3/4
✓ Branch 0 taken 343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 288 times.
343 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3324 55 mov_preroll_write_stbl_atoms(pb, track);
3325 }
3326 343 return update_size(pb, pos);
3327 }
3328
3329 343 static int mov_write_dinf_tag(AVIOContext *pb)
3330 {
3331 343 int64_t pos = avio_tell(pb);
3332 343 avio_wb32(pb, 0); /* size */
3333 343 ffio_wfourcc(pb, "dinf");
3334 343 mov_write_dref_tag(pb);
3335 343 return update_size(pb, pos);
3336 }
3337
3338 6 static int mov_write_nmhd_tag(AVIOContext *pb)
3339 {
3340 6 avio_wb32(pb, 12);
3341 6 ffio_wfourcc(pb, "nmhd");
3342 6 avio_wb32(pb, 0);
3343 6 return 12;
3344 }
3345
3346 1 static int mov_write_sthd_tag(AVIOContext *pb)
3347 {
3348 1 avio_wb32(pb, 12);
3349 1 ffio_wfourcc(pb, "sthd");
3350 1 avio_wb32(pb, 0);
3351 1 return 12;
3352 }
3353
3354 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3355 {
3356 9 int64_t pos = avio_tell(pb);
3357 9 const char *font = "Lucida Grande";
3358 9 avio_wb32(pb, 0); /* size */
3359 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3360 9 avio_wb32(pb, 0); /* version & flags */
3361 9 avio_wb16(pb, 0); /* text font */
3362 9 avio_wb16(pb, 0); /* text face */
3363 9 avio_wb16(pb, 12); /* text size */
3364 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3365 9 avio_wb16(pb, 0x0000); /* text color (red) */
3366 9 avio_wb16(pb, 0x0000); /* text color (green) */
3367 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3368 9 avio_wb16(pb, 0xffff); /* background color (red) */
3369 9 avio_wb16(pb, 0xffff); /* background color (green) */
3370 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3371 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3372 9 avio_write(pb, font, strlen(font)); /* font name */
3373 9 return update_size(pb, pos);
3374 }
3375
3376 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3377 {
3378 11 int64_t pos = avio_tell(pb);
3379 11 avio_wb32(pb, 0); /* size */
3380 11 ffio_wfourcc(pb, "gmhd");
3381 11 avio_wb32(pb, 0x18); /* gmin size */
3382 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3383 11 avio_wb32(pb, 0); /* version & flags */
3384 11 avio_wb16(pb, 0x40); /* graphics mode = */
3385 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3386 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3387 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3388 11 avio_wb16(pb, 0); /* balance */
3389 11 avio_wb16(pb, 0); /* reserved */
3390
3391 /*
3392 * This special text atom is required for
3393 * Apple Quicktime chapters. The contents
3394 * don't appear to be documented, so the
3395 * bytes are copied verbatim.
3396 */
3397
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3398 11 avio_wb32(pb, 0x2C); /* size */
3399 11 ffio_wfourcc(pb, "text");
3400 11 avio_wb16(pb, 0x01);
3401 11 avio_wb32(pb, 0x00);
3402 11 avio_wb32(pb, 0x00);
3403 11 avio_wb32(pb, 0x00);
3404 11 avio_wb32(pb, 0x01);
3405 11 avio_wb32(pb, 0x00);
3406 11 avio_wb32(pb, 0x00);
3407 11 avio_wb32(pb, 0x00);
3408 11 avio_wb32(pb, 0x00004000);
3409 11 avio_wb16(pb, 0x0000);
3410 }
3411
3412
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3413 9 int64_t tmcd_pos = avio_tell(pb);
3414 9 avio_wb32(pb, 0); /* size */
3415 9 ffio_wfourcc(pb, "tmcd");
3416 9 mov_write_tcmi_tag(pb, track);
3417 9 update_size(pb, tmcd_pos);
3418
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3419 1 int64_t gpmd_pos = avio_tell(pb);
3420 1 avio_wb32(pb, 0); /* size */
3421 1 ffio_wfourcc(pb, "gpmd");
3422 1 avio_wb32(pb, 0); /* version */
3423 1 update_size(pb, gpmd_pos);
3424 }
3425 11 return update_size(pb, pos);
3426 }
3427
3428 112 static int mov_write_smhd_tag(AVIOContext *pb)
3429 {
3430 112 avio_wb32(pb, 16); /* size */
3431 112 ffio_wfourcc(pb, "smhd");
3432 112 avio_wb32(pb, 0); /* version & flags */
3433 112 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3434 112 avio_wb16(pb, 0); /* reserved */
3435 112 return 16;
3436 }
3437
3438 211 static int mov_write_vmhd_tag(AVIOContext *pb)
3439 {
3440 211 avio_wb32(pb, 0x14); /* size (always 0x14) */
3441 211 ffio_wfourcc(pb, "vmhd");
3442 211 avio_wb32(pb, 0x01); /* version & flags */
3443 211 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3444 211 return 0x14;
3445 }
3446
3447 222 static int is_clcp_track(MOVTrack *track)
3448 {
3449
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
444 return track->tag == MKTAG('c','7','0','8') ||
3450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
222 track->tag == MKTAG('c','6','0','8');
3451 }
3452
3453 532 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3454 {
3455 532 MOVMuxContext *mov = s->priv_data;
3456 532 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3457 532 int64_t pos = avio_tell(pb);
3458 size_t descr_len;
3459
3460 532 hdlr = "dhlr";
3461 532 hdlr_type = "url ";
3462 532 descr = "DataHandler";
3463
3464
2/2
✓ Branch 0 taken 343 times.
✓ Branch 1 taken 189 times.
532 if (track) {
3465
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 154 times.
343 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3466
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 132 times.
343 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 if (track->mode == MODE_AVIF) {
3468 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3469 descr = "PictureHandler";
3470 } else {
3471 211 hdlr_type = "vide";
3472 211 descr = "VideoHandler";
3473 }
3474
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 20 times.
132 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3475 112 hdlr_type = "soun";
3476 112 descr = "SoundHandler";
3477
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3478
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3479 hdlr_type = "clcp";
3480 descr = "ClosedCaptionHandler";
3481 } else {
3482
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3483 1 hdlr_type = "sbtl";
3484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3485 hdlr_type = "subp";
3486
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3487 1 hdlr_type = "subt";
3488 } else {
3489 2 hdlr_type = "text";
3490 }
3491 4 descr = "SubtitleHandler";
3492 }
3493
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3494 2 hdlr_type = "hint";
3495 2 descr = "HintHandler";
3496
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3497 13 hdlr_type = "tmcd";
3498 13 descr = "TimeCodeHandler";
3499
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3500 1 hdlr_type = "meta";
3501 1 descr = "GoPro MET"; // GoPro Metadata
3502 } else {
3503 av_log(s, AV_LOG_WARNING,
3504 "Unknown hdlr_type for %s, writing dummy values\n",
3505 av_fourcc2str(track->par->codec_tag));
3506 }
3507
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 3 times.
343 if (track->st) {
3508 // hdlr.name is used by some players to identify the content title
3509 // of the track. So if an alternate handler description is
3510 // specified, use it.
3511 AVDictionaryEntry *t;
3512 340 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3513
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 314 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
340 if (t && utf8len(t->value))
3514 26 descr = t->value;
3515 }
3516 }
3517
3518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 532 times.
532 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3519 descr = "";
3520
3521 532 avio_wb32(pb, 0); /* size */
3522 532 ffio_wfourcc(pb, "hdlr");
3523 532 avio_wb32(pb, 0); /* Version & flags */
3524 532 avio_write(pb, hdlr, 4); /* handler */
3525 532 ffio_wfourcc(pb, hdlr_type); /* handler type */
3526 532 avio_wb32(pb, 0); /* reserved */
3527 532 avio_wb32(pb, 0); /* reserved */
3528 532 avio_wb32(pb, 0); /* reserved */
3529 532 descr_len = strlen(descr);
3530
4/4
✓ Branch 0 taken 343 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 154 times.
532 if (!track || track->mode == MODE_MOV)
3531 378 avio_w8(pb, descr_len); /* pascal string */
3532 532 avio_write(pb, descr, descr_len); /* handler description */
3533
4/4
✓ Branch 0 taken 343 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 154 times.
✓ Branch 3 taken 189 times.
532 if (track && track->mode != MODE_MOV)
3534 154 avio_w8(pb, 0); /* c string */
3535 532 return update_size(pb, pos);
3536 }
3537
3538 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3539 {
3540 int64_t pos = avio_tell(pb);
3541 avio_wb32(pb, 0); /* size */
3542 ffio_wfourcc(pb, "pitm");
3543 avio_wb32(pb, 0); /* Version & flags */
3544 avio_wb16(pb, item_id); /* item_id */
3545 return update_size(pb, pos);
3546 }
3547
3548 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3549 {
3550 int64_t pos = avio_tell(pb);
3551 avio_wb32(pb, 0); /* size */
3552 ffio_wfourcc(pb, "iloc");
3553 avio_wb32(pb, 0); /* Version & flags */
3554 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3555 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3556 avio_wb16(pb, mov->nb_streams); /* item_count */
3557
3558 for (int i = 0; i < mov->nb_streams; i++) {
3559 avio_wb16(pb, i + 1); /* item_id */
3560 avio_wb16(pb, 0); /* data_reference_index */
3561 avio_wb16(pb, 1); /* extent_count */
3562 mov->avif_extent_pos[i] = avio_tell(pb);
3563 avio_wb32(pb, 0); /* extent_offset (written later) */
3564 // For animated AVIF, we simply write the first packet's size.
3565 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3566 }
3567
3568 return update_size(pb, pos);
3569 }
3570
3571 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3572 {
3573 int64_t iinf_pos = avio_tell(pb);
3574 avio_wb32(pb, 0); /* size */
3575 ffio_wfourcc(pb, "iinf");
3576 avio_wb32(pb, 0); /* Version & flags */
3577 avio_wb16(pb, mov->nb_streams); /* entry_count */
3578
3579 for (int i = 0; i < mov->nb_streams; i++) {
3580 int64_t infe_pos = avio_tell(pb);
3581 avio_wb32(pb, 0); /* size */
3582 ffio_wfourcc(pb, "infe");
3583 avio_w8(pb, 0x2); /* Version */
3584 avio_wb24(pb, 0); /* flags */
3585 avio_wb16(pb, i + 1); /* item_id */
3586 avio_wb16(pb, 0); /* item_protection_index */
3587 avio_write(pb, "av01", 4); /* item_type */
3588 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3589 update_size(pb, infe_pos);
3590 }
3591
3592 return update_size(pb, iinf_pos);
3593 }
3594
3595
3596 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3597 {
3598 int64_t auxl_pos;
3599 int64_t iref_pos = avio_tell(pb);
3600 avio_wb32(pb, 0); /* size */
3601 ffio_wfourcc(pb, "iref");
3602 avio_wb32(pb, 0); /* Version & flags */
3603
3604 auxl_pos = avio_tell(pb);
3605 avio_wb32(pb, 0); /* size */
3606 ffio_wfourcc(pb, "auxl");
3607 avio_wb16(pb, 2); /* from_item_ID */
3608 avio_wb16(pb, 1); /* reference_count */
3609 avio_wb16(pb, 1); /* to_item_ID */
3610 update_size(pb, auxl_pos);
3611
3612 return update_size(pb, iref_pos);
3613 }
3614
3615 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3616 int stream_index)
3617 {
3618 int64_t pos = avio_tell(pb);
3619 avio_wb32(pb, 0); /* size */
3620 ffio_wfourcc(pb, "ispe");
3621 avio_wb32(pb, 0); /* Version & flags */
3622 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3623 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3624 return update_size(pb, pos);
3625 }
3626
3627 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3628 int stream_index)
3629 {
3630 int64_t pos = avio_tell(pb);
3631 const AVPixFmtDescriptor *pixdesc =
3632 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3633 avio_wb32(pb, 0); /* size */
3634 ffio_wfourcc(pb, "pixi");
3635 avio_wb32(pb, 0); /* Version & flags */
3636 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3637 for (int i = 0; i < pixdesc->nb_components; ++i) {
3638 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3639 }
3640 return update_size(pb, pos);
3641 }
3642
3643 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3644 {
3645 int64_t pos = avio_tell(pb);
3646 avio_wb32(pb, 0); /* size */
3647 ffio_wfourcc(pb, "ipco");
3648 for (int i = 0; i < mov->nb_streams; i++) {
3649 mov_write_ispe_tag(pb, mov, s, i);
3650 mov_write_pixi_tag(pb, mov, s, i);
3651 mov_write_av1c_tag(pb, &mov->tracks[i]);
3652 if (!i)
3653 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3654 else
3655 mov_write_aux_tag(pb, "auxC");
3656 }
3657 return update_size(pb, pos);
3658 }
3659
3660 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3661 {
3662 int64_t pos = avio_tell(pb);
3663 avio_wb32(pb, 0); /* size */
3664 ffio_wfourcc(pb, "ipma");
3665 avio_wb32(pb, 0); /* Version & flags */
3666 avio_wb32(pb, mov->nb_streams); /* entry_count */
3667
3668 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3669 avio_wb16(pb, i + 1); /* item_ID */
3670 avio_w8(pb, 4); /* association_count */
3671
3672 // ispe association.
3673 avio_w8(pb, index++); /* essential and property_index */
3674 // pixi association.
3675 avio_w8(pb, index++); /* essential and property_index */
3676 // av1C association.
3677 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3678 // colr/auxC association.
3679 avio_w8(pb, index++); /* essential and property_index */
3680 }
3681 return update_size(pb, pos);
3682 }
3683
3684 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3685 {
3686 int64_t pos = avio_tell(pb);
3687 avio_wb32(pb, 0); /* size */
3688 ffio_wfourcc(pb, "iprp");
3689 mov_write_ipco_tag(pb, mov, s);
3690 mov_write_ipma_tag(pb, mov, s);
3691 return update_size(pb, pos);
3692 }
3693
3694 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3695 {
3696 /* This atom must be present, but leaving the values at zero
3697 * seems harmless. */
3698 2 avio_wb32(pb, 28); /* size */
3699 2 ffio_wfourcc(pb, "hmhd");
3700 2 avio_wb32(pb, 0); /* version, flags */
3701 2 avio_wb16(pb, 0); /* maxPDUsize */
3702 2 avio_wb16(pb, 0); /* avgPDUsize */
3703 2 avio_wb32(pb, 0); /* maxbitrate */
3704 2 avio_wb32(pb, 0); /* avgbitrate */
3705 2 avio_wb32(pb, 0); /* reserved */
3706 2 return 28;
3707 }
3708
3709 343 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3710 {
3711 343 int64_t pos = avio_tell(pb);
3712 int ret;
3713
3714 343 avio_wb32(pb, 0); /* size */
3715 343 ffio_wfourcc(pb, "minf");
3716
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 132 times.
343 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3717 211 mov_write_vmhd_tag(pb);
3718
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 20 times.
132 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3719 112 mov_write_smhd_tag(pb);
3720
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3721
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
4 if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
3722 1 mov_write_gmhd_tag(pb, track);
3723
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3724 1 mov_write_sthd_tag(pb);
3725 } else {
3726 2 mov_write_nmhd_tag(pb);
3727 }
3728
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3729 2 mov_write_hmhd_tag(pb);
3730
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3731
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3732 4 mov_write_nmhd_tag(pb);
3733 else
3734 9 mov_write_gmhd_tag(pb, track);
3735
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3736 1 mov_write_gmhd_tag(pb, track);
3737 }
3738
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 154 times.
343 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3739 189 mov_write_hdlr_tag(s, pb, NULL);
3740 343 mov_write_dinf_tag(pb);
3741
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 343 times.
343 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3742 return ret;
3743 343 return update_size(pb, pos);
3744 }
3745
3746 1328 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3747 int64_t *start, int64_t *end)
3748 {
3749
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1278 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1328 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3750 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3751 // another track's duration, while the end_pts may be left at zero.
3752 // Calculate the pts duration for that track instead.
3753 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3754 38 *start = av_rescale(*start, track->timescale,
3755 38 mov->tracks[track->src_track].timescale);
3756 38 *end = av_rescale(*end, track->timescale,
3757 38 mov->tracks[track->src_track].timescale);
3758 38 return;
3759 }
3760
2/2
✓ Branch 0 taken 1228 times.
✓ Branch 1 taken 62 times.
1290 if (track->end_pts != AV_NOPTS_VALUE &&
3761
1/2
✓ Branch 0 taken 1228 times.
✗ Branch 1 not taken.
1228 track->start_dts != AV_NOPTS_VALUE &&
3762
1/2
✓ Branch 0 taken 1228 times.
✗ Branch 1 not taken.
1228 track->start_cts != AV_NOPTS_VALUE) {
3763 1228 *start = track->start_dts + track->start_cts;
3764 1228 *end = track->end_pts;
3765 1228 return;
3766 }
3767 62 *start = 0;
3768 62 *end = track->track_duration;
3769 }
3770
3771 632 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3772 {
3773 int64_t start, end;
3774 632 get_pts_range(mov, track, &start, &end);
3775 632 return end - start;
3776 }
3777
3778 // Calculate the actual duration of the track, after edits.
3779 // If it starts with a pts < 0, that is removed by the edit list.
3780 // If it starts with a pts > 0, the edit list adds a delay before that.
3781 // Thus, with edit lists enabled, the post-edit output of the file is
3782 // starting with pts=0.
3783 658 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3784 {
3785 int64_t start, end;
3786 658 get_pts_range(mov, track, &start, &end);
3787
2/2
✓ Branch 0 taken 584 times.
✓ Branch 1 taken 74 times.
658 if (mov->use_editlist != 0)
3788 584 start = 0;
3789 658 return end - start;
3790 }
3791
3792 930 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3793 {
3794
4/4
✓ Branch 0 taken 686 times.
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 672 times.
930 if (track && track->mode == MODE_ISM)
3795 14 return 1;
3796
2/2
✓ Branch 0 taken 912 times.
✓ Branch 1 taken 4 times.
916 if (duration < INT32_MAX)
3797 912 return 0;
3798 4 return 1;
3799 }
3800
3801 343 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3802 MOVTrack *track)
3803 {
3804 343 int64_t duration = calc_samples_pts_duration(mov, track);
3805 343 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3806
3807
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 332 times.
343 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3808 343 ffio_wfourcc(pb, "mdhd");
3809 343 avio_w8(pb, version);
3810 343 avio_wb24(pb, 0); /* flags */
3811
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 332 times.
343 if (version == 1) {
3812 11 avio_wb64(pb, track->time);
3813 11 avio_wb64(pb, track->time);
3814 } else {
3815 332 avio_wb32(pb, track->time); /* creation time */
3816 332 avio_wb32(pb, track->time); /* modification time */
3817 }
3818 343 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3819
4/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 87 times.
343 if (!track->entry && mov->mode == MODE_ISM)
3820
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3821
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 249 times.
336 else if (!track->entry)
3822
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 83 times.
87 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3823 else
3824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3825 343 avio_wb16(pb, track->language); /* language */
3826 343 avio_wb16(pb, 0); /* reserved (quality) */
3827
3828
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
343 if (version != 0 && track->mode == MODE_MOV) {
3829 av_log(NULL, AV_LOG_ERROR,
3830 "FATAL error, file duration too long for timebase, this file will not be\n"
3831 "playable with QuickTime. Choose a different timebase with "
3832 "-video_track_timescale or a different container format\n");
3833 }
3834
3835 343 return 32;
3836 }
3837
3838 343 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3839 MOVMuxContext *mov, MOVTrack *track)
3840 {
3841 343 int64_t pos = avio_tell(pb);
3842 int ret;
3843
3844 343 avio_wb32(pb, 0); /* size */
3845 343 ffio_wfourcc(pb, "mdia");
3846 343 mov_write_mdhd_tag(pb, mov, track);
3847 343 mov_write_hdlr_tag(s, pb, track);
3848
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 343 times.
343 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3849 return ret;
3850 343 return update_size(pb, pos);
3851 }
3852
3853 /* transformation matrix
3854 |a b u|
3855 |c d v|
3856 |tx ty w| */
3857 586 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3858 int16_t d, int16_t tx, int16_t ty)
3859 {
3860 586 avio_wb32(pb, a << 16); /* 16.16 format */
3861 586 avio_wb32(pb, b << 16); /* 16.16 format */
3862 586 avio_wb32(pb, 0); /* u in 2.30 format */
3863 586 avio_wb32(pb, c << 16); /* 16.16 format */
3864 586 avio_wb32(pb, d << 16); /* 16.16 format */
3865 586 avio_wb32(pb, 0); /* v in 2.30 format */
3866 586 avio_wb32(pb, tx << 16); /* 16.16 format */
3867 586 avio_wb32(pb, ty << 16); /* 16.16 format */
3868 586 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3869 586 }
3870
3871 343 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3872 MOVTrack *track, AVStream *st)
3873 {
3874 686 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3875 343 mov->movie_timescale, track->timescale,
3876 AV_ROUND_UP);
3877 int version;
3878 343 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3879 343 int group = 0;
3880
3881 343 uint32_t *display_matrix = NULL;
3882 int i;
3883
3884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
343 if (mov->mode == MODE_AVIF)
3885 if (!mov->avif_loop_count)
3886 duration = INT64_MAX;
3887 else
3888 duration *= mov->avif_loop_count;
3889
3890
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 13 times.
343 if (st) {
3891 const AVPacketSideData *sd;
3892
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 328 times.
330 if (mov->per_stream_grouping)
3893 2 group = st->index;
3894 else
3895 328 group = st->codecpar->codec_type;
3896
3897 330 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3898 330 st->codecpar->nb_coded_side_data,
3899 AV_PKT_DATA_DISPLAYMATRIX);
3900
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 329 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
330 if (sd && sd->size == 9 * sizeof(*display_matrix))
3901 1 display_matrix = (uint32_t *)sd->data;
3902 }
3903
3904
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 25 times.
343 if (track->flags & MOV_TRACK_ENABLED)
3905 318 flags |= MOV_TKHD_FLAG_ENABLED;
3906
3907 343 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3908
3909
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 336 times.
343 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3910 343 ffio_wfourcc(pb, "tkhd");
3911 343 avio_w8(pb, version);
3912 343 avio_wb24(pb, flags);
3913
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 336 times.
343 if (version == 1) {
3914 7 avio_wb64(pb, track->time);
3915 7 avio_wb64(pb, track->time);
3916 } else {
3917 336 avio_wb32(pb, track->time); /* creation time */
3918 336 avio_wb32(pb, track->time); /* modification time */
3919 }
3920 343 avio_wb32(pb, track->track_id); /* track-id */
3921 343 avio_wb32(pb, 0); /* reserved */
3922
4/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 87 times.
343 if (!track->entry && mov->mode == MODE_ISM)
3923
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3924
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 249 times.
336 else if (!track->entry)
3925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
87 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3926 else
3927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3928
3929 343 avio_wb32(pb, 0); /* reserved */
3930 343 avio_wb32(pb, 0); /* reserved */
3931 343 avio_wb16(pb, 0); /* layer */
3932 343 avio_wb16(pb, group); /* alternate group) */
3933 /* Volume, only for audio */
3934
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 231 times.
343 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3935 112 avio_wb16(pb, 0x0100);
3936 else
3937 231 avio_wb16(pb, 0);
3938 343 avio_wb16(pb, 0); /* reserved */
3939
3940 /* Matrix structure */
3941
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 342 times.
343 if (display_matrix) {
3942
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3943 9 avio_wb32(pb, display_matrix[i]);
3944 } else {
3945 342 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3946 }
3947 /* Track width and height, for visual only */
3948
4/4
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 119 times.
✓ Branch 3 taken 211 times.
343 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3949
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 116 times.
333 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3950 int64_t track_width_1616;
3951
3/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 74 times.
214 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
3952 140 track_width_1616 = track->par->width * 0x10000ULL;
3953 } else {
3954 74 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3955 74 track->par->width * 0x10000LL,
3956 74 st->sample_aspect_ratio.den);
3957
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 68 times.
74 if (!track_width_1616 ||
3958
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 track->height != track->par->height ||
3959 track_width_1616 > UINT32_MAX)
3960 68 track_width_1616 = track->par->width * 0x10000ULL;
3961 }
3962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (track_width_1616 > UINT32_MAX) {
3963 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3964 track_width_1616 = 0;
3965 }
3966 214 avio_wb32(pb, track_width_1616);
3967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (track->height > 0xFFFF) {
3968 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3969 avio_wb32(pb, 0);
3970 } else
3971 214 avio_wb32(pb, track->height * 0x10000U);
3972 } else {
3973 129 avio_wb32(pb, 0);
3974 129 avio_wb32(pb, 0);
3975 }
3976 343 return 0x5c;
3977 }
3978
3979 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3980 {
3981 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3982 1 track->par->sample_aspect_ratio.den);
3983
3984 1 int64_t pos = avio_tell(pb);
3985
3986 1 avio_wb32(pb, 0); /* size */
3987 1 ffio_wfourcc(pb, "tapt");
3988
3989 1 avio_wb32(pb, 20);
3990 1 ffio_wfourcc(pb, "clef");
3991 1 avio_wb32(pb, 0);
3992 1 avio_wb32(pb, width << 16);
3993 1 avio_wb32(pb, track->par->height << 16);
3994
3995 1 avio_wb32(pb, 20);
3996 1 ffio_wfourcc(pb, "prof");
3997 1 avio_wb32(pb, 0);
3998 1 avio_wb32(pb, width << 16);
3999 1 avio_wb32(pb, track->par->height << 16);
4000
4001 1 avio_wb32(pb, 20);
4002 1 ffio_wfourcc(pb, "enof");
4003 1 avio_wb32(pb, 0);
4004 1 avio_wb32(pb, track->par->width << 16);
4005 1 avio_wb32(pb, track->par->height << 16);
4006
4007 1 return update_size(pb, pos);
4008 }
4009
4010 // This box is written in the following cases:
4011 // * Seems important for the psp playback. Without it the movie seems to hang.
4012 // * Used for specifying the looping behavior of animated AVIF (as specified
4013 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4014 289 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4015 MOVTrack *track)
4016 {
4017 578 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
4018 289 mov->movie_timescale, track->timescale,
4019 AV_ROUND_UP);
4020 289 int version = duration < INT32_MAX ? 0 : 1;
4021 int entry_size, entry_count, size;
4022 289 int64_t delay, start_ct = track->start_cts;
4023 289 int64_t start_dts = track->start_dts;
4024 289 int flags = 0;
4025
4026
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 56 times.
289 if (track->entry) {
4027
2/6
✓ Branch 0 taken 233 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 233 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
233 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4028
4029 av_log(mov->fc, AV_LOG_DEBUG,
4030 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4031 track->cluster[0].dts, track->cluster[0].cts,
4032 start_dts, start_ct, track->track_id);
4033 start_dts = track->cluster[0].dts;
4034 start_ct = track->cluster[0].cts;
4035 }
4036 }
4037
4038 289 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4039 289 track->timescale, AV_ROUND_DOWN);
4040
4041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 if (mov->mode == MODE_AVIF) {
4042 delay = 0;
4043 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4044 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4045 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4046 // edit list is repeated.
4047 flags = mov->avif_loop_count != 1;
4048 start_ct = 0;
4049 }
4050
4051 289 version |= delay < INT32_MAX ? 0 : 1;
4052
4053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 entry_size = (version == 1) ? 20 : 12;
4054
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 287 times.
289 entry_count = 1 + (delay > 0);
4055 289 size = 24 + entry_count * entry_size;
4056
4057 /* write the atom data */
4058 289 avio_wb32(pb, size);
4059 289 ffio_wfourcc(pb, "edts");
4060 289 avio_wb32(pb, size - 8);
4061 289 ffio_wfourcc(pb, "elst");
4062 289 avio_w8(pb, version);
4063 289 avio_wb24(pb, flags); /* flags */
4064
4065 289 avio_wb32(pb, entry_count);
4066
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 287 times.
289 if (delay > 0) { /* add an empty edit to delay presentation */
4067 /* In the positive delay case, the delay includes the cts
4068 * offset, and the second edit list entry below trims out
4069 * the same amount from the actual content. This makes sure
4070 * that the offset last sample is included in the edit
4071 * list duration as well. */
4072
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
4073 avio_wb64(pb, delay);
4074 avio_wb64(pb, -1);
4075 } else {
4076 2 avio_wb32(pb, delay);
4077 2 avio_wb32(pb, -1);
4078 }
4079 2 avio_wb32(pb, 0x00010000);
4080
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 } else if (mov->mode != MODE_AVIF) {
4081 /* Avoid accidentally ending up with start_ct = -1 which has got a
4082 * special meaning. Normally start_ct should end up positive or zero
4083 * here, but use FFMIN in case dts is a small positive integer
4084 * rounded to 0 when represented in movie timescale units. */
4085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4086 287 start_ct = -FFMIN(start_dts, 0);
4087
4088 #if CONFIG_IAMFENC
4089
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
287 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4090 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4091 #endif
4092 /* Note, this delay is calculated from the pts of the first sample,
4093 * ensuring that we don't reduce the duration for cases with
4094 * dts<0 pts=0. */
4095 287 duration += delay;
4096 }
4097
4098 /* For fragmented files, we don't know the full length yet. Setting
4099 * duration to 0 allows us to only specify the offset, including
4100 * the rest of the content (from all future fragments) without specifying
4101 * an explicit duration.
4102 *
4103 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4104 * don't reset duration to zero.
4105 */
4106
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 229 times.
289 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4107
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4108 60 duration = 0;
4109
4110 /* duration */
4111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
289 if (version == 1) {
4112 avio_wb64(pb, duration);
4113 avio_wb64(pb, start_ct);
4114 } else {
4115 289 avio_wb32(pb, duration);
4116 289 avio_wb32(pb, start_ct);
4117 }
4118 289 avio_wb32(pb, 0x00010000);
4119 289 return size;
4120 }
4121
4122 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4123 {
4124 14 avio_wb32(pb, 20); // size
4125 14 ffio_wfourcc(pb, "tref");
4126 14 avio_wb32(pb, 12); // size (subatom)
4127 14 avio_wl32(pb, track->tref_tag);
4128 14 avio_wb32(pb, track->tref_id);
4129 14 return 20;
4130 }
4131
4132 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4133 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4134 {
4135 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4136 2 ffio_wfourcc(pb, "uuid");
4137 2 ffio_wfourcc(pb, "USMT");
4138 2 avio_wb32(pb, 0x21d24fce);
4139 2 avio_wb32(pb, 0xbb88695c);
4140 2 avio_wb32(pb, 0xfac9c740);
4141 2 avio_wb32(pb, 0x1c); // another size here!
4142 2 ffio_wfourcc(pb, "MTDT");
4143 2 avio_wb32(pb, 0x00010012);
4144 2 avio_wb32(pb, 0x0a);
4145 2 avio_wb32(pb, 0x55c40000);
4146 2 avio_wb32(pb, 0x1);
4147 2 avio_wb32(pb, 0x0);
4148 2 return 0x34;
4149 }
4150
4151 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4152 {
4153 2 AVFormatContext *ctx = track->rtp_ctx;
4154 2 char buf[1000] = "";
4155 int len;
4156
4157 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4158 NULL, NULL, 0, 0, ctx);
4159 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4160 2 len = strlen(buf);
4161
4162 2 avio_wb32(pb, len + 24);
4163 2 ffio_wfourcc(pb, "udta");
4164 2 avio_wb32(pb, len + 16);
4165 2 ffio_wfourcc(pb, "hnti");
4166 2 avio_wb32(pb, len + 8);
4167 2 ffio_wfourcc(pb, "sdp ");
4168 2 avio_write(pb, buf, len);
4169 2 return len + 24;
4170 }
4171
4172 322 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4173 const char *tag, const char *str)
4174 {
4175 322 int64_t pos = avio_tell(pb);
4176 322 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4177
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 321 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
322 if (!t || !utf8len(t->value))
4178 321 return 0;
4179
4180 1 avio_wb32(pb, 0); /* size */
4181 1 ffio_wfourcc(pb, tag); /* type */
4182 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4183 1 return update_size(pb, pos);
4184 }
4185
4186 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4187 const char *value)
4188 {
4189 2 int64_t pos = avio_tell(pb);
4190
4191 /* Box|FullBox basics */
4192 2 avio_wb32(pb, 0); /* size placeholder */
4193 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4194 2 avio_w8(pb, 0); /* version = 0 */
4195 2 avio_wb24(pb, 0); /* flags = 0 */
4196
4197 /* Required null-terminated scheme URI */
4198 2 avio_write(pb, (const unsigned char *)scheme_uri,
4199 2 strlen(scheme_uri));
4200 2 avio_w8(pb, 0);
4201
4202 /* Optional value string */
4203
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])
4204 2 avio_write(pb, (const unsigned char *)value,
4205 2 strlen(value));
4206
4207 2 avio_w8(pb, 0);
4208
4209 2 return update_size(pb, pos);
4210 }
4211
4212 139 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4213 {
4214 139 int ret = AVERROR_BUG;
4215
4216
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 139 times.
278 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4217 139 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4218
4219
2/2
✓ Branch 0 taken 695 times.
✓ Branch 1 taken 139 times.
834 for (int j = 0; map.value_maps[j].disposition; j++) {
4220 695 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4221
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 2 times.
695 if (!(st->disposition & value_map.disposition))
4222 693 continue;
4223
4224
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)
4225 return ret;
4226 }
4227 }
4228
4229 139 return 0;
4230 }
4231
4232 343 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4233 AVStream *st)
4234 {
4235 AVIOContext *pb_buf;
4236 int ret, size;
4237 uint8_t *buf;
4238
4239
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 330 times.
343 if (!st)
4240 13 return 0;
4241
4242 330 ret = avio_open_dyn_buf(&pb_buf);
4243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
330 if (ret < 0)
4244 return ret;
4245
4246
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 8 times.
330 if (mov->mode & (MODE_MP4|MODE_MOV))
4247 322 mov_write_track_metadata(pb_buf, st, "name", "title");
4248
4249
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 191 times.
330 if (mov->mode & MODE_MP4) {
4250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
139 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4251 return ret;
4252 }
4253
4254
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 327 times.
330 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4255 3 avio_wb32(pb, size + 8);
4256 3 ffio_wfourcc(pb, "udta");
4257 3 avio_write(pb, buf, size);
4258 }
4259 330 ffio_free_dyn_buf(&pb_buf);
4260
4261 330 return 0;
4262 }
4263
4264 343 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4265 MOVTrack *track, AVStream *st)
4266 {
4267 343 int64_t pos = avio_tell(pb);
4268 343 int entry_backup = track->entry;
4269 343 int chunk_backup = track->chunkCount;
4270 int ret;
4271
4272 /* If we want to have an empty moov, but some samples already have been
4273 * buffered (delay_moov), pretend that no samples have been written yet. */
4274
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 249 times.
343 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4275 94 track->chunkCount = track->entry = 0;
4276
4277 343 avio_wb32(pb, 0); /* size */
4278 343 ffio_wfourcc(pb, "trak");
4279 343 mov_write_tkhd_tag(pb, mov, track, st);
4280
4281 av_assert2(mov->use_editlist >= 0);
4282
4283
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 28 times.
343 if (track->start_dts != AV_NOPTS_VALUE) {
4284
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 26 times.
315 if (mov->use_editlist)
4285 289 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4286
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))
4287 av_log(mov->fc, AV_LOG_WARNING,
4288 "Not writing any edit list even though one would have been required\n");
4289 }
4290
4291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
343 if (mov->is_animated_avif)
4292 mov_write_edts_tag(pb, mov, track);
4293
4294
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 329 times.
343 if (track->tref_tag)
4295 14 mov_write_tref_tag(pb, track);
4296
4297
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 343 times.
343 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4298 return ret;
4299
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 341 times.
343 if (track->mode == MODE_PSP)
4300 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4301
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 341 times.
343 if (track->tag == MKTAG('r','t','p',' '))
4302 2 mov_write_udta_sdp(pb, track);
4303
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 154 times.
343 if (track->mode == MODE_MOV) {
4304
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 49 times.
189 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4305 140 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4306
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
140 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4307 1 mov_write_tapt_tag(pb, track);
4308 }
4309 }
4310
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 189 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
189 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4311 mov_write_tapt_tag(pb, track);
4312 }
4313 }
4314 343 mov_write_track_udta_tag(pb, mov, st);
4315 343 track->entry = entry_backup;
4316 343 track->chunkCount = chunk_backup;
4317 343 return update_size(pb, pos);
4318 }
4319
4320 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4321 {
4322 int i, has_audio = 0, has_video = 0;
4323 int64_t pos = avio_tell(pb);
4324 int audio_profile = mov->iods_audio_profile;
4325 int video_profile = mov->iods_video_profile;
4326 for (i = 0; i < mov->nb_tracks; i++) {
4327 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4328 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4329 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4330 }
4331 }
4332 if (audio_profile < 0)
4333 audio_profile = 0xFF - has_audio;
4334 if (video_profile < 0)
4335 video_profile = 0xFF - has_video;
4336 avio_wb32(pb, 0x0); /* size */
4337 ffio_wfourcc(pb, "iods");
4338 avio_wb32(pb, 0); /* version & flags */
4339 put_descr(pb, 0x10, 7);
4340 avio_wb16(pb, 0x004f);
4341 avio_w8(pb, 0xff);
4342 avio_w8(pb, 0xff);
4343 avio_w8(pb, audio_profile);
4344 avio_w8(pb, video_profile);
4345 avio_w8(pb, 0xff);
4346 return update_size(pb, pos);
4347 }
4348
4349 110 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4350 {
4351 110 avio_wb32(pb, 0x20); /* size */
4352 110 ffio_wfourcc(pb, "trex");
4353 110 avio_wb32(pb, 0); /* version & flags */
4354 110 avio_wb32(pb, track->track_id); /* track ID */
4355 110 avio_wb32(pb, 1); /* default sample description index */
4356 110 avio_wb32(pb, 0); /* default sample duration */
4357 110 avio_wb32(pb, 0); /* default sample size */
4358 110 avio_wb32(pb, 0); /* default sample flags */
4359 110 return 0;
4360 }
4361
4362 58 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4363 {
4364 58 int64_t pos = avio_tell(pb);
4365 int i;
4366 58 avio_wb32(pb, 0x0); /* size */
4367 58 ffio_wfourcc(pb, "mvex");
4368
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 58 times.
168 for (i = 0; i < mov->nb_tracks; i++)
4369 110 mov_write_trex_tag(pb, &mov->tracks[i]);
4370 58 return update_size(pb, pos);
4371 }
4372
4373 244 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4374 {
4375 244 int max_track_id = 1, i;
4376 244 int64_t max_track_len = 0;
4377 int version;
4378 int timescale;
4379
4380
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 244 times.
589 for (i = 0; i < mov->nb_tracks; i++) {
4381
3/4
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
345 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4382 630 int64_t max_track_len_temp = av_rescale_rnd(
4383 315 calc_pts_duration(mov, &mov->tracks[i]),
4384 315 mov->movie_timescale,
4385 315 mov->tracks[i].timescale,
4386 AV_ROUND_UP);
4387
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 70 times.
315 if (max_track_len < max_track_len_temp)
4388 245 max_track_len = max_track_len_temp;
4389
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 230 times.
315 if (max_track_id < mov->tracks[i].track_id)
4390 85 max_track_id = mov->tracks[i].track_id;
4391 }
4392 }
4393 /* If using delay_moov, make sure the output is the same as if no
4394 * samples had been written yet. */
4395
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 194 times.
244 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4396 50 max_track_len = 0;
4397 50 max_track_id = 1;
4398 }
4399
4400 244 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4402
4403 244 ffio_wfourcc(pb, "mvhd");
4404 244 avio_w8(pb, version);
4405 244 avio_wb24(pb, 0); /* flags */
4406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (version == 1) {
4407 avio_wb64(pb, mov->time);
4408 avio_wb64(pb, mov->time);
4409 } else {
4410 244 avio_wb32(pb, mov->time); /* creation time */
4411 244 avio_wb32(pb, mov->time); /* modification time */
4412 }
4413
4414 244 timescale = mov->movie_timescale;
4415
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
244 if (mov->mode == MODE_AVIF && !timescale)
4416 timescale = mov->tracks[0].timescale;
4417
4418 244 avio_wb32(pb, timescale);
4419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4420
4421 244 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4422 244 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4423 244 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4424
4425 /* Matrix structure */
4426 244 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4427
4428 244 avio_wb32(pb, 0); /* reserved (preview time) */
4429 244 avio_wb32(pb, 0); /* reserved (preview duration) */
4430 244 avio_wb32(pb, 0); /* reserved (poster time) */
4431 244 avio_wb32(pb, 0); /* reserved (selection time) */
4432 244 avio_wb32(pb, 0); /* reserved (selection duration) */
4433 244 avio_wb32(pb, 0); /* reserved (current time) */
4434 244 avio_wb32(pb, max_track_id + 1); /* Next track id */
4435 244 return 0x6c;
4436 }
4437
4438 88 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4439 AVFormatContext *s)
4440 {
4441 88 avio_wb32(pb, 33); /* size */
4442 88 ffio_wfourcc(pb, "hdlr");
4443 88 avio_wb32(pb, 0);
4444 88 avio_wb32(pb, 0);
4445 88 ffio_wfourcc(pb, "mdir");
4446 88 ffio_wfourcc(pb, "appl");
4447 88 avio_wb32(pb, 0);
4448 88 avio_wb32(pb, 0);
4449 88 avio_w8(pb, 0);
4450 88 return 33;
4451 }
4452
4453 /* helper function to write a data tag with the specified string as data */
4454 57 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4455 {
4456 57 size_t data_len = strlen(data);
4457
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 34 times.
57 if (long_style) {
4458 23 int size = 16 + data_len;
4459 23 avio_wb32(pb, size); /* size */
4460 23 ffio_wfourcc(pb, "data");
4461 23 avio_wb32(pb, 1);
4462 23 avio_wb32(pb, 0);
4463 23 avio_write(pb, data, data_len);
4464 23 return size;
4465 } else {
4466 34 avio_wb16(pb, data_len); /* string length */
4467
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4468 26 lang = ff_mov_iso639_to_lang("und", 1);
4469 34 avio_wb16(pb, lang);
4470 34 avio_write(pb, data, data_len);
4471 34 return data_len + 4;
4472 }
4473 }
4474
4475 57 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4476 const char *value, int lang, int long_style)
4477 {
4478 57 int size = 0;
4479
2/4
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
57 if (value && value[0]) {
4480 57 int64_t pos = avio_tell(pb);
4481 57 avio_wb32(pb, 0); /* size */
4482 57 ffio_wfourcc(pb, name);
4483 57 mov_write_string_data_tag(pb, value, lang, long_style);
4484 57 size = update_size(pb, pos);
4485 }
4486 57 return size;
4487 }
4488
4489 3842 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4490 const char *tag, int *lang)
4491 {
4492 int l, len, len2;
4493 3842 AVDictionaryEntry *t, *t2 = NULL;
4494 char tag2[16];
4495
4496 3842 *lang = 0;
4497
4498
2/2
✓ Branch 1 taken 3789 times.
✓ Branch 2 taken 53 times.
3842 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4499 3789 return NULL;
4500
4501 53 len = strlen(t->key);
4502 53 snprintf(tag2, sizeof(tag2), "%s-", tag);
4503
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 45 times.
53 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4504 8 len2 = strlen(t2->key);
4505
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)
4506
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4507 8 *lang = l;
4508 8 return t;
4509 }
4510 }
4511 45 return t;
4512 }
4513
4514 3754 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4515 const char *name, const char *tag,
4516 int long_style)
4517 {
4518 int lang;
4519 3754 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4520
2/2
✓ Branch 0 taken 3701 times.
✓ Branch 1 taken 53 times.
3754 if (!t)
4521 3701 return 0;
4522 53 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4523 }
4524
4525 /* iTunes bpm number */
4526 88 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4527 {
4528 88 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4529
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 int size = 0, tmpo = t ? atoi(t->value) : 0;
4530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 if (tmpo) {
4531 size = 26;
4532 avio_wb32(pb, size);
4533 ffio_wfourcc(pb, "tmpo");
4534 avio_wb32(pb, size-8); /* size */
4535 ffio_wfourcc(pb, "data");
4536 avio_wb32(pb, 0x15); //type specifier
4537 avio_wb32(pb, 0);
4538 avio_wb16(pb, tmpo); // data
4539 }
4540 88 return size;
4541 }
4542
4543 /* 3GPP TS 26.244 */
4544 88 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4545 {
4546 int lang;
4547 88 int64_t pos = avio_tell(pb);
4548 double latitude, longitude, altitude;
4549 int32_t latitude_fix, longitude_fix, altitude_fix;
4550 88 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4551 88 const char *ptr, *place = "";
4552 char *end;
4553 static const char *astronomical_body = "earth";
4554
1/2
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
88 if (!t)
4555 88 return 0;
4556
4557 ptr = t->value;
4558 latitude = strtod(ptr, &end);
4559 if (end == ptr) {
4560 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4561 return 0;
4562 }
4563 ptr = end;
4564 longitude = strtod(ptr, &end);
4565 if (end == ptr) {
4566 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4567 return 0;
4568 }
4569 ptr = end;
4570 altitude = strtod(ptr, &end);
4571 /* If no altitude was present, the default 0 should be fine */
4572 if (*end == '/')
4573 place = end + 1;
4574
4575 latitude_fix = (int32_t) ((1 << 16) * latitude);
4576 longitude_fix = (int32_t) ((1 << 16) * longitude);
4577 altitude_fix = (int32_t) ((1 << 16) * altitude);
4578
4579 avio_wb32(pb, 0); /* size */
4580 ffio_wfourcc(pb, "loci"); /* type */
4581 avio_wb32(pb, 0); /* version + flags */
4582 avio_wb16(pb, lang);
4583 avio_write(pb, place, strlen(place) + 1);
4584 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4585 avio_wb32(pb, longitude_fix);
4586 avio_wb32(pb, latitude_fix);
4587 avio_wb32(pb, altitude_fix);
4588 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4589 avio_w8(pb, 0); /* additional notes, null terminated string */
4590
4591 return update_size(pb, pos);
4592 }
4593
4594 /* iTunes track or disc number */
4595 176 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4596 AVFormatContext *s, int disc)
4597 {
4598
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 88 times.
176 AVDictionaryEntry *t = av_dict_get(s->metadata,
4599 disc ? "disc" : "track",
4600 NULL, 0);
4601
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 174 times.
176 int size = 0, track = t ? atoi(t->value) : 0;
4602
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 174 times.
176 if (track) {
4603 2 int tracks = 0;
4604 2 char *slash = strchr(t->value, '/');
4605
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4606 2 tracks = atoi(slash + 1);
4607 2 avio_wb32(pb, 32); /* size */
4608
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4609 2 avio_wb32(pb, 24); /* size */
4610 2 ffio_wfourcc(pb, "data");
4611 2 avio_wb32(pb, 0); // 8 bytes empty
4612 2 avio_wb32(pb, 0);
4613 2 avio_wb16(pb, 0); // empty
4614 2 avio_wb16(pb, track); // track / disc number
4615 2 avio_wb16(pb, tracks); // total track / disc number
4616 2 avio_wb16(pb, 0); // empty
4617 2 size = 32;
4618 }
4619 176 return size;
4620 }
4621
4622 528 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4623 const char *name, const char *tag,
4624 int len)
4625 {
4626 528 AVDictionaryEntry *t = NULL;
4627 uint8_t num;
4628 528 int size = 24 + len;
4629
4630
3/4
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 176 times.
528 if (len != 1 && len != 4)
4631 return -1;
4632
4633
2/2
✓ Branch 1 taken 526 times.
✓ Branch 2 taken 2 times.
528 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4634 526 return 0;
4635 2 num = atoi(t->value);
4636
4637 2 avio_wb32(pb, size);
4638 2 ffio_wfourcc(pb, name);
4639 2 avio_wb32(pb, size - 8);
4640 2 ffio_wfourcc(pb, "data");
4641 2 avio_wb32(pb, 0x15);
4642 2 avio_wb32(pb, 0);
4643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4644 2 else avio_w8 (pb, num);
4645
4646 2 return size;
4647 }
4648
4649 88 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4650 {
4651 88 MOVMuxContext *mov = s->priv_data;
4652 88 int64_t pos = 0;
4653
4654
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 88 times.
235 for (int i = 0; i < mov->nb_streams; i++) {
4655 147 MOVTrack *trk = &mov->tracks[i];
4656
4657
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 145 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
147 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4658 145 continue;
4659
4660
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4661 1 pos = avio_tell(pb);
4662 1 avio_wb32(pb, 0);
4663 1 ffio_wfourcc(pb, "covr");
4664 }
4665 2 avio_wb32(pb, 16 + trk->cover_image->size);
4666 2 ffio_wfourcc(pb, "data");
4667 2 avio_wb32(pb, trk->tag);
4668 2 avio_wb32(pb , 0);
4669 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4670 }
4671
4672
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 87 times.
88 return pos ? update_size(pb, pos) : 0;
4673 }
4674
4675 /* iTunes meta data list */
4676 88 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4677 AVFormatContext *s)
4678 {
4679 88 int64_t pos = avio_tell(pb);
4680 88 avio_wb32(pb, 0); /* size */
4681 88 ffio_wfourcc(pb, "ilst");
4682 88 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4683 88 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4684 88 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4685 88 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4686 88 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4687 88 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4688
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4689
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 84 times.
88 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4690 4 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4691 }
4692 88 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4693 88 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4694 88 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4695 88 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4696 88 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4697 88 mov_write_string_metadata(s, pb, "desc", "description",1);
4698 88 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4699 88 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4700 88 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4701 88 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4702 88 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4703 88 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4704 88 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4705 88 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4706 88 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4707 88 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4708 88 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4709 88 mov_write_covr(pb, s);
4710 88 mov_write_trkn_tag(pb, mov, s, 0); // track number
4711 88 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4712 88 mov_write_tmpo_tag(pb, s);
4713 88 return update_size(pb, pos);
4714 }
4715
4716 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4717 AVFormatContext *s)
4718 {
4719 avio_wb32(pb, 33); /* size */
4720 ffio_wfourcc(pb, "hdlr");
4721 avio_wb32(pb, 0);
4722 avio_wb32(pb, 0);
4723 ffio_wfourcc(pb, "mdta");
4724 avio_wb32(pb, 0);
4725 avio_wb32(pb, 0);
4726 avio_wb32(pb, 0);
4727 avio_w8(pb, 0);
4728 return 33;
4729 }
4730
4731 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4732 AVFormatContext *s)
4733 {
4734 const AVDictionaryEntry *t = NULL;
4735 int64_t pos = avio_tell(pb);
4736 int64_t curpos, entry_pos;
4737 int count = 0;
4738
4739 avio_wb32(pb, 0); /* size */
4740 ffio_wfourcc(pb, "keys");
4741 avio_wb32(pb, 0);
4742 entry_pos = avio_tell(pb);
4743 avio_wb32(pb, 0); /* entry count */
4744
4745 while (t = av_dict_iterate(s->metadata, t)) {
4746 size_t key_len = strlen(t->key);
4747 avio_wb32(pb, key_len + 8);
4748 ffio_wfourcc(pb, "mdta");
4749 avio_write(pb, t->key, key_len);
4750 count += 1;
4751 }
4752 curpos = avio_tell(pb);
4753 avio_seek(pb, entry_pos, SEEK_SET);
4754 avio_wb32(pb, count); // rewrite entry count
4755 avio_seek(pb, curpos, SEEK_SET);
4756
4757 return update_size(pb, pos);
4758 }
4759
4760 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4761 AVFormatContext *s)
4762 {
4763 const AVDictionaryEntry *t = NULL;
4764 int64_t pos = avio_tell(pb);
4765 int count = 1; /* keys are 1-index based */
4766
4767 avio_wb32(pb, 0); /* size */
4768 ffio_wfourcc(pb, "ilst");
4769
4770 while (t = av_dict_iterate(s->metadata, t)) {
4771 int64_t entry_pos = avio_tell(pb);
4772 avio_wb32(pb, 0); /* size */
4773 avio_wb32(pb, count); /* key */
4774 mov_write_string_data_tag(pb, t->value, 0, 1);
4775 update_size(pb, entry_pos);
4776 count += 1;
4777 }
4778 return update_size(pb, pos);
4779 }
4780
4781 /* meta data tags */
4782 88 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4783 AVFormatContext *s)
4784 {
4785 88 int size = 0;
4786 88 int64_t pos = avio_tell(pb);
4787 88 avio_wb32(pb, 0); /* size */
4788 88 ffio_wfourcc(pb, "meta");
4789 88 avio_wb32(pb, 0);
4790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4791 mov_write_mdta_hdlr_tag(pb, mov, s);
4792 mov_write_mdta_keys_tag(pb, mov, s);
4793 mov_write_mdta_ilst_tag(pb, mov, s);
4794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 } else if (mov->mode == MODE_AVIF) {
4795 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4796 // We always write the primary item id as 1 since only one track is
4797 // supported for AVIF.
4798 mov_write_pitm_tag(pb, 1);
4799 mov_write_iloc_tag(pb, mov, s);
4800 mov_write_iinf_tag(pb, mov, s);
4801 if (mov->nb_streams > 1)
4802 mov_write_iref_tag(pb, mov, s);
4803 mov_write_iprp_tag(pb, mov, s);
4804 } else {
4805 /* iTunes metadata tag */
4806 88 mov_write_itunes_hdlr_tag(pb, mov, s);
4807 88 mov_write_ilst_tag(pb, mov, s);
4808 }
4809 88 size = update_size(pb, pos);
4810 88 return size;
4811 }
4812
4813 155 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4814 const char *name, const char *key)
4815 {
4816 int len;
4817 AVDictionaryEntry *t;
4818
4819
1/2
✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
155 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4820 155 return 0;
4821
4822 len = strlen(t->value);
4823 if (len > 0) {
4824 int size = len + 8;
4825 avio_wb32(pb, size);
4826 ffio_wfourcc(pb, name);
4827 avio_write(pb, t->value, len);
4828 return size;
4829 }
4830 return 0;
4831 }
4832
4833 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4834 {
4835 int val;
4836 while (*b) {
4837 GET_UTF8(val, *b++, return -1;)
4838 avio_wb16(pb, val);
4839 }
4840 avio_wb16(pb, 0x00);
4841 return 0;
4842 }
4843
4844 static uint16_t language_code(const char *str)
4845 {
4846 return (((str[0] - 0x60) & 0x1F) << 10) +
4847 (((str[1] - 0x60) & 0x1F) << 5) +
4848 (( str[2] - 0x60) & 0x1F);
4849 }
4850
4851 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4852 const char *tag, const char *str)
4853 {
4854 int64_t pos = avio_tell(pb);
4855 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4856 if (!t || !utf8len(t->value))
4857 return 0;
4858 avio_wb32(pb, 0); /* size */
4859 ffio_wfourcc(pb, tag); /* type */
4860 avio_wb32(pb, 0); /* version + flags */
4861 if (!strcmp(tag, "yrrc"))
4862 avio_wb16(pb, atoi(t->value));
4863 else {
4864 avio_wb16(pb, language_code("eng")); /* language */
4865 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4866 if (!strcmp(tag, "albm") &&
4867 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4868 avio_w8(pb, atoi(t->value));
4869 }
4870 return update_size(pb, pos);
4871 }
4872
4873 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4874 {
4875 1 int64_t pos = avio_tell(pb);
4876 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4877
4878 1 avio_wb32(pb, 0); // size
4879 1 ffio_wfourcc(pb, "chpl");
4880 1 avio_wb32(pb, 0x01000000); // version + flags
4881 1 avio_wb32(pb, 0); // unknown
4882 1 avio_w8(pb, nb_chapters);
4883
4884
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4885 4 AVChapter *c = s->chapters[i];
4886 AVDictionaryEntry *t;
4887 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4888
4889
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4890
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4891 4 avio_w8(pb, len);
4892 4 avio_write(pb, t->value, len);
4893 } else
4894 avio_w8(pb, 0);
4895 }
4896 1 return update_size(pb, pos);
4897 }
4898
4899 243 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4900 AVFormatContext *s)
4901 {
4902 AVIOContext *pb_buf;
4903 int ret, size;
4904 uint8_t *buf;
4905
4906 243 ret = avio_open_dyn_buf(&pb_buf);
4907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 if (ret < 0)
4908 return ret;
4909
4910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 if (mov->mode & MODE_3GP) {
4911 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4912 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4913 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4914 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4915 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4916 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4917 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4918 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4919 mov_write_loci_tag(s, pb_buf);
4920
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
243 } 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
4921 155 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4922 155 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4923 155 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4924 155 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4925 155 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4926 155 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4927 // currently ignored by mov.c
4928 155 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4929 // add support for libquicktime, this atom is also actually read by mov.c
4930 155 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4931 155 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4932 155 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4933 155 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4934 155 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4935 155 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4936 155 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4937 155 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4938 } else {
4939 /* iTunes meta data */
4940 88 mov_write_meta_tag(pb_buf, mov, s);
4941 88 mov_write_loci_tag(s, pb_buf);
4942 }
4943
4944
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 242 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
243 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
4945 1 mov_write_chpl_tag(pb_buf, s);
4946
4947
2/2
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 127 times.
243 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4948 116 avio_wb32(pb, size + 8);
4949 116 ffio_wfourcc(pb, "udta");
4950 116 avio_write(pb, buf, size);
4951 }
4952 243 ffio_free_dyn_buf(&pb_buf);
4953
4954 243 return 0;
4955 }
4956
4957 static void mov_write_psp_udta_tag(AVIOContext *pb,
4958 const char *str, const char *lang, int type)
4959 {
4960 int len = utf8len(str) + 1;
4961 if (len <= 0)
4962 return;
4963 avio_wb16(pb, len * 2 + 10); /* size */
4964 avio_wb32(pb, type); /* type */
4965 avio_wb16(pb, language_code(lang)); /* language */
4966 avio_wb16(pb, 0x01); /* ? */
4967 ascii_to_wc(pb, str);
4968 }
4969
4970 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4971 {
4972 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4973 int64_t pos, pos2;
4974
4975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4976 pos = avio_tell(pb);
4977 avio_wb32(pb, 0); /* size placeholder*/
4978 ffio_wfourcc(pb, "uuid");
4979 ffio_wfourcc(pb, "USMT");
4980 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4981 avio_wb32(pb, 0xbb88695c);
4982 avio_wb32(pb, 0xfac9c740);
4983
4984 pos2 = avio_tell(pb);
4985 avio_wb32(pb, 0); /* size placeholder*/
4986 ffio_wfourcc(pb, "MTDT");
4987 avio_wb16(pb, 4);
4988
4989 // ?
4990 avio_wb16(pb, 0x0C); /* size */
4991 avio_wb32(pb, 0x0B); /* type */
4992 avio_wb16(pb, language_code("und")); /* language */
4993 avio_wb16(pb, 0x0); /* ? */
4994 avio_wb16(pb, 0x021C); /* data */
4995
4996 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4997 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4998 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4999 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5000
5001 update_size(pb, pos2);
5002 return update_size(pb, pos);
5003 }
5004
5005 1 return 0;
5006 }
5007
5008 332 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5009 {
5010 AVEncryptionInitInfo *info;
5011 332 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5012 332 st->codecpar->nb_coded_side_data,
5013 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5014
1/2
✓ Branch 0 taken 332 times.
✗ Branch 1 not taken.
332 if (!sd)
5015 332 return 0;
5016
5017 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5018 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5019 int64_t pos;
5020
5021 if (!copy->data_size && !copy->num_key_ids)
5022 continue;
5023
5024 pos = avio_tell(pb);
5025 avio_wb32(pb, 0); /* size placeholder */
5026 ffio_wfourcc(pb, "pssh");
5027 avio_w8(pb, 1); /* version */
5028 avio_wb24(pb, 0);
5029 for (int i = 0; i < copy->system_id_size; i++)
5030 avio_w8(pb, copy->system_id[i]);
5031 avio_wb32(pb, copy->num_key_ids);
5032 for (int i = 0; i < copy->num_key_ids; i++)
5033 for (int j = 0; j < copy->key_id_size; j++)
5034 avio_w8(pb, copy->key_ids[i][j]);
5035 avio_wb32(pb, copy->data_size);
5036 avio_write(pb, copy->data, copy->data_size);
5037 update_size(pb, pos);
5038 }
5039
5040 av_encryption_init_info_free(info);
5041
5042 return 0;
5043 }
5044
5045 315 static void build_chunks(MOVTrack *trk)
5046 {
5047 int i;
5048 315 MOVIentry *chunk = &trk->cluster[0];
5049 315 uint64_t chunkSize = chunk->size;
5050 315 chunk->chunkNum = 1;
5051
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 259 times.
315 if (trk->chunkCount)
5052 56 return;
5053 259 trk->chunkCount = 1;
5054
2/2
✓ Branch 0 taken 14887 times.
✓ Branch 1 taken 259 times.
15146 for (i = 1; i<trk->entry; i++){
5055
2/2
✓ Branch 0 taken 12984 times.
✓ Branch 1 taken 1903 times.
14887 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5056
2/2
✓ Branch 0 taken 12983 times.
✓ Branch 1 taken 1 times.
12984 chunk->stsd_index == trk->cluster[i].stsd_index &&
5057
2/2
✓ Branch 0 taken 12338 times.
✓ Branch 1 taken 645 times.
12983 chunkSize + trk->cluster[i].size < (1<<20)){
5058 12338 chunkSize += trk->cluster[i].size;
5059 12338 chunk->samples_in_chunk += trk->cluster[i].entries;
5060 } else {
5061 2549 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5062 2549 chunk=&trk->cluster[i];
5063 2549 chunkSize = chunk->size;
5064 2549 trk->chunkCount++;
5065 }
5066 }
5067 }
5068
5069 /**
5070 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5071 * the stream ids are used as track ids.
5072 *
5073 * This assumes mov->tracks and s->streams are in the same order and
5074 * there are no gaps in either of them (so mov->tracks[n] refers to
5075 * s->streams[n]).
5076 *
5077 * As an exception, there can be more entries in
5078 * s->streams than in mov->tracks, in which case new track ids are
5079 * generated (starting after the largest found stream id).
5080 */
5081 244 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5082 {
5083 int i;
5084
5085
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 214 times.
244 if (mov->track_ids_ok)
5086 30 return 0;
5087
5088
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->use_stream_ids_as_track_ids) {
5089 1 int next_generated_track_id = 0;
5090
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5091 2 AVStream *st = mov->tracks[i].st;
5092
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5093 2 next_generated_track_id = st->id;
5094 }
5095
5096
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5097
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))
5098 continue;
5099
5100
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;
5101 }
5102 } else {
5103 213 int last_track_id = 0;
5104
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 213 times.
494 for (i = 0; i < mov->nb_tracks; i++) {
5105
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 253 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26 times.
281 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5106 2 continue;
5107
5108 279 last_track_id =
5109 279 mov->tracks[i].track_id = (mov->tracks[i].st
5110 276 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5111
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 3 times.
279 : FFMAX(i, last_track_id)) + 1;
5112 }
5113 }
5114
5115 214 mov->track_ids_ok = 1;
5116
5117 214 return 0;
5118 }
5119
5120 244 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5121 AVFormatContext *s)
5122 {
5123 int i;
5124 244 int64_t pos = avio_tell(pb);
5125 244 avio_wb32(pb, 0); /* size placeholder*/
5126 244 ffio_wfourcc(pb, "moov");
5127
5128 244 mov_setup_track_ids(mov, s);
5129
5130
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 244 times.
589 for (i = 0; i < mov->nb_tracks; i++) {
5131
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 315 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 28 times.
345 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5132 2 continue;
5133
5134 343 mov->tracks[i].time = mov->time;
5135
5136
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 28 times.
343 if (mov->tracks[i].entry)
5137 315 build_chunks(&mov->tracks[i]);
5138 }
5139
5140
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 243 times.
244 if (mov->chapter_track)
5141
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5142 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5143 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5144 }
5145
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 244 times.
589 for (i = 0; i < mov->nb_tracks; i++) {
5146 345 MOVTrack *track = &mov->tracks[i];
5147
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 343 times.
345 if (track->tag == MKTAG('r','t','p',' ')) {
5148 2 track->tref_tag = MKTAG('h','i','n','t');
5149 2 track->tref_id = mov->tracks[track->src_track].track_id;
5150
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 231 times.
343 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5151 112 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5152 112 track->st->codecpar->nb_coded_side_data,
5153 AV_PKT_DATA_FALLBACK_TRACK );
5154
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
112 if (sd && sd->size == sizeof(int)) {
5155 int *fallback = (int *)sd->data;
5156 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5157 track->tref_tag = MKTAG('f','a','l','l');
5158 track->tref_id = mov->tracks[*fallback].track_id;
5159 }
5160 }
5161 }
5162 }
5163
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 244 times.
589 for (i = 0; i < mov->nb_tracks; i++) {
5164
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 332 times.
345 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5165 13 int src_trk = mov->tracks[i].src_track;
5166 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5167 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5168 //src_trk may have a different timescale than the tmcd track
5169 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5170 13 mov->tracks[i].timescale,
5171 13 mov->tracks[src_trk].timescale);
5172 }
5173 }
5174
5175 244 mov_write_mvhd_tag(pb, mov);
5176
4/6
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 89 times.
244 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5177 mov_write_iods_tag(pb, mov);
5178
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 244 times.
589 for (i = 0; i < mov->nb_tracks; i++) {
5179
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 315 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 28 times.
345 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5181
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 13 times.
343 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
343 if (ret < 0)
5183 return ret;
5184 }
5185 }
5186 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5187 * (mov->moov_written != 0)
5188 */
5189
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 184 times.
244 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5190
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
60 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
5191 58 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5192
5193
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 243 times.
244 if (mov->mode == MODE_PSP)
5194 1 mov_write_uuidusmt_tag(pb, s);
5195
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 else if (mov->mode != MODE_AVIF)
5196 243 mov_write_udta_tag(pb, mov, s);
5197
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 244 times.
576 for (i = 0; i < mov->nb_streams; i++)
5198 332 mov_write_pssh_tag(pb, mov->tracks[i].st);
5199
5200 244 return update_size(pb, pos);
5201 }
5202
5203 static void param_write_int(AVIOContext *pb, const char *name, int value)
5204 {
5205 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5206 }
5207
5208 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5209 {
5210 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5211 }
5212
5213 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5214 {
5215 char buf[150];
5216 len = FFMIN(sizeof(buf) / 2 - 1, len);
5217 ff_data_to_hex(buf, value, len, 0);
5218 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5219 }
5220
5221 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5222 {
5223 int64_t pos = avio_tell(pb);
5224 int i;
5225
5226 static const AVUUID uuid = {
5227 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5228 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5229 };
5230
5231 avio_wb32(pb, 0);
5232 ffio_wfourcc(pb, "uuid");
5233 avio_write(pb, uuid, AV_UUID_LEN);
5234 avio_wb32(pb, 0);
5235
5236 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5237 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5238 avio_printf(pb, "<head>\n");
5239 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5240 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5241 LIBAVFORMAT_IDENT);
5242 avio_printf(pb, "</head>\n");
5243 avio_printf(pb, "<body>\n");
5244 avio_printf(pb, "<switch>\n");
5245
5246 mov_setup_track_ids(mov, s);
5247
5248 for (i = 0; i < mov->nb_tracks; i++) {
5249 MOVTrack *track = &mov->tracks[i];
5250 struct mpeg4_bit_rate_values bit_rates =
5251 calculate_mpeg4_bit_rates(track);
5252 const char *type;
5253 int track_id = track->track_id;
5254 char track_name_buf[32] = { 0 };
5255
5256 AVStream *st = track->st;
5257 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5258
5259 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5260 type = "video";
5261 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5262 type = "audio";
5263 } else {
5264 continue;
5265 }
5266
5267 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5268 bit_rates.avg_bit_rate);
5269 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5270 param_write_int(pb, "trackID", track_id);
5271 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5272
5273 /* Build track name piece by piece: */
5274 /* 1. track type */
5275 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5276 /* 2. track language, if available */
5277 if (lang)
5278 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5279 "_%s", lang->value);
5280 /* 3. special type suffix */
5281 /* "_cc" = closed captions, "_ad" = audio_description */
5282 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5283 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5284 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5285 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5286
5287 param_write_string(pb, "trackName", track_name_buf);
5288
5289 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5290 if (track->par->codec_id == AV_CODEC_ID_H264) {
5291 uint8_t *ptr;
5292 int size = track->extradata_size[track->last_stsd_index];
5293 if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5294 &size)) {
5295 param_write_hex(pb, "CodecPrivateData",
5296 ptr ? ptr : track->extradata[track->last_stsd_index],
5297 size);
5298 av_free(ptr);
5299 }
5300 param_write_string(pb, "FourCC", "H264");
5301 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5302 param_write_string(pb, "FourCC", "WVC1");
5303 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5304 track->extradata_size[track->last_stsd_index]);
5305 }
5306 param_write_int(pb, "MaxWidth", track->par->width);
5307 param_write_int(pb, "MaxHeight", track->par->height);
5308 param_write_int(pb, "DisplayWidth", track->par->width);
5309 param_write_int(pb, "DisplayHeight", track->par->height);
5310 } else {
5311 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5312 switch (track->par->profile) {
5313 case AV_PROFILE_AAC_HE_V2:
5314 param_write_string(pb, "FourCC", "AACP");
5315 break;
5316 case AV_PROFILE_AAC_HE:
5317 param_write_string(pb, "FourCC", "AACH");
5318 break;
5319 default:
5320 param_write_string(pb, "FourCC", "AACL");
5321 }
5322 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5323 param_write_string(pb, "FourCC", "WMAP");
5324 }
5325 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5326 track->extradata_size[track->last_stsd_index]);
5327 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5328 track->par->codec_id));
5329 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5330 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5331 0 : track->par->sample_rate);
5332 param_write_int(pb, "BitsPerSample", 16);
5333 param_write_int(pb, "PacketSize", track->par->block_align ?
5334 track->par->block_align : 4);
5335 }
5336 avio_printf(pb, "</%s>\n", type);
5337 }
5338 avio_printf(pb, "</switch>\n");
5339 avio_printf(pb, "</body>\n");
5340 avio_printf(pb, "</smil>\n");
5341
5342 return update_size(pb, pos);
5343 }
5344
5345 148 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5346 {
5347 148 avio_wb32(pb, 16);
5348 148 ffio_wfourcc(pb, "mfhd");
5349 148 avio_wb32(pb, 0);
5350 148 avio_wb32(pb, mov->fragments);
5351 148 return 0;
5352 }
5353
5354 11014 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5355 {
5356
2/2
✓ Branch 0 taken 7472 times.
✓ Branch 1 taken 3542 times.
11014 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5357 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5358 }
5359
5360 242 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5361 MOVTrack *track, int64_t moof_offset)
5362 {
5363 242 int64_t pos = avio_tell(pb);
5364 242 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5365 MOV_TFHD_BASE_DATA_OFFSET;
5366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (!track->entry) {
5367 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5368 } else {
5369 242 flags |= MOV_TFHD_DEFAULT_FLAGS;
5370 }
5371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5372 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5373
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 162 times.
242 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5374 80 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5375 80 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5376 }
5377 /* CMAF requires all values to be explicit in tfhd atoms */
5378
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 234 times.
242 if (mov->flags & FF_MOV_FLAG_CMAF)
5379 8 flags |= MOV_TFHD_STSD_ID;
5380
5381 /* Don't set a default sample size, the silverlight player refuses
5382 * to play files with that set. Don't set a default sample duration,
5383 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5384 * file format says it MUST NOT be set. */
5385
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 212 times.
242 if (track->mode == MODE_ISM)
5386 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5387 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5388
5389 242 avio_wb32(pb, 0); /* size placeholder */
5390 242 ffio_wfourcc(pb, "tfhd");
5391 242 avio_w8(pb, 0); /* version */
5392 242 avio_wb24(pb, flags);
5393
5394 242 avio_wb32(pb, track->track_id); /* track-id */
5395
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 110 times.
242 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5396 132 avio_wb64(pb, moof_offset);
5397
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 234 times.
242 if (flags & MOV_TFHD_STSD_ID) {
5398 8 avio_wb32(pb, 1);
5399 }
5400
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 30 times.
242 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5401 212 track->default_duration = get_cluster_duration(track, 0);
5402 212 avio_wb32(pb, track->default_duration);
5403 }
5404
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 30 times.
242 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5405
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 track->default_size = track->entry ? track->cluster[0].size : 1;
5406 212 avio_wb32(pb, track->default_size);
5407 } else
5408 30 track->default_size = -1;
5409
5410
1/2
✓ Branch 0 taken 242 times.
✗ Branch 1 not taken.
242 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5411 /* Set the default flags based on the second sample, if available.
5412 * If the first sample is different, that can be signaled via a separate field. */
5413
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 12 times.
242 if (track->entry > 1)
5414 230 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5415 else
5416 12 track->default_sample_flags =
5417 12 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5418
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5419 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5420 242 avio_wb32(pb, track->default_sample_flags);
5421 }
5422
5423 242 return update_size(pb, pos);
5424 }
5425
5426 244 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5427 MOVTrack *track, int moof_size,
5428 int first, int end)
5429 {
5430 244 int64_t pos = avio_tell(pb);
5431 244 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5432 int i;
5433
5434
2/2
✓ Branch 0 taken 10308 times.
✓ Branch 1 taken 244 times.
10552 for (i = first; i < end; i++) {
5435
2/2
✓ Branch 1 taken 620 times.
✓ Branch 2 taken 9688 times.
10308 if (get_cluster_duration(track, i) != track->default_duration)
5436 620 flags |= MOV_TRUN_SAMPLE_DURATION;
5437
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 9720 times.
10308 if (track->cluster[i].size != track->default_size)
5438 588 flags |= MOV_TRUN_SAMPLE_SIZE;
5439
4/4
✓ Branch 0 taken 10064 times.
✓ Branch 1 taken 244 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 10054 times.
10308 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5440 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5441 }
5442
3/4
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
244 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5443
2/2
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 124 times.
236 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5444 112 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5445
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 176 times.
244 if (track->flags & MOV_TRACK_CTTS)
5446 68 flags |= MOV_TRUN_SAMPLE_CTS;
5447
5448 244 avio_wb32(pb, 0); /* size placeholder */
5449 244 ffio_wfourcc(pb, "trun");
5450
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 190 times.
244 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5451 54 avio_w8(pb, 1); /* version */
5452 else
5453 190 avio_w8(pb, 0); /* version */
5454 244 avio_wb24(pb, flags);
5455
5456 244 avio_wb32(pb, end - first); /* sample count */
5457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5458 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5459 !mov->first_trun)
5460 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5461 else
5462 244 avio_wb32(pb, moof_size + 8 + track->data_offset +
5463 244 track->cluster[first].pos); /* data offset */
5464
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 132 times.
244 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5465 112 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5466
5467
2/2
✓ Branch 0 taken 10308 times.
✓ Branch 1 taken 244 times.
10552 for (i = first; i < end; i++) {
5468
2/2
✓ Branch 0 taken 808 times.
✓ Branch 1 taken 9500 times.
10308 if (flags & MOV_TRUN_SAMPLE_DURATION)
5469 808 avio_wb32(pb, get_cluster_duration(track, i));
5470
2/2
✓ Branch 0 taken 1238 times.
✓ Branch 1 taken 9070 times.
10308 if (flags & MOV_TRUN_SAMPLE_SIZE)
5471 1238 avio_wb32(pb, track->cluster[i].size);
5472
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 9936 times.
10308 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5473 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5474
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 8328 times.
10308 if (flags & MOV_TRUN_SAMPLE_CTS)
5475 1980 avio_wb32(pb, track->cluster[i].cts);
5476 }
5477
5478 244 mov->first_trun = 0;
5479 244 return update_size(pb, pos);
5480 }
5481
5482 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5483 {
5484 30 int64_t pos = avio_tell(pb);
5485 static const uint8_t uuid[] = {
5486 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5487 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5488 };
5489
5490 30 avio_wb32(pb, 0); /* size placeholder */
5491 30 ffio_wfourcc(pb, "uuid");
5492 30 avio_write(pb, uuid, AV_UUID_LEN);
5493 30 avio_w8(pb, 1);
5494 30 avio_wb24(pb, 0);
5495 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5496 30 avio_wb64(pb, track->end_pts -
5497 30 (track->cluster[0].dts + track->cluster[0].cts));
5498
5499 30 return update_size(pb, pos);
5500 }
5501
5502 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5503 MOVTrack *track, int entry)
5504 {
5505 int n = track->nb_frag_info - 1 - entry, i;
5506 int size = 8 + 16 + 4 + 1 + 16*n;
5507 static const uint8_t uuid[] = {
5508 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5509 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5510 };
5511
5512 if (entry < 0)
5513 return 0;
5514
5515 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5516 avio_wb32(pb, size);
5517 ffio_wfourcc(pb, "uuid");
5518 avio_write(pb, uuid, AV_UUID_LEN);
5519 avio_w8(pb, 1);
5520 avio_wb24(pb, 0);
5521 avio_w8(pb, n);
5522 for (i = 0; i < n; i++) {
5523 int index = entry + 1 + i;
5524 avio_wb64(pb, track->frag_info[index].time);
5525 avio_wb64(pb, track->frag_info[index].duration);
5526 }
5527 if (n < mov->ism_lookahead) {
5528 int free_size = 16 * (mov->ism_lookahead - n);
5529 avio_wb32(pb, free_size);
5530 ffio_wfourcc(pb, "free");
5531 ffio_fill(pb, 0, free_size - 8);
5532 }
5533
5534 return 0;
5535 }
5536
5537 121 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5538 MOVTrack *track)
5539 {
5540 121 int64_t pos = avio_tell(pb);
5541 int i;
5542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 for (i = 0; i < mov->ism_lookahead; i++) {
5543 /* Update the tfrf tag for the last ism_lookahead fragments,
5544 * nb_frag_info - 1 is the next fragment to be written. */
5545 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5546 }
5547 121 avio_seek(pb, pos, SEEK_SET);
5548 121 return 0;
5549 }
5550
5551 74 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5552 int size)
5553 {
5554 int i;
5555
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 74 times.
212 for (i = 0; i < mov->nb_tracks; i++) {
5556 138 MOVTrack *track = &mov->tracks[i];
5557 MOVFragmentInfo *info;
5558
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 121 times.
138 if ((tracks >= 0 && i != tracks) || !track->entry)
5559 17 continue;
5560 121 track->nb_frag_info++;
5561
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 55 times.
121 if (track->nb_frag_info >= track->frag_info_capacity) {
5562 66 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5563
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
66 if (av_reallocp_array(&track->frag_info,
5564 new_capacity,
5565 sizeof(*track->frag_info)))
5566 return AVERROR(ENOMEM);
5567 66 track->frag_info_capacity = new_capacity;
5568 }
5569 121 info = &track->frag_info[track->nb_frag_info - 1];
5570 121 info->offset = avio_tell(pb);
5571 121 info->size = size;
5572 // Try to recreate the original pts for the first packet
5573 // from the fields we have stored
5574 121 info->time = track->cluster[0].dts + track->cluster[0].cts;
5575 121 info->duration = track->end_pts -
5576 121 (track->cluster[0].dts + track->cluster[0].cts);
5577 // If the pts is less than zero, we will have trimmed
5578 // away parts of the media track using an edit list,
5579 // and the corresponding start presentation time is zero.
5580
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 113 times.
121 if (info->time < 0) {
5581 8 info->duration += info->time;
5582 8 info->time = 0;
5583 }
5584 121 info->tfrf_offset = 0;
5585 121 mov_write_tfrf_tags(pb, mov, track);
5586 }
5587 74 return 0;
5588 }
5589
5590 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5591 {
5592 int i;
5593 for (i = 0; i < mov->nb_tracks; i++) {
5594 MOVTrack *track = &mov->tracks[i];
5595 if ((tracks >= 0 && i != tracks) || !track->entry)
5596 continue;
5597 if (track->nb_frag_info > max) {
5598 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5599 track->nb_frag_info = max;
5600 }
5601 }
5602 }
5603
5604 212 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5605 {
5606 212 int64_t pos = avio_tell(pb);
5607
5608 212 avio_wb32(pb, 0); /* size */
5609 212 ffio_wfourcc(pb, "tfdt");
5610 212 avio_w8(pb, 1); /* version */
5611 212 avio_wb24(pb, 0);
5612 212 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5613 212 return update_size(pb, pos);
5614 }
5615
5616 242 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5617 MOVTrack *track, int64_t moof_offset,
5618 int moof_size)
5619 {
5620 242 int64_t pos = avio_tell(pb);
5621 242 int i, start = 0;
5622 242 avio_wb32(pb, 0); /* size placeholder */
5623 242 ffio_wfourcc(pb, "traf");
5624
5625 242 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5626
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 30 times.
242 if (mov->mode != MODE_ISM)
5627 212 mov_write_tfdt_tag(pb, track);
5628
2/2
✓ Branch 0 taken 10066 times.
✓ Branch 1 taken 242 times.
10308 for (i = 1; i < track->entry; i++) {
5629
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10064 times.
10066 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5630 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5631 2 start = i;
5632 }
5633 }
5634 242 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5635
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 212 times.
242 if (mov->mode == MODE_ISM) {
5636 30 mov_write_tfxd_tag(pb, track);
5637
5638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5639 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5640
5641 if (track->nb_frag_info > 0) {
5642 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5643 if (!info->tfrf_offset)
5644 info->tfrf_offset = avio_tell(pb);
5645 }
5646 avio_wb32(pb, 8 + size);
5647 ffio_wfourcc(pb, "free");
5648 ffio_fill(pb, 0, size);
5649 }
5650 }
5651
5652
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
242 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5653 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5654
5655 242 return update_size(pb, pos);
5656 }
5657
5658 148 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5659 int tracks, int moof_size)
5660 {
5661 148 int64_t pos = avio_tell(pb);
5662 int i;
5663
5664 148 avio_wb32(pb, 0); /* size placeholder */
5665 148 ffio_wfourcc(pb, "moof");
5666 148 mov->first_trun = 1;
5667
5668 148 mov_write_mfhd_tag(pb, mov);
5669
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 148 times.
424 for (i = 0; i < mov->nb_tracks; i++) {
5670 276 MOVTrack *track = &mov->tracks[i];
5671
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 222 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 30 times.
276 if (tracks >= 0 && i != tracks)
5672 24 continue;
5673
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 242 times.
252 if (!track->entry)
5674 10 continue;
5675
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
242 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5676 mov_write_pssh_tag(pb, track->st);
5677 242 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5678 }
5679
5680 148 return update_size(pb, pos);
5681 }
5682
5683 72 static int mov_write_sidx_tag(AVIOContext *pb,
5684 MOVTrack *track, int ref_size, int total_sidx_size)
5685 {
5686 72 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5687 int64_t presentation_time, duration, offset;
5688 unsigned starts_with_SAP;
5689 int i, entries;
5690
5691
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 if (track->entry) {
5692 72 entries = 1;
5693 72 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5694 72 track->start_dts - track->start_cts;
5695 72 duration = track->end_pts -
5696 72 (track->cluster[0].dts + track->cluster[0].cts);
5697 72 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5698
5699 // pts<0 should be cut away using edts
5700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (presentation_time < 0) {
5701 duration += presentation_time;
5702 presentation_time = 0;
5703 }
5704 } else {
5705 entries = track->nb_frag_info;
5706 if (entries <= 0)
5707 return 0;
5708 presentation_time = track->frag_info[0].time;
5709 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5710 if (presentation_time > 0)
5711 presentation_time -= track->start_dts + track->start_cts;
5712 }
5713
5714 72 avio_wb32(pb, 0); /* size */
5715 72 ffio_wfourcc(pb, "sidx");
5716 72 avio_w8(pb, 1); /* version */
5717 72 avio_wb24(pb, 0);
5718 72 avio_wb32(pb, track->track_id); /* reference_ID */
5719 72 avio_wb32(pb, track->timescale); /* timescale */
5720 72 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5721 72 offset_pos = avio_tell(pb);
5722 72 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5723 72 avio_wb16(pb, 0); /* reserved */
5724
5725 72 avio_wb16(pb, entries); /* reference_count */
5726
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 for (i = 0; i < entries; i++) {
5727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (!track->entry) {
5728 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5729 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5730 }
5731 duration = track->frag_info[i].duration;
5732 ref_size = track->frag_info[i].size;
5733 starts_with_SAP = 1;
5734 }
5735 72 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5736 72 avio_wb32(pb, duration); /* subsegment_duration */
5737 72 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5738 }
5739
5740 72 end_pos = avio_tell(pb);
5741 72 offset = pos + total_sidx_size - end_pos;
5742 72 avio_seek(pb, offset_pos, SEEK_SET);
5743 72 avio_wb64(pb, offset);
5744 72 avio_seek(pb, end_pos, SEEK_SET);
5745 72 return update_size(pb, pos);
5746 }
5747
5748 21 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5749 int tracks, int ref_size)
5750 {
5751 int i, round, ret;
5752 AVIOContext *avio_buf;
5753 21 int total_size = 0;
5754
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 21 times.
63 for (round = 0; round < 2; round++) {
5755 // First run one round to calculate the total size of all
5756 // sidx atoms.
5757 // This would be much simpler if we'd only write one sidx
5758 // atom, for the first track in the moof.
5759
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
42 if (round == 0) {
5760
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5761 return ret;
5762 } else {
5763 21 avio_buf = pb;
5764 }
5765
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 42 times.
114 for (i = 0; i < mov->nb_tracks; i++) {
5766 72 MOVTrack *track = &mov->tracks[i];
5767
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
72 if (tracks >= 0 && i != tracks)
5768 continue;
5769 // When writing a sidx for the full file, entry is 0, but
5770 // we want to include all tracks. ref_size is 0 in this case,
5771 // since we read it from frag_info instead.
5772
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
72 if (!track->entry && ref_size > 0)
5773 continue;
5774 72 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5775 total_size);
5776 }
5777
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
42 if (round == 0)
5778 21 total_size = ffio_close_null_buf(avio_buf);
5779 }
5780 21 return 0;
5781 }
5782
5783 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5784 {
5785 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5786 MOVTrack *first_track;
5787 int flags = 24;
5788
5789 /* PRFT should be associated with at most one track. So, choosing only the
5790 * first track. */
5791 if (tracks > 0)
5792 return 0;
5793 first_track = &(mov->tracks[0]);
5794
5795 if (!first_track->entry) {
5796 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5797 return 0;
5798 }
5799
5800 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5801 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5802 return 0;
5803 }
5804
5805 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5806 if (first_track->cluster[0].prft.wallclock) {
5807 /* Round the NTP time to whole milliseconds. */
5808 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5809 NTP_OFFSET_US);
5810 flags = first_track->cluster[0].prft.flags;
5811 } else
5812 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5813 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5814 pts_us = av_rescale_q(first_track->cluster[0].pts,
5815 first_track->st->time_base, AV_TIME_BASE_Q);
5816 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5817 } else {
5818 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5819 mov->write_prft);
5820 return 0;
5821 }
5822
5823 avio_wb32(pb, 0); // Size place holder
5824 ffio_wfourcc(pb, "prft"); // Type
5825 avio_w8(pb, 1); // Version
5826 avio_wb24(pb, flags); // Flags
5827 avio_wb32(pb, first_track->track_id); // reference track ID
5828 avio_wb64(pb, ntp_ts); // NTP time stamp
5829 avio_wb64(pb, first_track->cluster[0].pts); //media time
5830 return update_size(pb, pos);
5831 }
5832
5833 74 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5834 int64_t mdat_size)
5835 {
5836 AVIOContext *avio_buf;
5837 int ret, moof_size;
5838
5839
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5840 return ret;
5841 74 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5842 74 moof_size = ffio_close_null_buf(avio_buf);
5843
5844
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 53 times.
74 if (mov->flags & FF_MOV_FLAG_DASH &&
5845
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5846 21 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5847
5848
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
74 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
5849 mov_write_prft_tag(pb, mov, tracks);
5850
5851
1/2
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
74 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5853 mov->ism_lookahead) {
5854
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
5855 return ret;
5856
1/2
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
74 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5857
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5858 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5859 }
5860 }
5861
5862 74 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5863 }
5864
5865 62 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5866 {
5867 62 int64_t pos = avio_tell(pb);
5868 int i;
5869
5870 62 avio_wb32(pb, 0); /* size placeholder */
5871 62 ffio_wfourcc(pb, "tfra");
5872 62 avio_w8(pb, 1); /* version */
5873 62 avio_wb24(pb, 0);
5874
5875 62 avio_wb32(pb, track->track_id);
5876 62 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5877 62 avio_wb32(pb, track->nb_frag_info);
5878
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 62 times.
177 for (i = 0; i < track->nb_frag_info; i++) {
5879 115 avio_wb64(pb, track->frag_info[i].time);
5880 115 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5881 115 avio_w8(pb, 1); /* traf number */
5882 115 avio_w8(pb, 1); /* trun number */
5883 115 avio_w8(pb, 1); /* sample number */
5884 }
5885
5886 62 return update_size(pb, pos);
5887 }
5888
5889 34 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5890 {
5891 AVIOContext *mfra_pb;
5892 int i, ret, sz;
5893 uint8_t *buf;
5894
5895 34 ret = avio_open_dyn_buf(&mfra_pb);
5896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (ret < 0)
5897 return ret;
5898
5899 34 avio_wb32(mfra_pb, 0); /* size placeholder */
5900 34 ffio_wfourcc(mfra_pb, "mfra");
5901 /* An empty mfra atom is enough to indicate to the publishing point that
5902 * the stream has ended. */
5903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (mov->flags & FF_MOV_FLAG_ISML)
5904 goto done_mfra;
5905
5906
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 34 times.
98 for (i = 0; i < mov->nb_tracks; i++) {
5907 64 MOVTrack *track = &mov->tracks[i];
5908
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 2 times.
64 if (track->nb_frag_info)
5909 62 mov_write_tfra_tag(mfra_pb, track);
5910 }
5911
5912 34 avio_wb32(mfra_pb, 16);
5913 34 ffio_wfourcc(mfra_pb, "mfro");
5914 34 avio_wb32(mfra_pb, 0); /* version + flags */
5915 34 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5916
5917 34 done_mfra:
5918
5919 34 sz = update_size(mfra_pb, 0);
5920 34 ret = avio_get_dyn_buf(mfra_pb, &buf);
5921 34 avio_write(pb, buf, ret);
5922 34 ffio_free_dyn_buf(&mfra_pb);
5923
5924 34 return sz;
5925 }
5926
5927 178 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5928 {
5929 178 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5930
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 32 times.
178 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5931
5932 178 mov->mdat_pos = avio_tell(pb);
5933 178 avio_wb32(pb, 0); /* size placeholder*/
5934 178 ffio_wfourcc(pb, "mdat");
5935 178 return 0;
5936 }
5937
5938 428 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5939 int has_h264, int has_video, int write_minor)
5940 {
5941 428 MOVMuxContext *mov = s->priv_data;
5942 428 int minor = 0x200;
5943
5944
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 428 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
428 if (mov->major_brand && strlen(mov->major_brand) >= 4)
5945 ffio_wfourcc(pb, mov->major_brand);
5946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428 times.
428 else if (mov->mode == MODE_3GP) {
5947 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5948 minor = has_h264 ? 0x100 : 0x200;
5949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428 times.
428 } else if (mov->mode == MODE_AVIF) {
5950 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5951 minor = 0;
5952
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428 times.
428 } else if (mov->mode & MODE_3G2) {
5953 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5954 minor = has_h264 ? 0x20000 : 0x10000;
5955
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 426 times.
428 } else if (mov->mode == MODE_PSP)
5956 2 ffio_wfourcc(pb, "MSNV");
5957
4/4
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 304 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 60 times.
426 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
5958
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 56 times.
62 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5959 6 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5960
4/4
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 304 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 92 times.
420 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5961 24 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5962
3/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 304 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
396 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5963 ffio_wfourcc(pb, "iso4");
5964
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 304 times.
396 else if (mov->mode == MODE_MP4)
5965 92 ffio_wfourcc(pb, "isom");
5966
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 302 times.
304 else if (mov->mode == MODE_IPOD)
5967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5968
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 294 times.
302 else if (mov->mode == MODE_ISM)
5969 8 ffio_wfourcc(pb, "isml");
5970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
294 else if (mov->mode == MODE_F4V)
5971 ffio_wfourcc(pb, "f4v ");
5972 else
5973 294 ffio_wfourcc(pb, "qt ");
5974
5975
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 214 times.
428 if (write_minor)
5976 214 avio_wb32(pb, minor);
5977 428 }
5978
5979 214 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5980 {
5981 214 MOVMuxContext *mov = s->priv_data;
5982 214 int64_t pos = avio_tell(pb);
5983 214 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
5984 214 int has_iamf = 0;
5985
5986 #if CONFIG_IAMFENC
5987
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 209 times.
214 for (int i = 0; i < s->nb_stream_groups; i++) {
5988 5 const AVStreamGroup *stg = s->stream_groups[i];
5989
5990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5991 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5992 5 has_iamf = 1;
5993 5 break;
5994 }
5995 }
5996 #endif
5997
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 214 times.
488 for (int i = 0; i < mov->nb_streams; i++) {
5998 274 AVStream *st = mov->tracks[i].st;
5999
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 272 times.
274 if (is_cover_image(st))
6000 2 continue;
6001
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 89 times.
272 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6002 183 has_video = 1;
6003
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 237 times.
272 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6004 35 has_h264 = 1;
6005
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 271 times.
272 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6006 1 has_av1 = 1;
6007
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 4 times.
272 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6008
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 1 times.
268 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6009
2/4
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
534 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6010 267 av_packet_side_data_get(st->codecpar->coded_side_data,
6011 267 st->codecpar->nb_coded_side_data,
6012 AV_PKT_DATA_DOVI_CONF))
6013 5 has_dolby = 1;
6014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 272 times.
272 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6015 has_id3 = 1;
6016 }
6017
6018 214 avio_wb32(pb, 0); /* size */
6019 214 ffio_wfourcc(pb, "ftyp");
6020
6021 // Write major brand
6022 214 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6023 // Write the major brand as the first compatible brand as well
6024 214 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6025
6026 // Write compatible brands, ensuring that we don't write the major brand as a
6027 // compatible brand a second time.
6028
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 210 times.
214 if (mov->mode == MODE_ISM) {
6029 4 ffio_wfourcc(pb, "piff");
6030
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 } else if (mov->mode == MODE_AVIF) {
6031 const AVPixFmtDescriptor *pix_fmt_desc =
6032 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6033 const int depth = pix_fmt_desc->comp[0].depth;
6034 if (mov->is_animated_avif) {
6035 // For animated AVIF, major brand is "avis". Add "avif" as a
6036 // compatible brand.
6037 ffio_wfourcc(pb, "avif");
6038 ffio_wfourcc(pb, "msf1");
6039 ffio_wfourcc(pb, "iso8");
6040 }
6041 ffio_wfourcc(pb, "mif1");
6042 ffio_wfourcc(pb, "miaf");
6043 if (depth == 8 || depth == 10) {
6044 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6045 // computing that is based on chroma subsampling type. 420 chroma
6046 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6047 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6048 // 444 chroma subsampling.
6049 ffio_wfourcc(pb, "MA1A");
6050 } else {
6051 // 420 chroma subsampling.
6052 ffio_wfourcc(pb, "MA1B");
6053 }
6054 }
6055
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 147 times.
210 } else if (mov->mode != MODE_MOV) {
6056 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6057 // brand, if not already the major brand. This is compatible with users that
6058 // don't understand tfdt.
6059
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (mov->mode == MODE_MP4) {
6060
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 60 times.
61 if (mov->flags & FF_MOV_FLAG_CMAF)
6061 1 ffio_wfourcc(pb, "cmfc");
6062
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 3 times.
61 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6063 28 ffio_wfourcc(pb, "iso6");
6064
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 60 times.
61 if (has_av1)
6065 1 ffio_wfourcc(pb, "av01");
6066
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 58 times.
61 if (has_dolby)
6067 3 ffio_wfourcc(pb, "dby1");
6068
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 56 times.
61 if (has_iamf)
6069 5 ffio_wfourcc(pb, "iamf");
6070 } else {
6071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6072 ffio_wfourcc(pb, "iso6");
6073
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6074 ffio_wfourcc(pb, "iso5");
6075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6076 ffio_wfourcc(pb, "iso4");
6077 }
6078 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6079
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 13 times.
63 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6080 // write isom for mp4 only if it it's not the major brand already.
6081
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 46 times.
50 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6082 4 ffio_wfourcc(pb, "isom");
6083 50 ffio_wfourcc(pb, "iso2");
6084
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 29 times.
50 if (has_h264)
6085 21 ffio_wfourcc(pb, "avc1");
6086 }
6087 }
6088
6089
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 153 times.
214 if (mov->mode == MODE_MP4)
6090 61 ffio_wfourcc(pb, "mp41");
6091
6092
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
214 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6093 ffio_wfourcc(pb, "dash");
6094
6095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (has_id3)
6096 ffio_wfourcc(pb, "aid3");
6097
6098 214 return update_size(pb, pos);
6099 }
6100
6101 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6102 {
6103 1 AVStream *video_st = s->streams[0];
6104 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6105 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6106 1 int audio_rate = audio_par->sample_rate;
6107 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6108
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 :
6109 0;
6110 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6111 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6112
6113
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) {
6114 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6115 return AVERROR(EINVAL);
6116 }
6117
6118 1 avio_wb32(pb, 0x94); /* size */
6119 1 ffio_wfourcc(pb, "uuid");
6120 1 ffio_wfourcc(pb, "PROF");
6121
6122 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6123 1 avio_wb32(pb, 0xbb88695c);
6124 1 avio_wb32(pb, 0xfac9c740);
6125
6126 1 avio_wb32(pb, 0x0); /* ? */
6127 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6128
6129 1 avio_wb32(pb, 0x14); /* size */
6130 1 ffio_wfourcc(pb, "FPRF");
6131 1 avio_wb32(pb, 0x0); /* ? */
6132 1 avio_wb32(pb, 0x0); /* ? */
6133 1 avio_wb32(pb, 0x0); /* ? */
6134
6135 1 avio_wb32(pb, 0x2c); /* size */
6136 1 ffio_wfourcc(pb, "APRF"); /* audio */
6137 1 avio_wb32(pb, 0x0);
6138 1 avio_wb32(pb, 0x2); /* TrackID */
6139 1 ffio_wfourcc(pb, "mp4a");
6140 1 avio_wb32(pb, 0x20f);
6141 1 avio_wb32(pb, 0x0);
6142 1 avio_wb32(pb, audio_kbitrate);
6143 1 avio_wb32(pb, audio_kbitrate);
6144 1 avio_wb32(pb, audio_rate);
6145 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6146
6147 1 avio_wb32(pb, 0x34); /* size */
6148 1 ffio_wfourcc(pb, "VPRF"); /* video */
6149 1 avio_wb32(pb, 0x0);
6150 1 avio_wb32(pb, 0x1); /* TrackID */
6151
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6152 1 ffio_wfourcc(pb, "avc1");
6153 1 avio_wb16(pb, 0x014D);
6154 1 avio_wb16(pb, 0x0015);
6155 } else {
6156 ffio_wfourcc(pb, "mp4v");
6157 avio_wb16(pb, 0x0000);
6158 avio_wb16(pb, 0x0103);
6159 }
6160 1 avio_wb32(pb, 0x0);
6161 1 avio_wb32(pb, video_kbitrate);
6162 1 avio_wb32(pb, video_kbitrate);
6163 1 avio_wb32(pb, frame_rate);
6164 1 avio_wb32(pb, frame_rate);
6165 1 avio_wb16(pb, video_par->width);
6166 1 avio_wb16(pb, video_par->height);
6167 1 avio_wb32(pb, 0x010001); /* ? */
6168
6169 1 return 0;
6170 }
6171
6172 214 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6173 {
6174 214 MOVMuxContext *mov = s->priv_data;
6175 int i;
6176
6177 214 mov_write_ftyp_tag(pb,s);
6178
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->mode == MODE_PSP) {
6179 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6180
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6181 2 AVStream *st = mov->tracks[i].st;
6182
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6183 continue;
6184
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6185 1 video_streams_nb++;
6186
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6187 1 audio_streams_nb++;
6188 else
6189 other_streams_nb++;
6190 }
6191
6192
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) {
6193 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6194 return AVERROR(EINVAL);
6195 }
6196 1 return mov_write_uuidprof_tag(pb, s);
6197 }
6198 213 return 0;
6199 }
6200
6201 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6202 {
6203 8 uint32_t c = -1;
6204 8 int i, closed_gop = 0;
6205
6206
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6207 368 c = (c << 8) + pkt->data[i];
6208
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6209 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6210
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6211 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6212
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
6213 8 *flags = MOV_SYNC_SAMPLE;
6214 else
6215 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6216 8 break;
6217 }
6218 }
6219 8 return 0;
6220 }
6221
6222 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6223 {
6224 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6225 int seq = 0, entry = 0;
6226 int key = pkt->flags & AV_PKT_FLAG_KEY;
6227 start = find_next_marker(pkt->data, end);
6228 for (next = start; next < end; start = next) {
6229 next = find_next_marker(start + 4, end);
6230 switch (AV_RB32(start)) {
6231 case VC1_CODE_SEQHDR:
6232 seq = 1;
6233 break;
6234 case VC1_CODE_ENTRYPOINT:
6235 entry = 1;
6236 break;
6237 case VC1_CODE_SLICE:
6238 trk->vc1_info.slices = 1;
6239 break;
6240 }
6241 }
6242 if (!trk->entry && trk->vc1_info.first_packet_seen)
6243 trk->vc1_info.first_frag_written = 1;
6244 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6245 /* First packet in first fragment */
6246 trk->vc1_info.first_packet_seq = seq;
6247 trk->vc1_info.first_packet_entry = entry;
6248 trk->vc1_info.first_packet_seen = 1;
6249 } else if ((seq && !trk->vc1_info.packet_seq) ||
6250 (entry && !trk->vc1_info.packet_entry)) {
6251 int i;
6252 for (i = 0; i < trk->entry; i++)
6253 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6254 trk->has_keyframes = 0;
6255 if (seq)
6256 trk->vc1_info.packet_seq = 1;
6257 if (entry)
6258 trk->vc1_info.packet_entry = 1;
6259 if (!trk->vc1_info.first_frag_written) {
6260 /* First fragment */
6261 if ((!seq || trk->vc1_info.first_packet_seq) &&
6262 (!entry || trk->vc1_info.first_packet_entry)) {
6263 /* First packet had the same headers as this one, readd the
6264 * sync sample flag. */
6265 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6266 trk->has_keyframes = 1;
6267 }
6268 }
6269 }
6270 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6271 key = seq && entry;
6272 else if (trk->vc1_info.packet_seq)
6273 key = seq;
6274 else if (trk->vc1_info.packet_entry)
6275 key = entry;
6276 if (key) {
6277 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6278 trk->has_keyframes++;
6279 }
6280 }
6281
6282 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6283 {
6284 int length;
6285
6286 if (pkt->size < 8)
6287 return;
6288
6289 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6290 if (length < 8 || length > pkt->size)
6291 return;
6292
6293 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6294 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6295 trk->has_keyframes++;
6296 }
6297
6298 return;
6299 }
6300
6301 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6302 {
6303 89 MOVMuxContext *mov = s->priv_data;
6304 int ret, buf_size;
6305 uint8_t *buf;
6306 int i, offset;
6307
6308
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!track->mdat_buf)
6309 1 return 0;
6310
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 86 times.
88 if (!mov->mdat_buf) {
6311
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6312 return ret;
6313 }
6314 88 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6315
6316 88 offset = avio_tell(mov->mdat_buf);
6317 88 avio_write(mov->mdat_buf, buf, buf_size);
6318 88 ffio_free_dyn_buf(&track->mdat_buf);
6319
6320
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 88 times.
176 for (i = track->entries_flushed; i < track->entry; i++)
6321 88 track->cluster[i].pos += offset;
6322 88 track->entries_flushed = track->entry;
6323 88 return 0;
6324 }
6325
6326 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6327 {
6328 2 MOVMuxContext *mov = s->priv_data;
6329 2 AVPacket *squashed_packet = mov->pkt;
6330 2 int ret = AVERROR_BUG;
6331
6332
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
6333 2 case AV_CODEC_ID_TTML: {
6334 2 int had_packets = !!track->squashed_packet_queue.head;
6335
6336
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_generate_squashed_ttml_packet(s, track, squashed_packet)) < 0) {
6337 goto finish_squash;
6338 }
6339
6340 // We have generated a padding packet (no actual input packets in
6341 // queue) and its duration is zero. Skipping writing it.
6342
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (!had_packets && squashed_packet->duration == 0) {
6343 goto finish_squash;
6344 }
6345
6346 2 track->end_reliable = 1;
6347 2 break;
6348 }
6349 default:
6350 ret = AVERROR(EINVAL);
6351 goto finish_squash;
6352 }
6353
6354 2 squashed_packet->stream_index = track->st->index;
6355
6356 2 ret = mov_write_single_packet(s, squashed_packet);
6357
6358 2 finish_squash:
6359 2 av_packet_unref(squashed_packet);
6360
6361 2 return ret;
6362 }
6363
6364 325 static int mov_write_squashed_packets(AVFormatContext *s)
6365 {
6366 325 MOVMuxContext *mov = s->priv_data;
6367
6368
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 325 times.
798 for (int i = 0; i < mov->nb_streams; i++) {
6369 473 MOVTrack *track = &mov->tracks[i];
6370 473 int ret = AVERROR_BUG;
6371
6372
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 471 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
473 if (track->squash_fragment_samples_to_one && !track->entry) {
6373
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6374 av_log(s, AV_LOG_ERROR,
6375 "Failed to write squashed packet for %s stream with "
6376 "index %d and track id %d. Error: %s\n",
6377 avcodec_get_name(track->st->codecpar->codec_id),
6378 track->st->index, track->track_id,
6379 av_err2str(ret));
6380 return ret;
6381 }
6382 }
6383 }
6384
6385 325 return 0;
6386 }
6387
6388 129 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6389 int64_t ref_pos)
6390 {
6391 int i;
6392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
129 if (!track->entry)
6393 return 0;
6394
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 121 times.
129 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6395
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6396 124 track->cluster[i].pos += ref_pos + track->data_offset;
6397
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
8 if (track->cluster_written == 0 && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) {
6398 // First flush. If this was a case of not using empty moov, reset chunking.
6399
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < track->entry; i++) {
6400 18 track->cluster[i].chunkNum = 0;
6401 18 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6402 }
6403 }
6404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6405 8 track->entry_written + track->entry,
6406 sizeof(*track->cluster)))
6407 return AVERROR(ENOMEM);
6408 8 memcpy(&track->cluster_written[track->entry_written],
6409 8 track->cluster, track->entry * sizeof(*track->cluster));
6410 8 track->entry_written += track->entry;
6411 }
6412 129 track->entry = 0;
6413 129 track->entries_flushed = 0;
6414 129 track->end_reliable = 0;
6415 129 return 0;
6416 }
6417
6418 111 static int mov_flush_fragment(AVFormatContext *s, int force)
6419 {
6420 111 MOVMuxContext *mov = s->priv_data;
6421 111 int i, first_track = -1;
6422 111 int64_t mdat_size = 0, mdat_start = 0;
6423 int ret;
6424 111 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6425
6426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111 times.
111 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6427 return 0;
6428
6429 // Check if we have any tracks that require squashing.
6430 // In that case, we'll have to write the packet here.
6431
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 111 times.
111 if ((ret = mov_write_squashed_packets(s)) < 0)
6432 return ret;
6433
6434 // Try to fill in the duration of the last packet in each stream
6435 // from queued packets in the interleave queues. If the flushing
6436 // of fragments was triggered automatically by an AVPacket, we
6437 // already have reliable info for the end of that track, but other
6438 // tracks may need to be filled in.
6439
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 111 times.
310 for (i = 0; i < mov->nb_streams; i++) {
6440 199 MOVTrack *track = &mov->tracks[i];
6441
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 39 times.
199 if (!track->end_reliable) {
6442 160 const AVPacket *pkt = ff_interleaved_peek(s, i);
6443
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 154 times.
160 if (pkt) {
6444 int64_t offset, dts, pts;
6445 6 ff_get_muxer_ts_offset(s, i, &offset);
6446 6 pts = pkt->pts + offset;
6447 6 dts = pkt->dts + offset;
6448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6449 dts += track->dts_shift;
6450 6 track->track_duration = dts - track->start_dts;
6451
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6452 6 track->end_pts = pts;
6453 else
6454 track->end_pts = dts;
6455 }
6456 }
6457 }
6458
6459
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 111 times.
316 for (i = 0; i < mov->nb_tracks; i++) {
6460 205 MOVTrack *track = &mov->tracks[i];
6461
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 157 times.
205 if (track->entry <= 1)
6462 48 continue;
6463 // Sample durations are calculated as the diff of dts values,
6464 // but for the last sample in a fragment, we don't know the dts
6465 // of the first sample in the next fragment, so we have to rely
6466 // on what was set as duration in the AVPacket. Not all callers
6467 // set this though, so we might want to replace it with an
6468 // estimate if it currently is zero.
6469
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 2 times.
157 if (get_cluster_duration(track, track->entry - 1) != 0)
6470 155 continue;
6471 // Use the duration (i.e. dts diff) of the second last sample for
6472 // the last one. This is a wild guess (and fatal if it turns out
6473 // to be too long), but probably the best we can do - having a zero
6474 // duration is bad as well.
6475 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6476 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6477
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6478 2 av_log(s, AV_LOG_WARNING,
6479 "Estimating the duration of the last packet in a "
6480 "fragment, consider setting the duration field in "
6481 "AVPacket instead.\n");
6482 2 mov->missing_duration_warned = 1;
6483 }
6484 }
6485
6486
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 87 times.
111 if (!mov->moov_written) {
6487 24 int64_t pos = avio_tell(s->pb);
6488 uint8_t *buf;
6489 int buf_size, moov_size;
6490
6491
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 20 times.
66 for (i = 0; i < mov->nb_tracks; i++)
6492
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 42 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
46 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6493 4 break;
6494 /* Don't write the initial moov unless all tracks have data */
6495
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
24 if (i < mov->nb_tracks && !force)
6496 2 return 0;
6497
6498 22 moov_size = get_moov_size(s);
6499
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 22 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6500 42 mov->tracks[i].data_offset = pos + moov_size + 8;
6501
6502 22 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6503
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6504 18 mov_write_identification(s->pb, s);
6505
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6506 return ret;
6507
6508
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6510 mov->reserved_header_pos = avio_tell(s->pb);
6511 18 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6512 18 mov->moov_written = 1;
6513 18 return 0;
6514 }
6515
6516 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6517 4 avio_wb32(s->pb, buf_size + 8);
6518 4 ffio_wfourcc(s->pb, "mdat");
6519 4 avio_write(s->pb, buf, buf_size);
6520 4 ffio_free_dyn_buf(&mov->mdat_buf);
6521
6522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6523 mov->reserved_header_pos = avio_tell(s->pb);
6524
6525 4 mov->moov_written = 1;
6526 4 mov->mdat_size = 0;
6527
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6528 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6529 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6530 4 return 0;
6531 }
6532
6533
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 85 times.
87 if (mov->frag_interleave) {
6534
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6535 4 MOVTrack *track = &mov->tracks[i];
6536 int ret;
6537
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6538 return ret;
6539 }
6540
6541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6542 return 0;
6543 2 mdat_size = avio_tell(mov->mdat_buf);
6544 }
6545
6546
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 87 times.
246 for (i = 0; i < mov->nb_tracks; i++) {
6547 159 MOVTrack *track = &mov->tracks[i];
6548
4/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 136 times.
159 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6549 23 track->data_offset = 0;
6550 else
6551 136 track->data_offset = mdat_size;
6552
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 84 times.
159 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6553 75 has_video = 1;
6554
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 if (first_video_track) {
6555
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 13 times.
75 if (track->entry)
6556 62 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6557 75 first_video_track = 0;
6558 }
6559 }
6560
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 121 times.
159 if (!track->entry)
6561 38 continue;
6562
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 3 times.
121 if (track->mdat_buf)
6563 118 mdat_size += avio_tell(track->mdat_buf);
6564
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 51 times.
121 if (first_track < 0)
6565 70 first_track = i;
6566 }
6567
6568
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 70 times.
87 if (!mdat_size)
6569 17 return 0;
6570
6571
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 4 times.
70 avio_write_marker(s->pb,
6572 70 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6573
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 7 times.
70 (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);
6574
6575
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 70 times.
199 for (i = first_track; i < mov->nb_tracks; i++) {
6576 129 MOVTrack *track = &mov->tracks[i];
6577 129 int buf_size, write_moof = 1, moof_tracks = -1;
6578 uint8_t *buf;
6579
6580
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 121 times.
129 if (!track->entry)
6581 9 continue;
6582
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 106 times.
121 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6583 15 mdat_size = avio_tell(track->mdat_buf);
6584 15 moof_tracks = i;
6585 } else {
6586 106 write_moof = i == first_track;
6587 }
6588
6589
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 47 times.
121 if (write_moof) {
6590 74 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6591
6592 74 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6593 74 mov->fragments++;
6594
6595 74 avio_wb32(s->pb, mdat_size + 8);
6596 74 ffio_wfourcc(s->pb, "mdat");
6597 74 mdat_start = avio_tell(s->pb);
6598 }
6599
6600 121 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6601
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 3 times.
121 if (!mov->frag_interleave) {
6602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (!track->mdat_buf)
6603 continue;
6604 118 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6605 118 track->mdat_buf = NULL;
6606 } else {
6607
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (!mov->mdat_buf)
6608 1 continue;
6609 2 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6610 2 mov->mdat_buf = NULL;
6611 }
6612
6613 120 avio_write(s->pb, buf, buf_size);
6614 120 av_free(buf);
6615 }
6616
6617 70 mov->mdat_size = 0;
6618
6619 70 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6620 70 return 0;
6621 }
6622
6623 63 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6624 {
6625 63 MOVMuxContext *mov = s->priv_data;
6626 63 int had_moov = mov->moov_written;
6627 63 int ret = mov_flush_fragment(s, force);
6628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if (ret < 0)
6629 return ret;
6630 // If using delay_moov, the first flush only wrote the moov,
6631 // not the actual moof+mdat pair, thus flush once again.
6632
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4 times.
63 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6633 9 ret = mov_flush_fragment(s, force);
6634 63 return ret;
6635 }
6636
6637 36445 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6638 {
6639 int64_t ref;
6640 uint64_t duration;
6641
6642
2/2
✓ Branch 0 taken 35792 times.
✓ Branch 1 taken 653 times.
36445 if (trk->entry) {
6643 35792 ref = trk->cluster[trk->entry - 1].dts;
6644
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 538 times.
653 } else if ( trk->start_dts != AV_NOPTS_VALUE
6645
2/2
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 8 times.
115 && !trk->frag_discont) {
6646 107 ref = trk->start_dts + trk->track_duration;
6647 } else
6648 546 ref = pkt->dts; // Skip tests for the first packet
6649
6650
2/2
✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 34790 times.
36445 if (trk->dts_shift != AV_NOPTS_VALUE) {
6651 /* With negative CTS offsets we have set an offset to the DTS,
6652 * reverse this for the check. */
6653 1655 ref -= trk->dts_shift;
6654 }
6655
6656 36445 duration = pkt->dts - ref;
6657
2/4
✓ Branch 0 taken 36445 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36445 times.
36445 if (pkt->dts < ref || duration >= INT_MAX) {
6658 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6659 duration, pkt->dts, pkt->stream_index);
6660
6661 pkt->dts = ref + 1;
6662 pkt->pts = AV_NOPTS_VALUE;
6663 }
6664
6665
2/4
✓ Branch 0 taken 36445 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36445 times.
36445 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6666 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6667 return AVERROR(EINVAL);
6668 }
6669 36445 return 0;
6670 }
6671
6672 18241 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6673 {
6674 18241 MOVMuxContext *mov = s->priv_data;
6675 18241 AVIOContext *pb = s->pb;
6676 MOVTrack *trk;
6677 AVCodecParameters *par;
6678 AVProducerReferenceTime *prft;
6679 18241 unsigned int samples_in_chunk = 0;
6680 18241 int size = pkt->size, ret = 0, offset = 0;
6681 size_t prft_size;
6682 18241 uint8_t *reformatted_data = NULL;
6683
6684
2/2
✓ Branch 0 taken 18195 times.
✓ Branch 1 taken 46 times.
18241 if (pkt->stream_index < s->nb_streams)
6685 18195 trk = s->streams[pkt->stream_index]->priv_data;
6686 else // Timecode or chapter
6687 46 trk = &mov->tracks[pkt->stream_index];
6688 18241 par = trk->par;
6689
6690 18241 ret = check_pkt(s, trk, pkt);
6691
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18241 times.
18241 if (ret < 0)
6692 return ret;
6693
6694
2/2
✓ Branch 0 taken 17639 times.
✓ Branch 1 taken 602 times.
18241 if (pkt->pts != AV_NOPTS_VALUE &&
6695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17639 times.
17639 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
6696 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6697 return AVERROR_PATCHWELCOME;
6698 }
6699
6700
3/4
✓ Branch 0 taken 12849 times.
✓ Branch 1 taken 5392 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12849 times.
18241 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6701 int ret;
6702
4/4
✓ Branch 0 taken 2174 times.
✓ Branch 1 taken 3218 times.
✓ Branch 2 taken 1936 times.
✓ Branch 3 taken 238 times.
5392 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
6703
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 5066 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
5154 if (mov->frag_interleave && mov->fragments > 0) {
6704
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6705
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6706 return ret;
6707 }
6708 }
6709
6710
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 4948 times.
5154 if (!trk->mdat_buf) {
6711
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
206 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6712 return ret;
6713 }
6714 5154 pb = trk->mdat_buf;
6715 } else {
6716
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6717
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6718 return ret;
6719 }
6720 238 pb = mov->mdat_buf;
6721 }
6722 }
6723
6724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18241 times.
18241 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6725 /* We must find out how many AMR blocks there are in one packet */
6726 static const uint16_t packed_size[16] =
6727 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6728 int len = 0;
6729
6730 while (len < size && samples_in_chunk < 100) {
6731 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6732 samples_in_chunk++;
6733 }
6734 if (samples_in_chunk > 1) {
6735 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6736 return -1;
6737 }
6738
1/2
✓ Branch 0 taken 18241 times.
✗ Branch 1 not taken.
18241 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18241 times.
18241 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6740 samples_in_chunk = trk->par->frame_size;
6741
2/2
✓ Branch 0 taken 1384 times.
✓ Branch 1 taken 16857 times.
18241 } else if (trk->sample_size)
6742 1384 samples_in_chunk = size / trk->sample_size;
6743 else
6744 16857 samples_in_chunk = 1;
6745
6746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18241 times.
18241 if (samples_in_chunk < 1) {
6747 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6748 return AVERROR_PATCHWELCOME;
6749 }
6750
6751 /* copy extradata if it exists */
6752
3/4
✓ Branch 0 taken 5466 times.
✓ Branch 1 taken 12775 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5466 times.
18241 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
6753 !TAG_IS_AVCI(trk->tag) &&
6754 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6755 trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
6756 if (!trk->extradata[0]) {
6757 ret = AVERROR(ENOMEM);
6758 goto err;
6759 }
6760 trk->extradata_size[0] = par->extradata_size;
6761 }
6762
6763
2/2
✓ Branch 0 taken 18126 times.
✓ Branch 1 taken 115 times.
18241 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6764
2/2
✓ Branch 0 taken 15534 times.
✓ Branch 1 taken 2592 times.
18126 par->codec_id == AV_CODEC_ID_H264 ||
6765
2/2
✓ Branch 0 taken 15379 times.
✓ Branch 1 taken 155 times.
15534 par->codec_id == AV_CODEC_ID_HEVC ||
6766
2/2
✓ Branch 0 taken 15369 times.
✓ Branch 1 taken 10 times.
15379 par->codec_id == AV_CODEC_ID_VVC ||
6767
1/2
✓ Branch 0 taken 15369 times.
✗ Branch 1 not taken.
15369 par->codec_id == AV_CODEC_ID_VP9 ||
6768
2/2
✓ Branch 0 taken 15069 times.
✓ Branch 1 taken 300 times.
15369 par->codec_id == AV_CODEC_ID_EVC ||
6769
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 15069 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3148 times.
18241 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
6770
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)) {
6771 /* copy frame to create needed atoms */
6772 24 trk->extradata_size[0] = size;
6773 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
6775 ret = AVERROR(ENOMEM);
6776 goto err;
6777 }
6778 24 memcpy(trk->extradata[0], pkt->data, size);
6779 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6780 }
6781
6782 18241 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
6783
4/6
✓ Branch 0 taken 18241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 18239 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
18241 if (pkt->size && sd && sd->size > 0) {
6784 int i;
6785
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < trk->stsd_count; i++) {
6786
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
6787 1 break;
6788 }
6789
6790
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (i < trk->stsd_count)
6791 1 trk->last_stsd_index = i;
6792
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (trk->stsd_count <= INT_MAX - 1) {
6793 1 int new_count = trk->stsd_count + 1;
6794 1 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
6795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!extradata)
6796 return AVERROR(ENOMEM);
6797 1 trk->extradata = extradata;
6798
6799 1 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
6800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!extradata_size)
6801 return AVERROR(ENOMEM);
6802 1 trk->extradata_size = extradata_size;
6803
6804 1 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
6805
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!trk->extradata[trk->stsd_count])
6806 return AVERROR(ENOMEM);
6807
6808 1 trk->extradata_size[trk->stsd_count] = sd->size;
6809 1 trk->last_stsd_index = trk->stsd_count;
6810 1 trk->stsd_count = new_count;
6811 } else
6812 return AVERROR(ENOMEM);
6813 }
6814
6815
3/4
✓ Branch 0 taken 5584 times.
✓ Branch 1 taken 12657 times.
✓ Branch 2 taken 5584 times.
✗ Branch 3 not taken.
18241 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5584 times.
5584 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6817 if (!trk->st->nb_frames) {
6818 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6819 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6820 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6821 return -1;
6822 }
6823 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6824 }
6825
3/4
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 15649 times.
✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
18241 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
6826
16/30
✓ Branch 0 taken 498 times.
✓ Branch 1 taken 2094 times.
✓ Branch 2 taken 498 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 498 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 498 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 498 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 498 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 498 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 498 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 498 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 498 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 498 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 498 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 498 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 498 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 498 times.
✗ Branch 29 not taken.
2592 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
6827 /* from x264 or from bytestream H.264 */
6828 /* NAL reformatting needed */
6829
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6830 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6831 &size);
6832 if (ret < 0)
6833 return ret;
6834 avio_write(pb, reformatted_data, size);
6835 } else {
6836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6837 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6838 if (size < 0) {
6839 ret = size;
6840 goto err;
6841 }
6842 } else {
6843 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6844 }
6845 }
6846
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 17588 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
17743 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
6847
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
299 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
6848 /* extradata is Annex B, assume the bitstream is too and convert it */
6849 144 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6850
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
144 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6851 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6852 &size, filter_ps, NULL);
6853 if (ret < 0)
6854 return ret;
6855 avio_write(pb, reformatted_data, size);
6856 } else {
6857
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6858 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6859 if (size < 0) {
6860 ret = size;
6861 goto err;
6862 }
6863 } else {
6864 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6865 }
6866 }
6867
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 17589 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
17599 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
6868
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
6869 /* extradata is Annex B, assume the bitstream is too and convert it */
6870
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) {
6871 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6872 &size, 0, NULL);
6873 if (ret < 0)
6874 return ret;
6875 avio_write(pb, reformatted_data, size);
6876 } else {
6877 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6878 }
6879
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17585 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
17589 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
6880
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) {
6881 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6882 &size, &offset);
6883 if (ret < 0)
6884 return ret;
6885 avio_write(pb, reformatted_data, size);
6886 } else {
6887 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6888
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]) {
6889 mov->avif_extent_length[pkt->stream_index] = size;
6890 }
6891 }
6892
6893
2/2
✓ Branch 0 taken 17198 times.
✓ Branch 1 taken 387 times.
17585 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6894
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 16546 times.
17198 par->codec_id == AV_CODEC_ID_EAC3) {
6895 1039 size = handle_eac3(mov, pkt, trk);
6896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6897 return size;
6898
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6899 1 goto end;
6900 1038 avio_write(pb, pkt->data, size);
6901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16546 times.
16546 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6902 size = 8;
6903
6904 for (int i = 0; i < pkt->size; i += 3) {
6905 if (pkt->data[i] == 0xFC) {
6906 size += 2;
6907 }
6908 }
6909 avio_wb32(pb, size);
6910 ffio_wfourcc(pb, "cdat");
6911 for (int i = 0; i < pkt->size; i += 3) {
6912 if (pkt->data[i] == 0xFC) {
6913 avio_w8(pb, pkt->data[i + 1]);
6914 avio_w8(pb, pkt->data[i + 2]);
6915 }
6916 }
6917
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16543 times.
16546 } else if (par->codec_id == AV_CODEC_ID_APV) {
6918 3 ff_isom_parse_apvc(trk->apv, pkt, s);
6919 3 avio_wb32(s->pb, pkt->size);
6920 3 size += 4;
6921
6922 3 avio_write(s->pb, pkt->data, pkt->size);
6923 } else {
6924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16543 times.
16543 if (trk->cenc.aes_ctr) {
6925 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
6926 int extradata_size = trk->extradata_size[trk->last_stsd_index];
6927 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
6928 int nal_size_length = (extradata[4] & 0x3) + 1;
6929 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6930 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
6931 int nal_size_length = (extradata[21] & 0x3) + 1;
6932 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6933 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6934 ret = AVERROR_PATCHWELCOME;
6935 } else if(par->codec_id == AV_CODEC_ID_AV1) {
6936 av_assert0(size == pkt->size);
6937 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
6938 if (ret > 0) {
6939 size = ret;
6940 ret = 0;
6941 }
6942 } else {
6943 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6944 }
6945
6946 if (ret) {
6947 goto err;
6948 }
6949 } else {
6950 16543 avio_write(pb, pkt->data, size);
6951 }
6952 }
6953
6954
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 17960 times.
18240 if (trk->entry >= trk->cluster_capacity) {
6955 280 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6956 280 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 if (!cluster) {
6958 ret = AVERROR(ENOMEM);
6959 goto err;
6960 }
6961 280 trk->cluster = cluster;
6962 280 trk->cluster_capacity = new_capacity;
6963 }
6964
6965 18240 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6966 18240 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
6967 18240 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6968 18240 trk->cluster[trk->entry].chunkNum = 0;
6969 18240 trk->cluster[trk->entry].size = size;
6970 18240 trk->cluster[trk->entry].entries = samples_in_chunk;
6971 18240 trk->cluster[trk->entry].dts = pkt->dts;
6972 18240 trk->cluster[trk->entry].pts = pkt->pts;
6973
2/2
✓ Branch 0 taken 18238 times.
✓ Branch 1 taken 2 times.
18240 if (!trk->squash_fragment_samples_to_one &&
6974
4/4
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 17898 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 264 times.
18238 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
6975
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 4 times.
76 if (!trk->frag_discont) {
6976 /* First packet of a new fragment. We already wrote the duration
6977 * of the last packet of the previous fragment based on track_duration,
6978 * which might not exactly match our dts. Therefore adjust the dts
6979 * of this packet to be what the previous packets duration implies. */
6980 72 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6981 /* We also may have written the pts and the corresponding duration
6982 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6983 * the next fragment. This means the cts of the first sample must
6984 * be the same in all fragments, unless end_pts was updated by
6985 * the packet causing the fragment to be written. */
6986
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 58 times.
72 if ((mov->flags & FF_MOV_FLAG_DASH &&
6987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6988
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 48 times.
58 mov->mode == MODE_ISM)
6989 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6990 } else {
6991 /* New fragment, but discontinuous from previous fragments.
6992 * Pretend the duration sum of the earlier fragments is
6993 * pkt->dts - trk->start_dts. */
6994 4 trk->end_pts = AV_NOPTS_VALUE;
6995 4 trk->frag_discont = 0;
6996 }
6997 }
6998
6999
6/6
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 17898 times.
✓ Branch 2 taken 266 times.
✓ Branch 3 taken 76 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 234 times.
18240 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7000
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 11 times.
32 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7001 /* Not using edit lists and shifting the first track to start from zero.
7002 * If the other streams start from a later timestamp, we won't be able
7003 * to signal the difference in starting time without an edit list.
7004 * Thus move the timestamp for this first sample to 0, increasing
7005 * its duration instead. */
7006 21 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7007 }
7008
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 17995 times.
18240 if (trk->start_dts == AV_NOPTS_VALUE) {
7009 245 trk->start_dts = pkt->dts;
7010
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 239 times.
245 if (trk->frag_discont) {
7011
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7012 /* Pretend the whole stream started at pts=0, with earlier fragments
7013 * already written. If the stream started at pts=0, the duration sum
7014 * of earlier fragments would have been pkt->pts. */
7015 4 trk->start_dts = pkt->dts - pkt->pts;
7016 } else {
7017 /* Pretend the whole stream started at dts=0, with earlier fragments
7018 * already written, with a duration summing up to pkt->dts. */
7019 2 trk->start_dts = 0;
7020 }
7021 6 trk->frag_discont = 0;
7022
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 206 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 31 times.
239 } else if (pkt->dts && mov->moov_written)
7023 2 av_log(s, AV_LOG_WARNING,
7024 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7025 "already has been written. Set the delay_moov flag to handle "
7026 "this case.\n",
7027 pkt->stream_index, pkt->dts);
7028 }
7029 18240 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7030 18240 trk->last_sample_is_subtitle_end = 0;
7031
7032
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 17638 times.
18240 if (pkt->pts == AV_NOPTS_VALUE) {
7033 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7034 602 pkt->pts = pkt->dts;
7035 }
7036
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 17222 times.
18240 if (pkt->dts != pkt->pts)
7037 1018 trk->flags |= MOV_TRACK_CTTS;
7038 18240 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7039 18240 trk->cluster[trk->entry].flags = 0;
7040
5/6
✓ Branch 0 taken 17974 times.
✓ Branch 1 taken 266 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 17925 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 49 times.
18240 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7041 266 trk->start_cts = pkt->pts - pkt->dts;
7042
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 17970 times.
18240 if (trk->end_pts == AV_NOPTS_VALUE)
7043 270 trk->end_pts = trk->cluster[trk->entry].dts +
7044 270 trk->cluster[trk->entry].cts + pkt->duration;
7045 else
7046 17970 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7047 trk->cluster[trk->entry].cts +
7048 pkt->duration);
7049
7050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18240 times.
18240 if (par->codec_id == AV_CODEC_ID_VC1) {
7051 mov_parse_vc1_frame(pkt, trk);
7052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18240 times.
18240 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7053 mov_parse_truehd_frame(pkt, trk);
7054
2/2
✓ Branch 0 taken 13598 times.
✓ Branch 1 taken 4642 times.
18240 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7055
4/4
✓ Branch 0 taken 6358 times.
✓ Branch 1 taken 7240 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6349 times.
13598 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7056
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7057 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7059 trk->flags |= MOV_TRACK_STPS;
7060 } else {
7061 13590 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7062 }
7063
1/2
✓ Branch 0 taken 13598 times.
✗ Branch 1 not taken.
13598 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7064 13598 trk->has_keyframes++;
7065 }
7066
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18233 times.
18240 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7067 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7068 7 trk->has_disposable++;
7069 }
7070
7071 18240 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7072
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18240 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18240 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7073 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7074 else
7075 18240 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7076
7077 18240 trk->entry++;
7078 18240 trk->sample_count += samples_in_chunk;
7079 18240 mov->mdat_size += size;
7080
7081
3/4
✓ Branch 0 taken 18158 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
18240 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7082 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7084 : NULL, size);
7085
7086 18241 end:
7087 18241 err:
7088
7089
1/2
✓ Branch 0 taken 18241 times.
✗ Branch 1 not taken.
18241 if (pkt->data != reformatted_data)
7090 18241 av_free(reformatted_data);
7091 18241 return ret;
7092 }
7093
7094 18204 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7095 {
7096 18204 MOVMuxContext *mov = s->priv_data;
7097 18204 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7098 18204 AVCodecParameters *par = trk->par;
7099 18204 int64_t frag_duration = 0;
7100 18204 int size = pkt->size;
7101
7102 18204 int ret = check_pkt(s, trk, pkt);
7103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18204 times.
18204 if (ret < 0)
7104 return ret;
7105
7106
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18199 times.
18204 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7107
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7108 10 mov->tracks[i].frag_discont = 1;
7109 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7110 }
7111
7112
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 17394 times.
18204 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7113
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 799 times.
810 if (trk->dts_shift == AV_NOPTS_VALUE)
7114 11 trk->dts_shift = pkt->pts - pkt->dts;
7115 810 pkt->dts += trk->dts_shift;
7116 }
7117
7118
1/2
✓ Branch 0 taken 18204 times.
✗ Branch 1 not taken.
18204 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7119
2/2
✓ Branch 0 taken 12618 times.
✓ Branch 1 taken 5586 times.
18204 trk->par->codec_id == AV_CODEC_ID_AAC ||
7120
2/2
✓ Branch 0 taken 12614 times.
✓ Branch 1 taken 4 times.
12618 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7121
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12559 times.
12614 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7122 size_t side_size;
7123 5645 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7124 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7125
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5639 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
5645 if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
7126 6 void *newextra = av_memdup(side, side_size);
7127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7128 return AVERROR(ENOMEM);
7129 6 av_free(trk->extradata[trk->last_stsd_index]);
7130 6 trk->extradata[trk->last_stsd_index] = newextra;
7131 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7132 }
7133 }
7134
7135
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18195 times.
18204 if (!pkt->size) {
7136
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) {
7137 4 trk->start_dts = pkt->dts;
7138
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7139 4 trk->start_cts = pkt->pts - pkt->dts;
7140 else
7141 trk->start_cts = 0;
7142 }
7143
7144 9 return 0; /* Discard 0 sized packets */
7145 }
7146
7147
4/4
✓ Branch 0 taken 17889 times.
✓ Branch 1 taken 306 times.
✓ Branch 2 taken 17865 times.
✓ Branch 3 taken 24 times.
18195 if (trk->entry && pkt->stream_index < mov->nb_streams)
7148 17865 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7149 17865 s->streams[pkt->stream_index]->time_base,
7150 17865 AV_TIME_BASE_Q);
7151
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 17934 times.
18195 if ((mov->max_fragment_duration &&
7152
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7153
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18191 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18191 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7154
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 14518 times.
18191 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7155
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 2548 times.
3673 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7156
4/4
✓ Branch 0 taken 1101 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 1076 times.
✓ Branch 3 taken 25 times.
1125 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18166 times.
18166 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7158
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (frag_duration >= mov->min_fragment_duration) {
7159
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (trk->entry) {
7160 // Set the duration of this track to line up with the next
7161 // sample in this track. This avoids relying on AVPacket
7162 // duration, but only helps for this particular track, not
7163 // for the other ones that are flushed at the same time.
7164 //
7165 // If we have trk->entry == 0, no fragment will be written
7166 // for this track, and we can't adjust the track end here.
7167 29 trk->track_duration = pkt->dts - trk->start_dts;
7168
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (pkt->pts != AV_NOPTS_VALUE)
7169 29 trk->end_pts = pkt->pts;
7170 else
7171 trk->end_pts = pkt->dts;
7172 29 trk->end_reliable = 1;
7173 }
7174 29 mov_auto_flush_fragment(s, 0);
7175 }
7176 }
7177
7178 18195 return ff_mov_write_packet(s, pkt);
7179 }
7180
7181 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7182 int stream_index,
7183 int64_t dts) {
7184 3 MOVMuxContext *mov = s->priv_data;
7185 3 AVPacket *end = mov->pkt;
7186 3 uint8_t data[2] = {0};
7187 int ret;
7188
7189 3 end->size = sizeof(data);
7190 3 end->data = data;
7191 3 end->pts = dts;
7192 3 end->dts = dts;
7193 3 end->duration = 0;
7194 3 end->stream_index = stream_index;
7195
7196 3 ret = mov_write_single_packet(s, end);
7197 3 av_packet_unref(end);
7198
7199 3 return ret;
7200 }
7201
7202 #if CONFIG_IAMFENC
7203 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7204 {
7205 uint8_t *data;
7206 int ret;
7207
7208
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7209 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7211 return ret;
7212 }
7213
7214 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7215 275 s->streams[pkt->stream_index]->id, pkt);
7216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7217 return ret;
7218
7219
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7220 220 return AVERROR(EAGAIN);
7221
7222 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7223 55 trk->iamf_buf = NULL;
7224
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7226 // Either all or none of the packets for a single
7227 // IA Sample may be empty.
7228 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7229 "stream #%d\n", pkt->stream_index);
7230 ret = AVERROR_INVALIDDATA;
7231 }
7232 5 av_free(data);
7233 5 return ret;
7234 }
7235
7236 50 av_buffer_unref(&pkt->buf);
7237 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7239 av_free(data);
7240 return AVERROR(ENOMEM);
7241 }
7242 50 pkt->data = data;
7243 50 pkt->size = ret;
7244 50 pkt->stream_index = trk->first_iamf_idx;
7245
7246 50 return avio_open_dyn_buf(&trk->iamf_buf);
7247 }
7248 #endif
7249
7250 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7251 {
7252 2 int64_t pos = avio_tell(pb);
7253 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7254 2 const char *value = "";
7255
7256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7257
7258 2 avio_write_marker(pb,
7259 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7260 AVIO_DATA_MARKER_BOUNDARY_POINT);
7261
7262 2 avio_wb32(pb, 0); /* size */
7263 2 ffio_wfourcc(pb, "emsg");
7264 2 avio_w8(pb, 1); /* version */
7265 2 avio_wb24(pb, 0);
7266 2 avio_wb32(pb, st->time_base.den); /* timescale */
7267 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7268 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7269 2 avio_wb32(pb, 0); /* id */
7270 /* null terminated UTF8 strings */
7271 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7272 2 avio_write(pb, value, strlen(value) + 1);
7273 2 avio_write(pb, pkt->data, pkt->size);
7274
7275 2 return update_size(pb, pos);
7276 }
7277
7278 18534 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7279 {
7280 18534 MOVMuxContext *mov = s->priv_data;
7281 MOVTrack *trk;
7282
7283
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 18497 times.
18534 if (!pkt) {
7284 37 mov_flush_fragment(s, 1);
7285 37 return 1;
7286 }
7287
7288
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18495 times.
18497 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7289 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7290 2 return 0;
7291 }
7292
7293 18495 trk = s->streams[pkt->stream_index]->priv_data;
7294
7295 #if CONFIG_IAMFENC
7296
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 18220 times.
18495 if (trk->iamf) {
7297 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7298
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7299
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7300 220 return 0;
7301 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7302 "for stream #%d\n", trk->st->index);
7303 return ret;
7304 }
7305 }
7306 #endif
7307
7308
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18273 times.
18275 if (is_cover_image(trk->st)) {
7309 int ret;
7310
7311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7312 if (trk->st->nb_frames == 1)
7313 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7314 " ignoring.\n", pkt->stream_index);
7315 return 0;
7316 }
7317
7318
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7319 return ret;
7320
7321 2 return 0;
7322 } else {
7323 int i;
7324
7325
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18264 times.
18273 if (!pkt->size)
7326 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7327
7328 /*
7329 * Subtitles require special handling.
7330 *
7331 * 1) For full compliance, every track must have a sample at
7332 * dts == 0, which is rarely true for subtitles. So, as soon
7333 * as we see any packet with dts > 0, write an empty subtitle
7334 * at dts == 0 for any subtitle track with no samples in it.
7335 *
7336 * 2) For each subtitle track, check if the current packet's
7337 * dts is past the duration of the last subtitle sample. If
7338 * so, we now need to write an end sample for that subtitle.
7339 *
7340 * This must be done conditionally to allow for subtitles that
7341 * immediately replace each other, in which case an end sample
7342 * is not needed, and is, in fact, actively harmful.
7343 *
7344 * 3) See mov_write_trailer for how the final end sample is
7345 * handled.
7346 */
7347
2/2
✓ Branch 0 taken 33092 times.
✓ Branch 1 taken 18264 times.
51356 for (i = 0; i < mov->nb_tracks; i++) {
7348 33092 MOVTrack *trk = &mov->tracks[i];
7349 int ret;
7350
7351
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 33089 times.
33092 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7352
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7353
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)) {
7354 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7356 2 trk->last_sample_is_subtitle_end = 1;
7357 }
7358 }
7359
7360
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 18190 times.
18264 if (trk->squash_fragment_samples_to_one) {
7361 /*
7362 * If the track has to have its samples squashed into one sample,
7363 * we just take it into the track's queue.
7364 * This will then be utilized as the samples get written in either
7365 * mov_flush_fragment or when the mux is finalized in
7366 * mov_write_trailer.
7367 */
7368 74 int ret = AVERROR_BUG;
7369
7370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
7371 av_log(s, AV_LOG_ERROR,
7372 "Packets without a valid presentation timestamp are "
7373 "not supported with packet squashing!\n");
7374 return AVERROR(EINVAL);
7375 }
7376
7377 /* The following will reset pkt and is only allowed to be used
7378 * because we return immediately. afterwards. */
7379
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7380 pkt, NULL, 0)) < 0) {
7381 return ret;
7382 }
7383
7384 74 return 0;
7385 }
7386
7387
7388
4/4
✓ Branch 0 taken 7827 times.
✓ Branch 1 taken 10363 times.
✓ Branch 2 taken 3704 times.
✓ Branch 3 taken 4123 times.
18190 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7389 3704 AVPacket *opkt = pkt;
7390 int reshuffle_ret, ret;
7391
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3679 times.
3704 if (trk->is_unaligned_qt_rgb) {
7392
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;
7393 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7394 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7396 return reshuffle_ret;
7397 } else
7398 3679 reshuffle_ret = 0;
7399
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3466 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3704 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7400 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7402 goto fail;
7403
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7404 5 trk->pal_done++;
7405
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2874 times.
3699 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7406
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7408 ret = av_packet_make_writable(pkt);
7409 if (ret < 0)
7410 goto fail;
7411 for (i = 0; i < pkt->size; i++)
7412 pkt->data[i] = ~pkt->data[i];
7413 }
7414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3704 times.
3704 if (reshuffle_ret) {
7415 ret = mov_write_single_packet(s, pkt);
7416 fail:
7417 if (reshuffle_ret)
7418 av_packet_free(&pkt);
7419 return ret;
7420 }
7421 }
7422
7423 18190 return mov_write_single_packet(s, pkt);
7424 }
7425 }
7426
7427 // QuickTime chapters involve an additional text track with the chapter names
7428 // as samples, and a tref pointing from the other tracks to the chapter one.
7429 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7430 {
7431 static const uint8_t stub_header[] = {
7432 // TextSampleEntry
7433 0x00, 0x00, 0x00, 0x01, // displayFlags
7434 0x00, 0x00, // horizontal + vertical justification
7435 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7436 // BoxRecord
7437 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7438 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7439 // StyleRecord
7440 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7441 0x00, 0x01, // fontID
7442 0x00, 0x00, // fontStyleFlags + fontSize
7443 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7444 // FontTableBox
7445 0x00, 0x00, 0x00, 0x0D, // box size
7446 'f', 't', 'a', 'b', // box atom name
7447 0x00, 0x01, // entry count
7448 // FontRecord
7449 0x00, 0x01, // font ID
7450 0x00, // font name length
7451 };
7452 1 MOVMuxContext *mov = s->priv_data;
7453 1 MOVTrack *track = &mov->tracks[tracknum];
7454 1 AVPacket *pkt = mov->pkt;
7455 int i, len;
7456 int ret;
7457
7458 1 track->mode = mov->mode;
7459 1 track->tag = MKTAG('t','e','x','t');
7460 1 track->timescale = mov->movie_timescale;
7461 1 track->par = avcodec_parameters_alloc();
7462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7463 return AVERROR(ENOMEM);
7464 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7465 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7467 return ret;
7468 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7469
7470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7471 track->stsd_count = 1;
7472 track->extradata = av_calloc(1, sizeof(*track->extradata));
7473 track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7474 if (!track->extradata || !track->extradata_size)
7475 return AVERROR(ENOMEM);
7476 }
7477
7478 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7480 return AVERROR(ENOMEM);
7481 1 track->extradata_size[0] = sizeof(stub_header);
7482
7483 1 pkt->stream_index = tracknum;
7484 1 pkt->flags = AV_PKT_FLAG_KEY;
7485
7486
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7487 4 AVChapter *c = s->chapters[i];
7488 AVDictionaryEntry *t;
7489
7490 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7491 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7492 4 pkt->duration = end - pkt->dts;
7493
7494
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7495 static const char encd[12] = {
7496 0x00, 0x00, 0x00, 0x0C,
7497 'e', 'n', 'c', 'd',
7498 0x00, 0x00, 0x01, 0x00 };
7499 4 len = strlen(t->value);
7500 4 pkt->size = len + 2 + 12;
7501 4 pkt->data = av_malloc(pkt->size);
7502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7503 av_packet_unref(pkt);
7504 return AVERROR(ENOMEM);
7505 }
7506 4 AV_WB16(pkt->data, len);
7507 4 memcpy(pkt->data + 2, t->value, len);
7508 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7509 4 ff_mov_write_packet(s, pkt);
7510 4 av_freep(&pkt->data);
7511 }
7512 }
7513
7514 1 av_packet_unref(mov->pkt);
7515
7516 1 return 0;
7517 }
7518
7519
7520 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7521 {
7522 int ret;
7523
7524 /* compute the frame number */
7525 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7526 13 return ret;
7527 }
7528
7529 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7530 {
7531 6 MOVMuxContext *mov = s->priv_data;
7532 6 MOVTrack *track = &mov->tracks[index];
7533 6 AVStream *src_st = mov->tracks[src_index].st;
7534 uint8_t data[4];
7535 6 AVPacket *pkt = mov->pkt;
7536 6 AVRational rate = src_st->avg_frame_rate;
7537 int ret;
7538
7539 /* tmcd track based on video stream */
7540 6 track->mode = mov->mode;
7541 6 track->tag = MKTAG('t','m','c','d');
7542 6 track->src_track = src_index;
7543 6 track->timescale = mov->tracks[src_index].timescale;
7544
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7545 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7546
7547 /* set st to src_st for metadata access*/
7548 6 track->st = src_st;
7549
7550 /* encode context: tmcd data stream */
7551 6 track->par = avcodec_parameters_alloc();
7552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7553 return AVERROR(ENOMEM);
7554 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7555 6 track->par->codec_tag = track->tag;
7556 6 track->st->avg_frame_rate = rate;
7557
7558 /* the tmcd track just contains one packet with the frame number */
7559 6 pkt->data = data;
7560 6 pkt->stream_index = index;
7561 6 pkt->flags = AV_PKT_FLAG_KEY;
7562 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7563 6 pkt->size = 4;
7564 6 AV_WB32(pkt->data, tc.start);
7565 6 ret = ff_mov_write_packet(s, pkt);
7566 6 av_packet_unref(pkt);
7567 6 return ret;
7568 }
7569
7570 /*
7571 * st->disposition controls the "enabled" flag in the tkhd tag.
7572 * QuickTime will not play a track if it is not enabled. So make sure
7573 * that one track of each type (audio, video, subtitle) is enabled.
7574 *
7575 * Subtitles are special. For audio and video, setting "enabled" also
7576 * makes the track "default" (i.e. it is rendered when played). For
7577 * subtitles, an "enabled" subtitle is not rendered by default, but
7578 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7579 * empty!
7580 */
7581 214 static void enable_tracks(AVFormatContext *s)
7582 {
7583 214 MOVMuxContext *mov = s->priv_data;
7584 int i;
7585 int enabled[AVMEDIA_TYPE_NB];
7586 int first[AVMEDIA_TYPE_NB];
7587
7588
2/2
✓ Branch 0 taken 1070 times.
✓ Branch 1 taken 214 times.
1284 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7589 1070 enabled[i] = 0;
7590 1070 first[i] = -1;
7591 }
7592
7593
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 214 times.
488 for (i = 0; i < mov->nb_streams; i++) {
7594 274 AVStream *st = mov->tracks[i].st;
7595
7596
1/2
✓ Branch 0 taken 274 times.
✗ Branch 1 not taken.
274 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7597
3/4
✓ Branch 0 taken 274 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 272 times.
548 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7598 274 is_cover_image(st))
7599 2 continue;
7600
7601
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 15 times.
272 if (first[st->codecpar->codec_type] < 0)
7602 257 first[st->codecpar->codec_type] = i;
7603
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 240 times.
272 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7604 32 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7605 32 enabled[st->codecpar->codec_type]++;
7606 }
7607 }
7608
7609
2/2
✓ Branch 0 taken 1070 times.
✓ Branch 1 taken 214 times.
1284 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7610
2/2
✓ Branch 0 taken 642 times.
✓ Branch 1 taken 428 times.
1070 switch (i) {
7611 642 case AVMEDIA_TYPE_VIDEO:
7612 case AVMEDIA_TYPE_AUDIO:
7613 case AVMEDIA_TYPE_SUBTITLE:
7614
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 641 times.
642 if (enabled[i] > 1)
7615 1 mov->per_stream_grouping = 1;
7616
4/4
✓ Branch 0 taken 615 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 228 times.
✓ Branch 3 taken 387 times.
642 if (!enabled[i] && first[i] >= 0)
7617 228 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7618 642 break;
7619 }
7620 }
7621 214 }
7622
7623 214 static void mov_free(AVFormatContext *s)
7624 {
7625 214 MOVMuxContext *mov = s->priv_data;
7626
7627
2/2
✓ Branch 0 taken 295 times.
✓ Branch 1 taken 214 times.
509 for (int i = 0; i < s->nb_streams; i++)
7628 295 s->streams[i]->priv_data = NULL;
7629
7630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (!mov->tracks)
7631 return;
7632
7633
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->chapter_track) {
7634 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7635 }
7636
7637
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 214 times.
497 for (int i = 0; i < mov->nb_tracks; i++) {
7638 283 MOVTrack *const track = &mov->tracks[i];
7639
7640
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 if (track->tag == MKTAG('r','t','p',' '))
7641 2 ff_mov_close_hinting(track);
7642
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 272 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
281 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7643 6 av_freep(&track->par);
7644 283 av_freep(&track->cluster);
7645 283 av_freep(&track->cluster_written);
7646 283 av_freep(&track->frag_info);
7647 283 av_packet_free(&track->cover_image);
7648
7649
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 278 times.
283 if (track->eac3_priv) {
7650 5 struct eac3_info *info = track->eac3_priv;
7651 5 av_packet_free(&info->pkt);
7652 5 av_freep(&track->eac3_priv);
7653 }
7654
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 283 times.
567 for (int j = 0; j < track->stsd_count; j++)
7655 284 av_freep(&track->extradata[j]);
7656 283 av_freep(&track->extradata);
7657 283 av_freep(&track->extradata_size);
7658
7659 283 ff_mov_cenc_free(&track->cenc);
7660 283 ffio_free_dyn_buf(&track->mdat_buf);
7661
7662 #if CONFIG_IAMFENC
7663 283 ffio_free_dyn_buf(&track->iamf_buf);
7664
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 278 times.
283 if (track->iamf)
7665 5 ff_iamf_uninit_context(track->iamf);
7666 283 av_freep(&track->iamf);
7667 #endif
7668 283 ff_isom_close_apvc(&track->apv);
7669
7670 283 avpriv_packet_list_free(&track->squashed_packet_queue);
7671 }
7672
7673 214 av_freep(&mov->tracks);
7674 214 ffio_free_dyn_buf(&mov->mdat_buf);
7675 }
7676
7677 static uint32_t rgb_to_yuv(uint32_t rgb)
7678 {
7679 uint8_t r, g, b;
7680 int y, cb, cr;
7681
7682 r = (rgb >> 16) & 0xFF;
7683 g = (rgb >> 8) & 0xFF;
7684 b = (rgb ) & 0xFF;
7685
7686 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7687 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7688 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7689
7690 return (y << 16) | (cr << 8) | cb;
7691 }
7692
7693 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7694 AVStream *st)
7695 {
7696 int i, width = 720, height = 480;
7697 int have_palette = 0, have_size = 0;
7698 uint32_t palette[16];
7699 char *cur = track->extradata[track->last_stsd_index];
7700
7701 while (cur && *cur) {
7702 if (strncmp("palette:", cur, 8) == 0) {
7703 int i, count;
7704 count = sscanf(cur + 8,
7705 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7706 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7707 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7708 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7709 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7710 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7711 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7712 &palette[12], &palette[13], &palette[14], &palette[15]);
7713
7714 for (i = 0; i < count; i++) {
7715 palette[i] = rgb_to_yuv(palette[i]);
7716 }
7717 have_palette = 1;
7718 } else if (!strncmp("size:", cur, 5)) {
7719 sscanf(cur + 5, "%dx%d", &width, &height);
7720 have_size = 1;
7721 }
7722 if (have_palette && have_size)
7723 break;
7724 cur += strcspn(cur, "\n\r");
7725 cur += strspn(cur, "\n\r");
7726 }
7727 if (have_palette) {
7728 track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7729 if (!track->extradata[track->last_stsd_index])
7730 return AVERROR(ENOMEM);
7731 for (i = 0; i < 16; i++) {
7732 AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
7733 }
7734 memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7735 track->extradata_size[track->last_stsd_index] = 16 * 4;
7736 }
7737 st->codecpar->width = width;
7738 st->codecpar->height = track->height = height;
7739
7740 return 0;
7741 }
7742
7743 #if CONFIG_IAMFENC
7744 214 static int mov_init_iamf_track(AVFormatContext *s)
7745 {
7746 214 MOVMuxContext *mov = s->priv_data;
7747 MOVTrack *track;
7748 IAMFContext *iamf;
7749 214 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7750 214 int nb_audio_elements = 0, nb_mix_presentations = 0;
7751 int ret;
7752
7753
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 214 times.
224 for (int i = 0; i < s->nb_stream_groups; i++) {
7754 10 const AVStreamGroup *stg = s->stream_groups[i];
7755
7756
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7757 5 nb_audio_elements++;
7758
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7759 5 nb_mix_presentations++;
7760 }
7761
7762
3/4
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 209 times.
✗ Branch 3 not taken.
214 if (!nb_audio_elements && !nb_mix_presentations)
7763 209 return 0;
7764
7765
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) {
7766 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7767 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7768 return AVERROR(EINVAL);
7769 }
7770
7771 5 iamf = av_mallocz(sizeof(*iamf));
7772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7773 return AVERROR(ENOMEM);
7774
7775
7776
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7777 10 const AVStreamGroup *stg = s->stream_groups[i];
7778
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7779 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7780
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7781 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7782 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7783 }
7784
7785 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7786 5 break;
7787 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7788 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7789 5 break;
7790 default:
7791 av_assert0(0);
7792 }
7793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7794 return ret;
7795 }
7796
7797 5 track = &mov->tracks[first_iamf_idx];
7798 5 track->iamf = iamf;
7799 5 track->first_iamf_idx = first_iamf_idx;
7800 5 track->last_iamf_idx = last_iamf_idx;
7801 5 track->tag = MKTAG('i','a','m','f');
7802
7803
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7804 10 AVStreamGroup *stg = s->stream_groups[i];
7805
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7806 5 continue;
7807
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7808 25 stg->streams[j]->priv_data = track;
7809 }
7810
7811 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7813 return ret;
7814
7815 5 return 0;
7816 }
7817 #endif
7818
7819 214 static int mov_init(AVFormatContext *s)
7820 {
7821 214 MOVMuxContext *mov = s->priv_data;
7822 214 int has_iamf = 0;
7823 int i, ret;
7824
7825 214 mov->fc = s;
7826 214 mov->pkt = ffformatcontext(s)->pkt;
7827
7828 /* Default mode == MP4 */
7829 214 mov->mode = MODE_MP4;
7830
7831 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7834
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 67 times.
214 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7835
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
67 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7836
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
66 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7837
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 61 times.
65 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7839
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7840 #undef IS_MODE
7841
7842
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 196 times.
214 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7843 18 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7844
7845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->mode == MODE_AVIF)
7846 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7847
7848 /* Set the FRAGMENT flag if any of the fragmentation methods are
7849 * enabled. */
7850
3/4
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
214 if (mov->max_fragment_duration || mov->max_fragment_size ||
7851
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 182 times.
212 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7852 FF_MOV_FLAG_FRAG_KEYFRAME |
7853 FF_MOV_FLAG_FRAG_CUSTOM |
7854 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7855 32 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7856
7857
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 212 times.
214 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
7858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
7859 av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
7860 return AVERROR(EINVAL);
7861 }
7862
7863 /* Set other implicit flags immediately */
7864
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 212 times.
214 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7865 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7866
7867
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 210 times.
214 if (mov->mode == MODE_ISM)
7868 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7869 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7870
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 202 times.
214 if (mov->flags & FF_MOV_FLAG_DASH)
7871 12 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7872 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7873
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->flags & FF_MOV_FLAG_CMAF)
7874 1 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7875 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7876
7877
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 2 times.
214 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
7878 30 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7879 30 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7880 }
7881
7882
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
214 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
7883 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7884 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7885 }
7886
7887
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 211 times.
214 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7888 3 mov->reserved_moov_size = -1;
7889 }
7890
7891
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 7 times.
214 if (mov->use_editlist < 0) {
7892 207 mov->use_editlist = 1;
7893
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 178 times.
207 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7894
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 16 times.
29 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7895 // If we can avoid needing an edit list by shifting the
7896 // tracks, prefer that over (trying to) write edit lists
7897 // in fragmented output.
7898
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
13 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7900 12 mov->use_editlist = 0;
7901 }
7902 }
7903
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 182 times.
214 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7904
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
32 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
7905 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7906
7907
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 196 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 1 times.
214 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
7908
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7909 11 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7910
7911 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7912 * if the latter is set that's enough and omit_tfhd_offset doesn't
7913 * add anything extra on top of that. */
7914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7915 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7916 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7917
7918
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->frag_interleave &&
7919
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)) {
7920 av_log(s, AV_LOG_ERROR,
7921 "Sample interleaving in fragments is mutually exclusive with "
7922 "omit_tfhd_offset and separate_moof\n");
7923 return AVERROR(EINVAL);
7924 }
7925
7926 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7927 * is enabled, we don't support non-seekable output at all. */
7928
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 186 times.
214 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7929
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
7930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7931 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7932 return AVERROR(EINVAL);
7933 }
7934
7935 /* AVIF output must have at most two video streams (one for YUV and one for
7936 * alpha). */
7937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->mode == MODE_AVIF) {
7938 if (s->nb_streams > 2) {
7939 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7940 return AVERROR(EINVAL);
7941 }
7942 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7943 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7944 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7945 return AVERROR(EINVAL);
7946 }
7947 if (s->nb_streams > 1) {
7948 const AVPixFmtDescriptor *pixdesc =
7949 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7950 if (pixdesc->nb_components != 1) {
7951 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7952 return AVERROR(EINVAL);
7953 }
7954 }
7955 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7956 }
7957
7958 #if CONFIG_IAMFENC
7959
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 214 times.
224 for (i = 0; i < s->nb_stream_groups; i++) {
7960 10 AVStreamGroup *stg = s->stream_groups[i];
7961
7962
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7963 5 continue;
7964
7965
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7966 25 AVStream *st = stg->streams[j];
7967
7968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
7969 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7970 "IAMF Audio Element\n", j);
7971 return AVERROR(EINVAL);
7972 }
7973 25 st->priv_data = st;
7974 }
7975 5 has_iamf = 1;
7976
7977
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
7978 5 mov->nb_tracks++;
7979 }
7980 #endif
7981
7982
2/2
✓ Branch 0 taken 295 times.
✓ Branch 1 taken 214 times.
509 for (i = 0; i < s->nb_streams; i++) {
7983 295 AVStream *st = s->streams[i];
7984
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 270 times.
295 if (st->priv_data)
7985 25 continue;
7986 // Don't produce a track in the output file for timed ID3 streams.
7987
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 269 times.
270 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7988 // Leave priv_data set to NULL for these AVStreams that don't
7989 // have a corresponding track.
7990 1 continue;
7991 }
7992 269 st->priv_data = st;
7993 269 mov->nb_tracks++;
7994 }
7995
7996 214 mov->nb_streams = mov->nb_tracks;
7997
7998
4/4
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 208 times.
214 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
7999 1 mov->chapter_track = mov->nb_tracks++;
8000
8001
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8002
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8003
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8004 2 mov->nb_tracks++;
8005 }
8006
8007
1/2
✓ Branch 0 taken 214 times.
✗ Branch 1 not taken.
214 if (mov->write_btrt < 0) {
8008 214 mov->write_btrt = mov->mode == MODE_MP4;
8009 }
8010
8011
6/6
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 147 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 61 times.
214 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8012
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
8013 211 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8014 NULL, 0);
8015
8016 /* +1 tmcd track for each video stream with a timecode */
8017
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 211 times.
501 for (i = 0; i < s->nb_streams; i++) {
8018 290 AVStream *st = s->streams[i];
8019 290 AVDictionaryEntry *t = global_tcr;
8020
4/4
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 107 times.
✓ Branch 2 taken 176 times.
✓ Branch 3 taken 7 times.
290 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8021
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176 times.
176 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8022 AVTimecode tc;
8023 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8024
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8025 7 mov->nb_meta_tmcd++;
8026 }
8027 }
8028
8029 /* check if there is already a tmcd track to remux */
8030
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 204 times.
211 if (mov->nb_meta_tmcd) {
8031
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8032 13 AVStream *st = s->streams[i];
8033
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8034 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8035 "so timecode metadata are now ignored\n");
8036 3 mov->nb_meta_tmcd = 0;
8037 }
8038 }
8039 }
8040
8041 211 mov->nb_tracks += mov->nb_meta_tmcd;
8042 }
8043
8044 // Reserve an extra stream for chapters for the case where chapters
8045 // are written in the trailer
8046 214 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (!mov->tracks)
8048 return AVERROR(ENOMEM);
8049
8050
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 214 times.
497 for (i = 0; i < mov->nb_tracks; i++) {
8051 283 MOVTrack *track = &mov->tracks[i];
8052
8053 283 track->stsd_count = 1;
8054 283 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8055 283 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8056
2/4
✓ Branch 0 taken 283 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 283 times.
283 if (!track->extradata || !track->extradata_size)
8057 return AVERROR(ENOMEM);
8058 }
8059
8060
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
214 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8061 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8062 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8063
8064 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8065 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8066 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8067 return AVERROR(EINVAL);
8068 }
8069
8070 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8071 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8072 mov->encryption_kid_len, CENC_KID_SIZE);
8073 return AVERROR(EINVAL);
8074 }
8075 } else {
8076 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8077 mov->encryption_scheme_str);
8078 return AVERROR(EINVAL);
8079 }
8080 }
8081
8082 #if CONFIG_IAMFENC
8083 214 ret = mov_init_iamf_track(s);
8084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (ret < 0)
8085 return ret;
8086 #endif
8087
8088
2/2
✓ Branch 0 taken 295 times.
✓ Branch 1 taken 214 times.
509 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8089 295 AVStream *st = s->streams[j];
8090
8091
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 269 times.
295 if (st != st->priv_data) {
8092
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8093 5 i += has_iamf--;
8094 26 continue;
8095 }
8096 269 st->priv_data = &mov->tracks[i++];
8097 }
8098
8099
2/2
✓ Branch 0 taken 295 times.
✓ Branch 1 taken 214 times.
509 for (i = 0; i < s->nb_streams; i++) {
8100 295 AVStream *st= s->streams[i];
8101 295 MOVTrack *track = st->priv_data;
8102 295 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8103
8104
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 294 times.
295 if (!track)
8105 1 continue;
8106
8107
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 20 times.
294 if (!track->st) {
8108 274 track->st = st;
8109 274 track->par = st->codecpar;
8110 }
8111
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 266 times.
294 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8112
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 139 times.
294 if (track->language < 0)
8113 155 track->language = 32767; // Unspecified Macintosh language code
8114 294 track->mode = mov->mode;
8115
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 25 times.
294 if (!track->tag)
8116 269 track->tag = mov_find_codec_tag(s, track);
8117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
294 if (!track->tag) {
8118 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8119 "codec not currently supported in container\n",
8120 avcodec_get_name(st->codecpar->codec_id), i);
8121 return AVERROR(EINVAL);
8122 }
8123 /* If hinting of this track is enabled by a later hint track,
8124 * this is updated. */
8125 294 track->hint_track = -1;
8126 294 track->start_dts = AV_NOPTS_VALUE;
8127 294 track->start_cts = AV_NOPTS_VALUE;
8128 294 track->end_pts = AV_NOPTS_VALUE;
8129 294 track->dts_shift = AV_NOPTS_VALUE;
8130
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 109 times.
294 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8131
2/4
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 185 times.
✗ Branch 3 not taken.
185 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8132
2/4
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 185 times.
✗ Branch 3 not taken.
185 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8133
2/4
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 185 times.
185 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8134 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8135 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8136 return AVERROR(EINVAL);
8137 }
8138 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8139 }
8140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 if (mov->video_track_timescale) {
8141 track->timescale = mov->video_track_timescale;
8142 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8143 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8144 } else {
8145 185 track->timescale = st->time_base.den;
8146
2/2
✓ Branch 0 taken 1494 times.
✓ Branch 1 taken 185 times.
1679 while(track->timescale < 10000)
8147 1494 track->timescale *= 2;
8148 }
8149
2/4
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 185 times.
185 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8150 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8151 return AVERROR(EINVAL);
8152 }
8153
4/4
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 130 times.
185 if (track->mode == MODE_MOV && track->timescale > 100000)
8154 2 av_log(s, AV_LOG_WARNING,
8155 "WARNING codec timebase is very high. If duration is too long,\n"
8156 "file may not be playable by quicktime. Specify a shorter timebase\n"
8157 "or choose different container.\n");
8158
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 53 times.
185 if (track->mode == MODE_MOV &&
8159
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 115 times.
132 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8160
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8161 1 enum AVPixelFormat pix_fmt = track->par->format;
8162
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)
8163 pix_fmt = AV_PIX_FMT_MONOWHITE;
8164 1 track->is_unaligned_qt_rgb =
8165 pix_fmt == AV_PIX_FMT_RGB24 ||
8166 pix_fmt == AV_PIX_FMT_BGR24 ||
8167 pix_fmt == AV_PIX_FMT_PAL8 ||
8168 pix_fmt == AV_PIX_FMT_GRAY8 ||
8169
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 ||
8170 pix_fmt == AV_PIX_FMT_MONOBLACK;
8171 }
8172
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
185 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8173 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8174 return AVERROR(EINVAL);
8175
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 184 times.
185 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8176
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8177 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8178 return AVERROR(EINVAL);
8179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8180 /* altref frames handling is not defined in the spec as of version v1.0,
8181 * so just forbid muxing VP8 streams altogether until a new version does */
8182 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8183 return AVERROR_PATCHWELCOME;
8184
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 184 times.
185 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8185 1 ret = ff_isom_init_apvc(&track->apv, s);
8186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8187 return ret;
8188 }
8189
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 183 times.
185 if (is_cover_image(st)) {
8190 2 track->cover_image = av_packet_alloc();
8191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8192 return AVERROR(ENOMEM);
8193 }
8194
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 7 times.
109 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8195 102 track->timescale = st->codecpar->sample_rate;
8196
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 70 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 26 times.
102 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8197 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8198 6 track->audio_vbr = 1;
8199
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8200
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8202 if (!st->codecpar->block_align) {
8203 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8204 return AVERROR(EINVAL);
8205 }
8206 track->sample_size = st->codecpar->block_align;
8207
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 26 times.
96 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8208 70 track->audio_vbr = 1;
8209 }else{
8210 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8211 26 st->codecpar->ch_layout.nb_channels;
8212 }
8213
1/2
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
102 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8215 track->audio_vbr = 1;
8216 }
8217
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 32 times.
102 if (track->mode != MODE_MOV &&
8218
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8219 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8220 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8221 i, track->par->sample_rate);
8222 return AVERROR(EINVAL);
8223 } else {
8224 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8225 i, track->par->sample_rate);
8226 }
8227 }
8228
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 25 times.
102 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8229
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8230
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 track->par->codec_id == AV_CODEC_ID_OPUS) {
8231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8232 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8233 return AVERROR(EINVAL);
8234 }
8235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8236 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8237 av_log(s, AV_LOG_ERROR,
8238 "%s in MP4 support is experimental, add "
8239 "'-strict %d' if you want to use it.\n",
8240 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8241 return AVERROR_EXPERIMENTAL;
8242 }
8243 }
8244
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8245 3 track->timescale = st->time_base.den;
8246
8247
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8248 /* 14496-30 requires us to use a single sample per fragment
8249 for TTML, for which we define a per-track flag.
8250
8251 We set the flag in case we are receiving TTML paragraphs
8252 from the input, in other words in case we are not doing
8253 stream copy. */
8254 2 track->squash_fragment_samples_to_one =
8255 2 ff_is_ttml_stream_paragraph_based(track->par);
8256
8257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8258 track->squash_fragment_samples_to_one) {
8259 av_log(s, AV_LOG_ERROR,
8260 "Fragmentation is not currently supported for "
8261 "TTML in MP4/ISMV (track synchronization between "
8262 "subtitles and other media is not yet implemented)!\n");
8263 return AVERROR_PATCHWELCOME;
8264 }
8265
8266
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
8267
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8269 av_log(s, AV_LOG_ERROR,
8270 "ISMV style TTML support with the 'dfxp' tag in "
8271 "non-ISMV formats is not officially supported. Add "
8272 "'-strict unofficial' if you want to use it.\n");
8273 return AVERROR_EXPERIMENTAL;
8274 }
8275 }
8276
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8277 4 track->timescale = st->time_base.den;
8278 } else {
8279 track->timescale = mov->movie_timescale;
8280 }
8281
1/2
✓ Branch 0 taken 294 times.
✗ Branch 1 not taken.
294 if (!track->height)
8282 294 track->height = st->codecpar->height;
8283 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8284 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8285 for video tracks, so if user-set, it isn't overwritten */
8286
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 289 times.
294 if (mov->mode == MODE_ISM &&
8287
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8288
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !mov->video_track_timescale))) {
8289 5 track->timescale = 10000000;
8290 }
8291
8292 294 avpriv_set_pts_info(st, 64, 1, track->timescale);
8293
8294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
294 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8295 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8296 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8297 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8298 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8299 if (ret)
8300 return ret;
8301 }
8302 }
8303
8304 214 enable_tracks(s);
8305 214 return 0;
8306 }
8307
8308 214 static int mov_write_header(AVFormatContext *s)
8309 {
8310 214 AVIOContext *pb = s->pb;
8311 214 MOVMuxContext *mov = s->priv_data;
8312 214 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8313
8314
4/4
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 208 times.
214 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8315 1 nb_tracks++;
8316
8317
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8318 1 hint_track = nb_tracks;
8319
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8320
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8321 2 nb_tracks++;
8322 }
8323 }
8324
8325
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 208 times.
214 if (mov->nb_meta_tmcd)
8326 6 tmcd_track = nb_tracks;
8327
8328
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 214 times.
488 for (int i = 0; i < mov->nb_streams; i++) {
8329 274 MOVTrack *track = &mov->tracks[i];
8330 274 AVStream *st = track->st;
8331
8332 /* copy extradata if it exists */
8333
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 155 times.
274 if (st->codecpar->extradata_size) {
8334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8335 mov_create_dvd_sub_decoder_specific_info(track, st);
8336
15/30
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 119 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 119 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 119 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 119 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 119 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 119 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 119 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 119 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 119 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 119 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 119 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 119 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 119 times.
✗ Branch 29 not taken.
119 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8337 119 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8338 238 track->extradata[track->last_stsd_index] =
8339 119 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (!track->extradata[track->last_stsd_index]) {
8341 return AVERROR(ENOMEM);
8342 }
8343 119 memcpy(track->extradata[track->last_stsd_index],
8344 119 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8345 119 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8346 0, AV_INPUT_BUFFER_PADDING_SIZE);
8347 }
8348 }
8349
8350
4/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 14 times.
356 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8351 82 av_channel_layout_compare(&track->par->ch_layout,
8352 82 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8353 260 continue;
8354
8355
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8356 33 AVStream *stj= mov->tracks[j].st;
8357 33 MOVTrack *trackj= &mov->tracks[j];
8358
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8359 14 continue;
8360
8361
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8362
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
18 (trackj->par->ch_layout.nb_channels != 1 ||
8363 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8364 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8365 )
8366 4 track->mono_as_fc = -1;
8367
8368
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
30 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8369 11 av_channel_layout_compare(&trackj->par->ch_layout,
8370 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8371
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
8372 )
8373 7 track->mono_as_fc++;
8374
8375
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
30 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8376 11 av_channel_layout_compare(&trackj->par->ch_layout,
8377 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8378 trackj->language != track->language ||
8379 trackj->tag != track->tag
8380 )
8381 19 continue;
8382 track->multichannel_as_mono++;
8383 }
8384 }
8385
8386
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 18 times.
214 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8387
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 196 times.
196 if ((ret = mov_write_identification(pb, s)) < 0)
8388 return ret;
8389 }
8390
8391
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 211 times.
214 if (mov->reserved_moov_size){
8392 3 mov->reserved_header_pos = avio_tell(pb);
8393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8394 avio_skip(pb, mov->reserved_moov_size);
8395 }
8396
8397
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 178 times.
214 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8398 /* If no fragmentation options have been set, set a default. */
8399
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 31 times.
36 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8400 FF_MOV_FLAG_FRAG_CUSTOM |
8401 5 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8402
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
5 !mov->max_fragment_duration && !mov->max_fragment_size)
8403 4 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8404
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34 times.
36 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8405 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8406
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8407 2 mov->mdat_pos = avio_tell(pb);
8408 }
8409
1/2
✓ Branch 0 taken 178 times.
✗ Branch 1 not taken.
178 } else if (mov->mode != MODE_AVIF) {
8410
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 175 times.
178 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8411 3 mov->reserved_header_pos = avio_tell(pb);
8412 178 mov_write_mdat_tag(pb, mov);
8413 }
8414
8415 214 ff_parse_creation_time_metadata(s, &mov->time, 1);
8416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->time)
8417 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8418
8419
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->chapter_track)
8420
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8421 return ret;
8422
8423
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 213 times.
214 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8424
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8425
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8426
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8427 return ret;
8428 2 hint_track++;
8429 }
8430 }
8431 }
8432
8433
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 208 times.
214 if (mov->nb_meta_tmcd) {
8434 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8435 "timecode", NULL, 0);
8436 /* Initialize the tmcd tracks */
8437
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8438 8 AVStream *st = mov->tracks[i].st;
8439 8 t = global_tcr;
8440
8441
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8442 AVTimecode tc;
8443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8444 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8446 continue;
8447
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8448 continue;
8449
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8450 return ret;
8451 6 tmcd_track++;
8452 }
8453 }
8454 }
8455
8456 214 avio_flush(pb);
8457
8458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214 times.
214 if (mov->flags & FF_MOV_FLAG_ISML)
8459 mov_write_isml_manifest(pb, mov, s);
8460
8461
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 182 times.
214 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8462
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 18 times.
32 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8463
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8464 return ret;
8465 14 mov->moov_written = 1;
8466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8467 mov->reserved_header_pos = avio_tell(pb);
8468 }
8469
8470 214 return 0;
8471 }
8472
8473 28 static int get_moov_size(AVFormatContext *s)
8474 {
8475 int ret;
8476 AVIOContext *moov_buf;
8477 28 MOVMuxContext *mov = s->priv_data;
8478
8479
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8480 return ret;
8481
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8482 return ret;
8483 28 return ffio_close_null_buf(moov_buf);
8484 }
8485
8486 static int get_sidx_size(AVFormatContext *s)
8487 {
8488 int ret;
8489 AVIOContext *buf;
8490 MOVMuxContext *mov = s->priv_data;
8491
8492 if ((ret = ffio_open_null_buf(&buf)) < 0)
8493 return ret;
8494 mov_write_sidx_tags(buf, mov, -1, 0);
8495 return ffio_close_null_buf(buf);
8496 }
8497
8498 /*
8499 * This function gets the moov size if moved to the top of the file: the chunk
8500 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8501 * entries) when the moov is moved to the beginning, so the size of the moov
8502 * would change. It also updates the chunk offset tables.
8503 */
8504 3 static int compute_moov_size(AVFormatContext *s)
8505 {
8506 int i, moov_size, moov_size2;
8507 3 MOVMuxContext *mov = s->priv_data;
8508
8509 3 moov_size = get_moov_size(s);
8510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8511 return moov_size;
8512
8513
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8514 8 mov->tracks[i].data_offset += moov_size;
8515
8516 3 moov_size2 = get_moov_size(s);
8517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8518 return moov_size2;
8519
8520 /* if the size changed, we just switched from stco to co64 and need to
8521 * update the offsets */
8522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8523 for (i = 0; i < mov->nb_tracks; i++)
8524 mov->tracks[i].data_offset += moov_size2 - moov_size;
8525
8526 3 return moov_size2;
8527 }
8528
8529 static int compute_sidx_size(AVFormatContext *s)
8530 {
8531 int i, sidx_size;
8532 MOVMuxContext *mov = s->priv_data;
8533
8534 sidx_size = get_sidx_size(s);
8535 if (sidx_size < 0)
8536 return sidx_size;
8537
8538 for (i = 0; i < mov->nb_tracks; i++)
8539 mov->tracks[i].data_offset += sidx_size;
8540
8541 return sidx_size;
8542 }
8543
8544 3 static int shift_data(AVFormatContext *s)
8545 {
8546 int moov_size;
8547 3 MOVMuxContext *mov = s->priv_data;
8548
8549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8550 moov_size = compute_sidx_size(s);
8551 else
8552 3 moov_size = compute_moov_size(s);
8553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8554 return moov_size;
8555
8556 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8557 }
8558
8559 214 static int mov_write_trailer(AVFormatContext *s)
8560 {
8561 214 MOVMuxContext *mov = s->priv_data;
8562 214 AVIOContext *pb = s->pb;
8563 214 int res = 0;
8564 int i;
8565 int64_t moov_pos;
8566
8567 /*
8568 * Before actually writing the trailer, make sure that there are no
8569 * dangling subtitles, that need a terminating sample.
8570 */
8571
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 214 times.
497 for (i = 0; i < mov->nb_tracks; i++) {
8572 283 MOVTrack *trk = &mov->tracks[i];
8573
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 282 times.
283 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8574
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8575 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8576 1 trk->last_sample_is_subtitle_end = 1;
8577 }
8578 }
8579
8580 // Check if we have any tracks that require squashing.
8581 // In that case, we'll have to write the packet here.
8582
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 214 times.
214 if ((res = mov_write_squashed_packets(s)) < 0)
8583 return res;
8584
8585 // If there were no chapters when the header was written, but there
8586 // are chapters now, write them in the trailer. This only works
8587 // when we are not doing fragments.
8588
4/4
✓ Branch 0 taken 213 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 36 times.
214 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
8589
3/4
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 176 times.
177 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
8590 mov->chapter_track = mov->nb_tracks++;
8591 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8592 return res;
8593 }
8594 }
8595
8596
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 178 times.
214 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8597
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34 times.
36 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8598
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8599 2 mov_flush_fragment(s, 1);
8600 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8601
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
8602 4 MOVTrack *track = &mov->tracks[i];
8603 4 track->data_offset = 0;
8604 4 av_free(track->cluster);
8605 4 track->cluster = track->cluster_written;
8606 4 track->entry = track->entry_written;
8607 4 track->cluster_written = NULL;
8608 4 track->entry_written = 0;
8609 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8610 }
8611 // Clear the empty_moov flag, as we do want the moov to include
8612 // all the samples at this point.
8613 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8614 }
8615
8616 180 moov_pos = avio_tell(pb);
8617
8618 /* Write size of mdat tag */
8619
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (mov->mdat_size + 8 <= UINT32_MAX) {
8620 180 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8621 180 avio_wb32(pb, mov->mdat_size + 8);
8622
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
180 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8623 2 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8624 } else {
8625 /* overwrite 'wide' placeholder atom */
8626 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8627 /* special value: real atom size will be 64 bit value after
8628 * tag field */
8629 avio_wb32(pb, 1);
8630 ffio_wfourcc(pb, "mdat");
8631 avio_wb64(pb, mov->mdat_size + 16);
8632 }
8633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
8634
8635
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 177 times.
180 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8636 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8637 3 res = shift_data(s);
8638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8639 return res;
8640 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8641
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8642 return res;
8643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
177 } else if (mov->reserved_moov_size > 0) {
8644 int64_t size;
8645 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8646 return res;
8647 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8648 if (size < 8){
8649 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8650 return AVERROR(EINVAL);
8651 }
8652 avio_wb32(pb, size);
8653 ffio_wfourcc(pb, "free");
8654 ffio_fill(pb, 0, size - 8);
8655 avio_seek(pb, moov_pos, SEEK_SET);
8656 } else {
8657
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 177 times.
177 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8658 return res;
8659 }
8660 180 res = 0;
8661 } else {
8662 34 mov_auto_flush_fragment(s, 1);
8663
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 34 times.
98 for (i = 0; i < mov->nb_tracks; i++)
8664 64 mov->tracks[i].data_offset = 0;
8665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8666 int64_t end;
8667 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8668 res = shift_data(s);
8669 if (res < 0)
8670 return res;
8671 end = avio_tell(pb);
8672 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8673 mov_write_sidx_tags(pb, mov, -1, 0);
8674 avio_seek(pb, end, SEEK_SET);
8675 }
8676
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8677 34 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8678 34 res = mov_write_mfra_tag(pb, mov);
8679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (res < 0)
8680 return res;
8681 }
8682 }
8683
8684 214 return res;
8685 }
8686
8687 236 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8688 const AVPacket *pkt)
8689 {
8690 236 int ret = 1;
8691
8692
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 227 times.
236 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8693
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
8694 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8696 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8697 }
8698
8699 236 return ret;
8700 }
8701
8702 #if CONFIG_AVIF_MUXER
8703 static int avif_write_trailer(AVFormatContext *s)
8704 {
8705 AVIOContext *pb = s->pb;
8706 MOVMuxContext *mov = s->priv_data;
8707 int64_t pos_backup, extent_offsets[2];
8708 uint8_t *buf;
8709 int buf_size, moov_size;
8710
8711 if (mov->moov_written) return 0;
8712
8713 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8714 if (mov->is_animated_avif && mov->nb_streams > 1) {
8715 // For animated avif with alpha channel, we need to write a tref tag
8716 // with type "auxl".
8717 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8718 mov->tracks[1].tref_id = 1;
8719 }
8720 mov_write_identification(pb, s);
8721 mov_write_meta_tag(pb, mov, s);
8722
8723 moov_size = get_moov_size(s);
8724 for (int i = 0; i < mov->nb_tracks; i++)
8725 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8726
8727 if (mov->is_animated_avif) {
8728 int ret;
8729 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8730 return ret;
8731 }
8732
8733 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8734 avio_wb32(pb, buf_size + 8);
8735 ffio_wfourcc(pb, "mdat");
8736
8737 // The offset for the YUV planes is the starting position of mdat.
8738 extent_offsets[0] = avio_tell(pb);
8739 // The offset for alpha plane is YUV offset + YUV size.
8740 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8741
8742 avio_write(pb, buf, buf_size);
8743
8744 // write extent offsets.
8745 pos_backup = avio_tell(pb);
8746 for (int i = 0; i < mov->nb_streams; i++) {
8747 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8748 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8749 return AVERROR_INVALIDDATA;
8750 }
8751 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8752 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8753 }
8754 avio_seek(pb, pos_backup, SEEK_SET);
8755
8756 return 0;
8757 }
8758 #endif
8759
8760 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8761 static const AVCodecTag codec_3gp_tags[] = {
8762 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8763 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8764 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8765 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8766 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8767 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8768 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8769 { AV_CODEC_ID_NONE, 0 },
8770 };
8771 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8772 #endif
8773
8774 static const AVCodecTag codec_mp4_tags[] = {
8775 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8776 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8777 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8778 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8779 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8780 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8781 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8782 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8783 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8784 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
8785 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8786 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8787 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8788 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8789 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8790 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8791 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8792 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8793 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8794 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8795 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8796 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8797 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8798 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8799 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8800 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8801 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8802 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8803 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8804 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8805 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8806 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8807 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8808 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8809 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8810 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8811 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8812 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8813 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8814 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8815 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8816
8817 /* ISO/IEC 23003-5 integer formats */
8818 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8819 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8820 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8821 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8822 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8823 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8824 /* ISO/IEC 23003-5 floating-point formats */
8825 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8826 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8827 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8828 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8829
8830 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
8831
8832 { AV_CODEC_ID_NONE, 0 },
8833 };
8834 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8835 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8836 #endif
8837
8838 static const AVCodecTag codec_ism_tags[] = {
8839 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8840 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8841 { AV_CODEC_ID_NONE , 0 },
8842 };
8843
8844 static const AVCodecTag codec_ipod_tags[] = {
8845 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8846 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8847 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8848 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8849 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8850 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8851 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8852 { AV_CODEC_ID_NONE, 0 },
8853 };
8854
8855 static const AVCodecTag codec_f4v_tags[] = {
8856 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8857 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8858 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8859 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8860 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8861 { AV_CODEC_ID_NONE, 0 },
8862 };
8863
8864 #if CONFIG_AVIF_MUXER
8865
8866 static const AVOption avif_options[] = {
8867 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8868 { "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 },
8869 { NULL },
8870 };
8871 static const AVCodecTag codec_avif_tags[] = {
8872 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8873 { AV_CODEC_ID_NONE, 0 },
8874 };
8875 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8876
8877 static const AVClass mov_avif_muxer_class = {
8878 .class_name = "avif muxer",
8879 .item_name = av_default_item_name,
8880 .option = avif_options,
8881 .version = LIBAVUTIL_VERSION_INT,
8882 };
8883 #endif
8884
8885 #if CONFIG_MOV_MUXER
8886 const FFOutputFormat ff_mov_muxer = {
8887 .p.name = "mov",
8888 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8889 .p.extensions = "mov",
8890 .priv_data_size = sizeof(MOVMuxContext),
8891 .p.audio_codec = AV_CODEC_ID_AAC,
8892 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8893 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8894 .init = mov_init,
8895 .write_header = mov_write_header,
8896 .write_packet = mov_write_packet,
8897 .write_trailer = mov_write_trailer,
8898 .deinit = mov_free,
8899 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8900 .p.codec_tag = (const AVCodecTag* const []){
8901 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8902 },
8903 .check_bitstream = mov_check_bitstream,
8904 .p.priv_class = &mov_isobmff_muxer_class,
8905 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8906 };
8907 #endif
8908 #if CONFIG_TGP_MUXER
8909 const FFOutputFormat ff_tgp_muxer = {
8910 .p.name = "3gp",
8911 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8912 .p.extensions = "3gp",
8913 .priv_data_size = sizeof(MOVMuxContext),
8914 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8915 .p.video_codec = AV_CODEC_ID_H263,
8916 .init = mov_init,
8917 .write_header = mov_write_header,
8918 .write_packet = mov_write_packet,
8919 .write_trailer = mov_write_trailer,
8920 .deinit = mov_free,
8921 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8922 .p.codec_tag = codec_3gp_tags_list,
8923 .check_bitstream = mov_check_bitstream,
8924 .p.priv_class = &mov_isobmff_muxer_class,
8925 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8926 };
8927 #endif
8928 #if CONFIG_MP4_MUXER
8929 const FFOutputFormat ff_mp4_muxer = {
8930 .p.name = "mp4",
8931 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8932 .p.mime_type = "video/mp4",
8933 .p.extensions = "mp4",
8934 .priv_data_size = sizeof(MOVMuxContext),
8935 .p.audio_codec = AV_CODEC_ID_AAC,
8936 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8937 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8938 .init = mov_init,
8939 .write_header = mov_write_header,
8940 .write_packet = mov_write_packet,
8941 .write_trailer = mov_write_trailer,
8942 .deinit = mov_free,
8943 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8944 .p.codec_tag = mp4_codec_tags_list,
8945 .check_bitstream = mov_check_bitstream,
8946 .p.priv_class = &mov_isobmff_muxer_class,
8947 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8948 };
8949 #endif
8950 #if CONFIG_PSP_MUXER
8951 const FFOutputFormat ff_psp_muxer = {
8952 .p.name = "psp",
8953 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8954 .p.extensions = "mp4,psp",
8955 .priv_data_size = sizeof(MOVMuxContext),
8956 .p.audio_codec = AV_CODEC_ID_AAC,
8957 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8958 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8959 .init = mov_init,
8960 .write_header = mov_write_header,
8961 .write_packet = mov_write_packet,
8962 .write_trailer = mov_write_trailer,
8963 .deinit = mov_free,
8964 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8965 .p.codec_tag = mp4_codec_tags_list,
8966 .check_bitstream = mov_check_bitstream,
8967 .p.priv_class = &mov_isobmff_muxer_class,
8968 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8969 };
8970 #endif
8971 #if CONFIG_TG2_MUXER
8972 const FFOutputFormat ff_tg2_muxer = {
8973 .p.name = "3g2",
8974 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8975 .p.extensions = "3g2",
8976 .priv_data_size = sizeof(MOVMuxContext),
8977 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8978 .p.video_codec = AV_CODEC_ID_H263,
8979 .init = mov_init,
8980 .write_header = mov_write_header,
8981 .write_packet = mov_write_packet,
8982 .write_trailer = mov_write_trailer,
8983 .deinit = mov_free,
8984 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8985 .p.codec_tag = codec_3gp_tags_list,
8986 .check_bitstream = mov_check_bitstream,
8987 .p.priv_class = &mov_isobmff_muxer_class,
8988 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8989 };
8990 #endif
8991 #if CONFIG_IPOD_MUXER
8992 const FFOutputFormat ff_ipod_muxer = {
8993 .p.name = "ipod",
8994 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8995 .p.mime_type = "video/mp4",
8996 .p.extensions = "m4v,m4a,m4b",
8997 .priv_data_size = sizeof(MOVMuxContext),
8998 .p.audio_codec = AV_CODEC_ID_AAC,
8999 .p.video_codec = AV_CODEC_ID_H264,
9000 .init = mov_init,
9001 .write_header = mov_write_header,
9002 .write_packet = mov_write_packet,
9003 .write_trailer = mov_write_trailer,
9004 .deinit = mov_free,
9005 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9006 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9007 .check_bitstream = mov_check_bitstream,
9008 .p.priv_class = &mov_isobmff_muxer_class,
9009 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9010 };
9011 #endif
9012 #if CONFIG_ISMV_MUXER
9013 const FFOutputFormat ff_ismv_muxer = {
9014 .p.name = "ismv",
9015 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9016 .p.mime_type = "video/mp4",
9017 .p.extensions = "ismv,isma",
9018 .priv_data_size = sizeof(MOVMuxContext),
9019 .p.audio_codec = AV_CODEC_ID_AAC,
9020 .p.video_codec = AV_CODEC_ID_H264,
9021 .init = mov_init,
9022 .write_header = mov_write_header,
9023 .write_packet = mov_write_packet,
9024 .write_trailer = mov_write_trailer,
9025 .deinit = mov_free,
9026 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9027 .p.codec_tag = (const AVCodecTag* const []){
9028 codec_mp4_tags, codec_ism_tags, 0 },
9029 .check_bitstream = mov_check_bitstream,
9030 .p.priv_class = &mov_isobmff_muxer_class,
9031 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9032 };
9033 #endif
9034 #if CONFIG_F4V_MUXER
9035 const FFOutputFormat ff_f4v_muxer = {
9036 .p.name = "f4v",
9037 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9038 .p.mime_type = "application/f4v",
9039 .p.extensions = "f4v",
9040 .priv_data_size = sizeof(MOVMuxContext),
9041 .p.audio_codec = AV_CODEC_ID_AAC,
9042 .p.video_codec = AV_CODEC_ID_H264,
9043 .init = mov_init,
9044 .write_header = mov_write_header,
9045 .write_packet = mov_write_packet,
9046 .write_trailer = mov_write_trailer,
9047 .deinit = mov_free,
9048 .p.flags = AVFMT_GLOBALHEADER,
9049 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9050 .check_bitstream = mov_check_bitstream,
9051 .p.priv_class = &mov_isobmff_muxer_class,
9052 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9053 };
9054 #endif
9055 #if CONFIG_AVIF_MUXER
9056 const FFOutputFormat ff_avif_muxer = {
9057 .p.name = "avif",
9058 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9059 .p.mime_type = "image/avif",
9060 .p.extensions = "avif",
9061 .priv_data_size = sizeof(MOVMuxContext),
9062 .p.video_codec = AV_CODEC_ID_AV1,
9063 .init = mov_init,
9064 .write_header = mov_write_header,
9065 .write_packet = mov_write_packet,
9066 .write_trailer = avif_write_trailer,
9067 .deinit = mov_free,
9068 .p.flags = AVFMT_GLOBALHEADER,
9069 .p.codec_tag = codec_avif_tags_list,
9070 .p.priv_class = &mov_avif_muxer_class,
9071 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9072 };
9073 #endif
9074