FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2026-09-16 18:55:35
Exec Total Coverage
Lines: 3976 5841 68.1%
Functions: 188 241 78.0%
Branches: 2379 4038 58.9%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <math.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29
30 #include "movenc.h"
31 #include "avformat.h"
32 #include "avio_internal.h"
33 #include "dovi_isom.h"
34 #include "riff.h"
35 #include "avio.h"
36 #include "iamf_writer.h"
37 #include "isom.h"
38 #include "av1.h"
39 #include "avc.h"
40 #include "evc.h"
41 #include "apv.h"
42 #include "lcevc.h"
43 #include "libavcodec/ac3_parser_internal.h"
44 #include "libavcodec/dnxhddata.h"
45 #include "libavcodec/flac.h"
46 #include "libavcodec/get_bits.h"
47
48 #include "libavcodec/internal.h"
49 #include "libavcodec/put_bits.h"
50 #include "libavcodec/vc1_common.h"
51 #include "libavcodec/raw.h"
52 #include "internal.h"
53 #include "libavutil/avstring.h"
54 #include "libavutil/channel_layout.h"
55 #include "libavutil/csp.h"
56 #include "libavutil/intfloat.h"
57 #include "libavutil/mathematics.h"
58 #include "libavutil/mem.h"
59 #include "libavutil/opt.h"
60 #include "libavutil/dict.h"
61 #include "libavutil/pixdesc.h"
62 #include "libavutil/stereo3d.h"
63 #include "libavutil/timecode.h"
64 #include "libavutil/dovi_meta.h"
65 #include "libavutil/uuid.h"
66 #include "hevc.h"
67 #include "rtpenc.h"
68 #include "nal.h"
69 #include "mov_chan.h"
70 #include "movenc_ttml.h"
71 #include "mux.h"
72 #include "rawutils.h"
73 #include "ttmlenc.h"
74 #include "version.h"
75 #include "vpcc.h"
76 #include "vvc.h"
77
78 static const AVOption options[] = {
79 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
80 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
81 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
82 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
84 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
85 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
86 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
87 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
88 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
89 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
90 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
91 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
92 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
104 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
105 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
106 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
107 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
116 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
117 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
118 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
119 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
120 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
121 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
122 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
125 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
126 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
128 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
129 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
130 { NULL },
131 };
132
133 static const AVClass mov_isobmff_muxer_class = {
134 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
135 .item_name = av_default_item_name,
136 .option = options,
137 .version = LIBAVUTIL_VERSION_INT,
138 };
139
140 static int get_moov_size(AVFormatContext *s);
141 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
142
143 30 static int utf8len(const uint8_t *b)
144 {
145 30 int len = 0;
146 int val;
147
2/2
✓ Branch 0 taken 569 times.
✓ Branch 1 taken 30 times.
599 while (*b) {
148
3/8
✓ Branch 0 taken 569 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 569 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 569 times.
569 GET_UTF8(val, *b++, return -1;)
149 569 len++;
150 }
151 30 return len;
152 }
153
154 //FIXME support 64 bit variant with wide placeholders
155 7272 static int64_t update_size(AVIOContext *pb, int64_t pos)
156 {
157 7272 int64_t curpos = avio_tell(pb);
158 7272 avio_seek(pb, pos, SEEK_SET);
159 7272 avio_wb32(pb, curpos - pos); /* rewrite size */
160 7272 avio_seek(pb, curpos, SEEK_SET);
161
162 7272 return curpos - pos;
163 }
164
165 382 static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version)
166 {
167 382 int64_t curpos = avio_tell(pb);
168 382 avio_seek(pb, pos, SEEK_SET);
169 382 avio_wb32(pb, curpos - pos); /* rewrite size */
170 382 avio_skip(pb, 4);
171 382 avio_w8(pb, version); /* rewrite version */
172 382 avio_seek(pb, curpos, SEEK_SET);
173
174 382 return curpos - pos;
175 }
176
177 382 static int co64_required(const MOVTrack *track)
178 {
179
3/4
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 275 times.
382 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
180 return 1;
181 382 return 0;
182 }
183
184 24509 static int is_cover_image(const AVStream *st)
185 {
186 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
187 * is encoded as sparse video track */
188
3/4
✓ Branch 0 taken 24509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24497 times.
24509 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
189 }
190
191 6 static int rtp_hinting_needed(const AVStream *st)
192 {
193 /* Add hint tracks for each real audio and video stream */
194
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
195 return 0;
196
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
197
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
198 }
199
200 /* Chunk offset atom */
201 382 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
202 {
203 int i;
204 382 int mode64 = co64_required(track); // use 32 bit size variant if possible
205 382 int64_t pos = avio_tell(pb);
206 382 avio_wb32(pb, 0); /* size */
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (mode64)
208 ffio_wfourcc(pb, "co64");
209 else
210 382 ffio_wfourcc(pb, "stco");
211 382 avio_wb32(pb, 0); /* version & flags */
212 382 avio_wb32(pb, track->chunkCount); /* entry count */
213
2/2
✓ Branch 0 taken 17321 times.
✓ Branch 1 taken 382 times.
17703 for (i = 0; i < track->entry; i++) {
214
2/2
✓ Branch 0 taken 14351 times.
✓ Branch 1 taken 2970 times.
17321 if (!track->cluster[i].chunkNum)
215 14351 continue;
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2970 times.
2970 if (mode64 == 1)
217 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
218 else
219 2970 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
220 }
221 382 return update_size(pb, pos);
222 }
223
224 /* Sample size atom */
225 382 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
226 {
227 382 int equalChunks = 1;
228 382 int i, j, entries = 0, tst = -1, oldtst = -1;
229
230 382 int64_t pos = avio_tell(pb);
231 382 avio_wb32(pb, 0); /* size */
232 382 ffio_wfourcc(pb, "stsz");
233 382 avio_wb32(pb, 0); /* version & flags */
234
235
2/2
✓ Branch 0 taken 17321 times.
✓ Branch 1 taken 382 times.
17703 for (i = 0; i < track->entry; i++) {
236 17321 tst = track->cluster[i].size / track->cluster[i].entries;
237
4/4
✓ Branch 0 taken 17046 times.
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 11935 times.
✓ Branch 3 taken 5111 times.
17321 if (oldtst != -1 && tst != oldtst)
238 11935 equalChunks = 0;
239 17321 oldtst = tst;
240 17321 entries += track->cluster[i].entries;
241 }
242
4/4
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 107 times.
502 if (equalChunks && track->entry) {
243
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
244 120 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
245 120 avio_wb32(pb, sSize); // sample size
246 120 avio_wb32(pb, entries); // sample count
247 } else {
248 262 avio_wb32(pb, 0); // sample size
249 262 avio_wb32(pb, entries); // sample count
250
2/2
✓ Branch 0 taken 13256 times.
✓ Branch 1 taken 262 times.
13518 for (i = 0; i < track->entry; i++) {
251
2/2
✓ Branch 0 taken 13256 times.
✓ Branch 1 taken 13256 times.
26512 for (j = 0; j < track->cluster[i].entries; j++) {
252 13256 avio_wb32(pb, track->cluster[i].size /
253 13256 track->cluster[i].entries);
254 }
255 }
256 }
257 382 return update_size(pb, pos);
258 }
259
260 /* Sample to chunk atom */
261 382 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
262 {
263 382 int index = 0, oldidx = -1, oldval = -1, i;
264 int64_t entryPos, curpos;
265
266 382 int64_t pos = avio_tell(pb);
267 382 avio_wb32(pb, 0); /* size */
268 382 ffio_wfourcc(pb, "stsc");
269 382 avio_wb32(pb, 0); // version & flags
270 382 entryPos = avio_tell(pb);
271 382 avio_wb32(pb, track->chunkCount); // entry count
272
2/2
✓ Branch 0 taken 17321 times.
✓ Branch 1 taken 382 times.
17703 for (i = 0; i < track->entry; i++) {
273
2/2
✓ Branch 0 taken 2133 times.
✓ Branch 1 taken 15188 times.
17321 if ((oldval != track->cluster[i].samples_in_chunk ||
274
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2131 times.
✓ Branch 2 taken 839 times.
✓ Branch 3 taken 14351 times.
17321 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
275 839 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
276 839 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
277 839 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
278 839 oldval = track->cluster[i].samples_in_chunk;
279 839 oldidx = track->cluster[i].stsd_index;
280 839 index++;
281 }
282 }
283 382 curpos = avio_tell(pb);
284 382 avio_seek(pb, entryPos, SEEK_SET);
285 382 avio_wb32(pb, index); // rewrite size
286 382 avio_seek(pb, curpos, SEEK_SET);
287
288 382 return update_size(pb, pos);
289 }
290
291 /* Sync sample atom */
292 68 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
293 {
294 int64_t curpos, entryPos;
295 68 int i, index = 0;
296 68 int64_t pos = avio_tell(pb);
297 68 avio_wb32(pb, 0); // size
298
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
299 68 avio_wb32(pb, 0); // version & flags
300 68 entryPos = avio_tell(pb);
301 68 avio_wb32(pb, track->entry); // entry count
302
2/2
✓ Branch 0 taken 3478 times.
✓ Branch 1 taken 68 times.
3546 for (i = 0; i < track->entry; i++) {
303
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 3253 times.
3478 if (track->cluster[i].flags & flag) {
304 225 avio_wb32(pb, i + 1);
305 225 index++;
306 }
307 }
308 68 curpos = avio_tell(pb);
309 68 avio_seek(pb, entryPos, SEEK_SET);
310 68 avio_wb32(pb, index); // rewrite size
311 68 avio_seek(pb, curpos, SEEK_SET);
312 68 return update_size(pb, pos);
313 }
314
315 /* Sample dependency atom */
316 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
317 {
318 int i;
319 uint8_t leading, dependent, reference, redundancy;
320 3 int64_t pos = avio_tell(pb);
321 3 avio_wb32(pb, 0); // size
322 3 ffio_wfourcc(pb, "sdtp");
323 3 avio_wb32(pb, 0); // version & flags
324
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
325 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
326 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
327
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
328 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
329 }
330
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
331 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
332 }
333 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
334 13 (reference << 2) | redundancy);
335 }
336 3 return update_size(pb, pos);
337 }
338
339 #if CONFIG_IAMFENC
340 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
341 {
342 AVIOContext *dyn_bc;
343 5 int64_t pos = avio_tell(pb);
344 5 uint8_t *dyn_buf = NULL;
345 int dyn_size;
346 5 int ret = avio_open_dyn_buf(&dyn_bc);
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
348 return ret;
349
350 5 avio_wb32(pb, 0);
351 5 ffio_wfourcc(pb, "iacb");
352 5 avio_w8(pb, 1); // configurationVersion
353
354 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0) {
356 ffio_free_dyn_buf(&dyn_bc);
357 return ret;
358 }
359
360 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
361 5 ffio_write_leb(pb, dyn_size);
362 5 avio_write(pb, dyn_buf, dyn_size);
363 5 av_free(dyn_buf);
364
365 5 return update_size(pb, pos);
366 }
367 #endif
368
369 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
370 {
371 avio_wb32(pb, 0x11); /* size */
372 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
373 else ffio_wfourcc(pb, "damr");
374 ffio_wfourcc(pb, "FFMP");
375 avio_w8(pb, 0); /* decoder version */
376
377 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
378 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
379 avio_w8(pb, 0x01); /* Frames per sample */
380 return 0x11;
381 }
382
383 struct eac3_info {
384 AVPacket *pkt;
385 uint8_t eof;
386 uint8_t ec3_done;
387 uint8_t num_blocks;
388
389 /* Layout of the EC3SpecificBox */
390 /* maximum bitrate */
391 uint16_t data_rate;
392 int8_t ac3_bit_rate_code;
393 /* number of independent substreams */
394 uint8_t num_ind_sub;
395 struct {
396 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
397 uint8_t fscod;
398 /* bit stream identification 5 bits */
399 uint8_t bsid;
400 /* one bit reserved */
401 /* audio service mixing (not supported yet) 1 bit */
402 /* bit stream mode 3 bits */
403 uint8_t bsmod;
404 /* audio coding mode 3 bits */
405 uint8_t acmod;
406 /* sub woofer on 1 bit */
407 uint8_t lfeon;
408 /* 3 bits reserved */
409 /* number of dependent substreams associated with this substream 4 bits */
410 uint8_t num_dep_sub;
411 /* channel locations of the dependent substream(s), if any, 9 bits */
412 uint16_t chan_loc;
413 /* if there is no dependent substream, then one bit reserved instead */
414 } substream[1]; /* TODO: support 8 independent substreams */
415 /* indicates the decoding complexity, 8 bits */
416 uint8_t complexity_index_type_a;
417 };
418
419 7 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
420 {
421 7 struct eac3_info *info = track->eac3_priv;
422 PutBitContext pbc;
423 uint8_t buf[3];
424
425
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!info || !info->ec3_done) {
426 av_log(s, AV_LOG_ERROR,
427 "Cannot write moov atom before AC3 packets."
428 " Set the delay_moov flag to fix this.\n");
429 return AVERROR(EINVAL);
430 }
431
432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->substream[0].bsid > 8) {
433 av_log(s, AV_LOG_ERROR,
434 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
435 "ISOBMFF specification in ETSI TS 102 366!\n",
436 info->substream[0].bsid);
437 return AVERROR(EINVAL);
438 }
439
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->ac3_bit_rate_code < 0) {
441 av_log(s, AV_LOG_ERROR,
442 "No valid AC3 bit rate code for data rate of %d!\n",
443 info->data_rate);
444 return AVERROR(EINVAL);
445 }
446
447 7 avio_wb32(pb, 11);
448 7 ffio_wfourcc(pb, "dac3");
449
450 7 init_put_bits(&pbc, buf, sizeof(buf));
451 7 put_bits(&pbc, 2, info->substream[0].fscod);
452 7 put_bits(&pbc, 5, info->substream[0].bsid);
453 7 put_bits(&pbc, 3, info->substream[0].bsmod);
454 7 put_bits(&pbc, 3, info->substream[0].acmod);
455 7 put_bits(&pbc, 1, info->substream[0].lfeon);
456 7 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
457 7 put_bits(&pbc, 5, 0); // reserved
458
459 7 flush_put_bits(&pbc);
460 7 avio_write(pb, buf, sizeof(buf));
461
462 7 return 11;
463 }
464
465 1737 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
466 {
467 1737 AC3HeaderInfo *hdr = NULL;
468 struct eac3_info *info;
469 int num_blocks, ret;
470
471
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
1737 if (!track->eac3_priv) {
472
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
473 return AVERROR(ENOMEM);
474
475 10 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
476 }
477 1737 info = track->eac3_priv;
478
479
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
1737 if (!info->pkt && !(info->pkt = av_packet_alloc()))
480 return AVERROR(ENOMEM);
481
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (info->eof) {
483 av_assert1(!info->pkt->size);
484 ret = pkt->size;
485 goto end;
486 }
487
488
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1736 times.
1737 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
490 goto end;
491
492 /* drop the packets until we see a good one */
493
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
494 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
495 1 ret = 0;
496 } else
497 ret = AVERROR_INVALIDDATA;
498 1 goto end;
499 }
500
501 1736 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
502 1736 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
503 hdr->ac3_bit_rate_code);
504 1736 info->complexity_index_type_a = hdr->complexity_index_type_a;
505
506 1736 num_blocks = hdr->num_blocks;
507
508
2/2
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 14 times.
1736 if (!info->ec3_done) {
509 /* AC-3 substream must be the first one */
510
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
14 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
511 ret = AVERROR(EINVAL);
512 goto end;
513 }
514
515 /* this should always be the case, given that our AC-3 parser
516 * concatenates dependent frames to their independent parent */
517
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
518
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
519 /* substream ids must be incremental */
520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid > info->num_ind_sub + 1) {
521 ret = AVERROR(EINVAL);
522 goto end;
523 }
524
525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid == info->num_ind_sub + 1) {
526 //info->num_ind_sub++;
527 avpriv_request_sample(mov->fc, "Multiple independent substreams");
528 ret = AVERROR_PATCHWELCOME;
529 goto end;
530
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 } else if (hdr->substreamid < info->num_ind_sub ||
531
3/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 10 times.
14 hdr->substreamid == 0 && info->substream[0].bsid) {
532 4 info->ec3_done = 1;
533 4 goto concatenate;
534 }
535 } else {
536 if (hdr->substreamid != 0) {
537 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
538 ret = AVERROR_PATCHWELCOME;
539 goto end;
540 }
541 }
542
543 /* fill the info needed for the "dec3" atom */
544 10 info->substream[hdr->substreamid].fscod = hdr->sr_code;
545 10 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
546 10 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
547 10 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
548 10 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
549
550
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (track->par->codec_id == AV_CODEC_ID_AC3) {
551 // with AC-3 we only require the information of a single packet,
552 // so we can finish as soon as the basic values of the bit stream
553 // have been set to the track's informational structure.
554 6 info->ec3_done = 1;
555 6 goto concatenate;
556 }
557
558 /* Parse dependent substream(s), if any */
559
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (pkt->size != hdr->frame_size) {
560 1 int cumul_size = hdr->frame_size;
561 1 int parent = hdr->substreamid;
562
563
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (cumul_size != pkt->size) {
564 1 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
566 goto end;
567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
568 ret = AVERROR(EINVAL);
569 goto end;
570 }
571 1 info->substream[parent].num_dep_sub++;
572 1 ret /= 8;
573
574 /* get the dependent stream channel map, if exists */
575
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (hdr->channel_map_present) {
576 /* chanmap is a 16-bit field read MSB-first, so flag index
577 * i sits at bit (15 - i), matching the indexing of
578 * ff_eac3_custom_channel_map_locations. chan_loc bits 0-7
579 * carry flag indices 5-12, i.e. chanmap bit (10 - j).
580 * The mapping is not contiguous at the top: index 13
581 * (Lts/Rts) has no chan_loc bit and is skipped, and
582 * chan_loc bit 8 carries LFE2, which is index 14 and so
583 * chanmap bit 1. */
584
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for (int j = 0; j < 8; j++) {
585
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if ((hdr->channel_map >> (10 - j)) & 1)
586 1 info->substream[parent].chan_loc |= 1 << j;
587 }
588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((hdr->channel_map >> 1) & 1)
589 info->substream[parent].chan_loc |= 1 << 8;
590 } else {
591 info->substream[parent].chan_loc |= hdr->channel_mode;
592 }
593 1 cumul_size += hdr->frame_size;
594 }
595 }
596 }
597
598 1726 concatenate:
599
2/4
✓ Branch 0 taken 1736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1736 times.
✗ Branch 3 not taken.
1736 if (!info->num_blocks && num_blocks == 6) {
600 1736 ret = pkt->size;
601 1736 goto end;
602 }
603 else if (info->num_blocks + num_blocks > 6) {
604 ret = AVERROR_INVALIDDATA;
605 goto end;
606 }
607
608 if (!info->num_blocks) {
609 ret = av_packet_ref(info->pkt, pkt);
610 if (!ret)
611 info->num_blocks = num_blocks;
612 goto end;
613 } else {
614 const AVPacketSideData *sd;
615 int64_t duration = pkt->duration;
616 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
617 goto end;
618 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
619 if (sd && sd->size >= 10) {
620 uint8_t *buf = av_packet_new_side_data(info->pkt, AV_PKT_DATA_SKIP_SAMPLES, sd->size);
621 if (buf)
622 memcpy(buf, sd->data, sd->size);
623 if (track->par->frame_size)
624 duration = FFMAX(av_rescale_q(track->par->frame_size, (AVRational){ 1, track->par->sample_rate },
625 track->st->time_base), duration);
626 }
627 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
628 info->num_blocks += num_blocks;
629 info->pkt->duration += duration;
630 if (info->num_blocks != 6)
631 goto end;
632 av_packet_unref(pkt);
633 av_packet_move_ref(pkt, info->pkt);
634 info->num_blocks = 0;
635 }
636 ret = pkt->size;
637
638 1737 end:
639 1737 av_free(hdr);
640
641 1737 return ret;
642 }
643
644 4 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
645 {
646 PutBitContext pbc;
647 uint8_t *buf;
648 struct eac3_info *info;
649 int size, i;
650
651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->eac3_priv) {
652 av_log(s, AV_LOG_ERROR,
653 "Cannot write moov atom before EAC3 packets parsed.\n");
654 return AVERROR(EINVAL);
655 }
656
657 4 info = track->eac3_priv;
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
659 4 buf = av_malloc(size);
660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!buf) {
661 return AVERROR(ENOMEM);
662 }
663
664 4 init_put_bits(&pbc, buf, size);
665 4 put_bits(&pbc, 13, info->data_rate);
666 4 put_bits(&pbc, 3, info->num_ind_sub);
667
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i <= info->num_ind_sub; i++) {
668 4 put_bits(&pbc, 2, info->substream[i].fscod);
669 4 put_bits(&pbc, 5, info->substream[i].bsid);
670 4 put_bits(&pbc, 1, 0); /* reserved */
671 4 put_bits(&pbc, 1, 0); /* asvc */
672 4 put_bits(&pbc, 3, info->substream[i].bsmod);
673 4 put_bits(&pbc, 3, info->substream[i].acmod);
674 4 put_bits(&pbc, 1, info->substream[i].lfeon);
675 4 put_bits(&pbc, 3, 0); /* reserved */
676 4 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
677
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (!info->substream[i].num_dep_sub) {
678 3 put_bits(&pbc, 1, 0); /* reserved */
679 } else {
680 1 put_bits(&pbc, 9, info->substream[i].chan_loc);
681 }
682 }
683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (info->complexity_index_type_a) {
684 put_bits(&pbc, 7, 0); /* reserved */
685 put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
686 put_bits(&pbc, 8, info->complexity_index_type_a);
687 }
688 4 flush_put_bits(&pbc);
689 4 size = put_bytes_output(&pbc);
690
691 4 avio_wb32(pb, size + 8);
692 4 ffio_wfourcc(pb, "dec3");
693 4 avio_write(pb, buf, size);
694
695 4 av_free(buf);
696
697 4 return size;
698 }
699
700 /**
701 * This function writes extradata "as is".
702 * Extradata must be formatted like a valid atom (with size and tag).
703 */
704 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
705 {
706 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
707 12 return track->extradata_size[track->last_stsd_index];
708 }
709
710 static int mov_write_enda_tag(AVIOContext *pb)
711 {
712 avio_wb32(pb, 10);
713 ffio_wfourcc(pb, "enda");
714 avio_wb16(pb, 1); /* little endian */
715 return 10;
716 }
717
718 2 static int mov_write_enda_tag_be(AVIOContext *pb)
719 {
720 2 avio_wb32(pb, 10);
721 2 ffio_wfourcc(pb, "enda");
722 2 avio_wb16(pb, 0); /* big endian */
723 2 return 10;
724 }
725
726 405 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
727 {
728 405 int i = 3;
729 405 avio_w8(pb, tag);
730
2/2
✓ Branch 0 taken 1215 times.
✓ Branch 1 taken 405 times.
1620 for (; i > 0; i--)
731 1215 avio_w8(pb, (size >> (7 * i)) | 0x80);
732 405 avio_w8(pb, size & 0x7F);
733 405 }
734
735 278 static unsigned compute_avg_bitrate(MOVTrack *track)
736 {
737 278 uint64_t size = 0;
738 int i;
739
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 226 times.
278 if (!track->track_duration)
740 52 return 0;
741
2/2
✓ Branch 0 taken 15257 times.
✓ Branch 1 taken 226 times.
15483 for (i = 0; i < track->entry; i++)
742 15257 size += track->cluster[i].size;
743 226 return size * 8 * track->timescale / track->track_duration;
744 }
745
746 struct mpeg4_bit_rate_values {
747 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
748 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
749 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
750 };
751
752 278 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
753 {
754 556 const AVPacketSideData *sd = track->st ?
755 277 av_packet_side_data_get(track->st->codecpar->coded_side_data,
756 277 track->st->codecpar->nb_coded_side_data,
757
2/2
✓ Branch 0 taken 277 times.
✓ Branch 1 taken 1 times.
278 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
758
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 228 times.
278 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
759 278 struct mpeg4_bit_rate_values bit_rates = { 0 };
760
761 278 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
762
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 124 times.
278 if (!bit_rates.avg_bit_rate) {
763 // if the average bit rate cannot be calculated at this point, such as
764 // in the case of fragmented MP4, utilize the following values as
765 // fall-back in priority order:
766 //
767 // 1. average bit rate property
768 // 2. bit rate (usually average over the whole clip)
769 // 3. maximum bit rate property
770
771
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
154 if (props && props->avg_bitrate) {
772 16 bit_rates.avg_bit_rate = props->avg_bitrate;
773
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 129 times.
138 } else if (track->par->bit_rate) {
774 9 bit_rates.avg_bit_rate = track->par->bit_rate;
775
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
129 } else if (props && props->max_bitrate) {
776 bit_rates.avg_bit_rate = props->max_bitrate;
777 }
778 }
779
780 // (FIXME should be max rate in any 1 sec window)
781 278 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
782 bit_rates.avg_bit_rate);
783
784 // utilize values from properties if we have them available
785
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 228 times.
278 if (props) {
786 // no avg_bitrate signals that the track is VBR
787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!props->avg_bitrate)
788 bit_rates.avg_bit_rate = props->avg_bitrate;
789 50 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
790 props->max_bitrate);
791 50 bit_rates.buffer_size = props->buffer_size / 8;
792 }
793
794 278 return bit_rates;
795 }
796
797 103 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
798 {
799 103 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
800 103 int64_t pos = avio_tell(pb);
801 206 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
802
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7 times.
103 5 + track->extradata_size[track->last_stsd_index] : 0;
803
804 103 avio_wb32(pb, 0); // size
805 103 ffio_wfourcc(pb, "esds");
806 103 avio_wb32(pb, 0); // Version
807
808 // ES descriptor
809 103 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
810 103 avio_wb16(pb, track->track_id);
811 103 avio_w8(pb, 0x00); // flags (= no flags)
812
813 // DecoderConfig descriptor
814 103 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
815
816 // Object type indication
817
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
103 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
818
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 102 times.
103 track->par->codec_id == AV_CODEC_ID_MP3) &&
819
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 track->par->sample_rate > 24000)
820 1 avio_w8(pb, 0x6B); // 11172-3
821 else
822 102 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
823
824 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
825 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
827 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
828
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 36 times.
103 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
829 67 avio_w8(pb, 0x15); // flags (= Audiostream)
830 else
831 36 avio_w8(pb, 0x11); // flags (= Visualstream)
832
833 103 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
834 103 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
835 103 avio_wb32(pb, bit_rates.avg_bit_rate);
836
837
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7 times.
103 if (track->extradata_size[track->last_stsd_index]) {
838 // DecoderSpecific info descriptor
839 96 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
840 96 avio_write(pb, track->extradata[track->last_stsd_index],
841 96 track->extradata_size[track->last_stsd_index]);
842 }
843
844 // SL descriptor
845 103 put_descr(pb, 0x06, 1);
846 103 avio_w8(pb, 0x02);
847 103 return update_size(pb, pos);
848 }
849
850 75 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
851 {
852
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 return codec_id == AV_CODEC_ID_PCM_S24LE ||
853
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 codec_id == AV_CODEC_ID_PCM_S32LE ||
854
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
150 codec_id == AV_CODEC_ID_PCM_F32LE ||
855 codec_id == AV_CODEC_ID_PCM_F64LE;
856 }
857
858 75 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
859 {
860
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
71 return codec_id == AV_CODEC_ID_PCM_S24BE ||
861
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 codec_id == AV_CODEC_ID_PCM_S32BE ||
862
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
146 codec_id == AV_CODEC_ID_PCM_F32BE ||
863 codec_id == AV_CODEC_ID_PCM_F64BE;
864 }
865
866 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
867 {
868 int ret;
869 int64_t pos = avio_tell(pb);
870 avio_wb32(pb, 0);
871 avio_wl32(pb, track->tag); // store it byteswapped
872 track->par->codec_tag = av_bswap16(track->tag >> 16);
873 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
874 return ret;
875 return update_size(pb, pos);
876 }
877
878 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
879 {
880 int ret;
881 int64_t pos = avio_tell(pb);
882 avio_wb32(pb, 0);
883 ffio_wfourcc(pb, "wfex");
884 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
885 return ret;
886 return update_size(pb, pos);
887 }
888
889 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
890 {
891 int64_t pos = avio_tell(pb);
892 avio_wb32(pb, 0);
893 ffio_wfourcc(pb, "dfLa");
894 avio_w8(pb, 0); /* version */
895 avio_wb24(pb, 0); /* flags */
896
897 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
898 if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
899 return AVERROR_INVALIDDATA;
900
901 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
902 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
903 avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
904 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
905
906 return update_size(pb, pos);
907 }
908
909 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
910 {
911 int64_t pos = avio_tell(pb);
912 int channels, channel_map;
913 avio_wb32(pb, 0);
914 ffio_wfourcc(pb, "dOps");
915 avio_w8(pb, 0); /* Version */
916 if (track->extradata_size[track->last_stsd_index] < 19) {
917 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
918 return AVERROR_INVALIDDATA;
919 }
920 /* extradata contains an Ogg OpusHead, other than byte-ordering and
921 OpusHead's preceding magic/version, OpusSpecificBox is currently
922 identical. */
923 channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
924 channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
925
926 avio_w8(pb, channels); /* OuputChannelCount */
927 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
928 avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
929 avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
930 avio_w8(pb, channel_map); /* ChannelMappingFamily */
931 /* Write the rest of the header out without byte-swapping. */
932 if (channel_map) {
933 if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
934 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
935 return AVERROR_INVALIDDATA;
936 }
937 avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
938 }
939
940 return update_size(pb, pos);
941 }
942
943 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
944 {
945 int64_t pos = avio_tell(pb);
946 int length;
947 avio_wb32(pb, 0);
948 ffio_wfourcc(pb, "dmlp");
949
950 if (track->extradata_size[track->last_stsd_index] < 20) {
951 av_log(s, AV_LOG_ERROR,
952 "Cannot write moov atom before TrueHD packets."
953 " Set the delay_moov flag to fix this.\n");
954 return AVERROR(EINVAL);
955 }
956
957 length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
958 if (length < 20 || length > track->extradata_size[track->last_stsd_index])
959 return AVERROR_INVALIDDATA;
960
961 // Only TrueHD is supported
962 if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
963 return AVERROR_INVALIDDATA;
964
965 avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
966 avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
967 avio_wb32(pb, 0); /* reserved */
968
969 return update_size(pb, pos);
970 }
971
972 86 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
973 {
974 86 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
975 86 AVChannelLayout ch_layout = { 0 };
976 int64_t pos;
977 int ambisonic_order, ambi_channels, non_diegetic_channels;
978 int i, ret;
979
980
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 if (!str)
981 86 return 0;
982
983 ret = av_channel_layout_from_string(&ch_layout, str->value);
984 if (ret < 0) {
985 if (ret == AVERROR(EINVAL)) {
986 invalid:
987 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
988 ret = 0;
989 }
990 av_channel_layout_uninit(&ch_layout);
991 return ret;
992 }
993
994 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
995 goto invalid;
996
997 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
998 if (ambisonic_order < 0)
999 goto invalid;
1000
1001 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
1002 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
1003 if (non_diegetic_channels &&
1004 (non_diegetic_channels != 2 ||
1005 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
1006 goto invalid;
1007
1008 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
1009
1010 pos = avio_tell(pb);
1011
1012 avio_wb32(pb, 0); // Size
1013 ffio_wfourcc(pb, "SA3D");
1014 avio_w8(pb, 0); // version
1015 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
1016 avio_wb32(pb, ambisonic_order); // ambisonic_order
1017 avio_w8(pb, 0); // ambisonic_channel_ordering
1018 avio_w8(pb, 0); // ambisonic_normalization
1019 avio_wb32(pb, ch_layout.nb_channels); // num_channels
1020 for (i = 0; i < ambi_channels; i++)
1021 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
1022 for (; i < ch_layout.nb_channels; i++)
1023 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
1024
1025 av_channel_layout_uninit(&ch_layout);
1026
1027 return update_size(pb, pos);
1028 }
1029
1030 39 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1031 {
1032 uint32_t layout_tag, bitmap, *channel_desc;
1033 39 int64_t pos = avio_tell(pb);
1034 int num_desc, ret;
1035
1036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (track->multichannel_as_mono)
1037 return 0;
1038
1039 39 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
1040 &bitmap, &channel_desc);
1041
1042
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0) {
1043 if (ret == AVERROR(ENOSYS)) {
1044 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
1045 "lack of channel information\n");
1046 ret = 0;
1047 }
1048
1049 return ret;
1050 }
1051
1052 /* no predefined tag found + ch_layout in AV_CHANNEL_ORDER_NATIVE
1053 * but bitstream channels not actually in native order */
1054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (layout_tag == MOV_CH_LAYOUT_UNKNOWN)
1055 return 0;
1056
1057
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
39 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1059 1 channel_desc = av_malloc(sizeof(*channel_desc));
1060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1061 return AVERROR(ENOMEM);
1062
1063 1 layout_tag = 0;
1064 1 bitmap = 0;
1065 1 *channel_desc = 3; // channel label "Center"
1066 }
1067
1068
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 36 times.
39 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1069
1070 39 avio_wb32(pb, 0); // Size
1071 39 ffio_wfourcc(pb, "chan"); // Type
1072 39 avio_w8(pb, 0); // Version
1073 39 avio_wb24(pb, 0); // Flags
1074 39 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1075 39 avio_wb32(pb, bitmap); // mChannelBitmap
1076 39 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1077
1078
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39 times.
42 for (int i = 0; i < num_desc; i++) {
1079 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1080 3 avio_wb32(pb, 0); // mChannelFlags
1081 3 avio_wl32(pb, 0); // mCoordinates[0]
1082 3 avio_wl32(pb, 0); // mCoordinates[1]
1083 3 avio_wl32(pb, 0); // mCoordinates[2]
1084 }
1085
1086 39 av_free(channel_desc);
1087
1088 39 return update_size(pb, pos);
1089 }
1090
1091 14 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1092 {
1093 14 int64_t pos = avio_tell(pb);
1094
1095 14 avio_wb32(pb, 0); /* size */
1096 14 ffio_wfourcc(pb, "wave");
1097
1098
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1099 14 avio_wb32(pb, 12); /* size */
1100 14 ffio_wfourcc(pb, "frma");
1101 14 avio_wl32(pb, track->tag);
1102 }
1103
1104
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1105 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1106 3 avio_wb32(pb, 12); /* size */
1107 3 ffio_wfourcc(pb, "mp4a");
1108 3 avio_wb32(pb, 0);
1109 3 mov_write_esds_tag(pb, track);
1110
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1111 mov_write_enda_tag(pb);
1112
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
11 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1113 2 mov_write_enda_tag_be(pb);
1114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1115 mov_write_amr_tag(pb, track);
1116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1117 mov_write_ac3_tag(s, pb, track);
1118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1119 mov_write_eac3_tag(s, pb, track);
1120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1121 track->par->codec_id == AV_CODEC_ID_QDM2) {
1122 9 mov_write_extradata_tag(pb, track);
1123 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1124 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1125 mov_write_ms_tag(s, pb, track);
1126 }
1127
1128 14 avio_wb32(pb, 8); /* size */
1129 14 avio_wb32(pb, 0); /* null tag */
1130
1131 14 return update_size(pb, pos);
1132 }
1133
1134 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1135 {
1136 uint8_t *unescaped;
1137 const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1138 track->extradata_size[track->last_stsd_index];
1139 int unescaped_size, seq_found = 0;
1140 int level = 0, interlace = 0;
1141 int packet_seq = track->vc1_info.packet_seq;
1142 int packet_entry = track->vc1_info.packet_entry;
1143 int slices = track->vc1_info.slices;
1144 PutBitContext pbc;
1145
1146 if (track->start_dts == AV_NOPTS_VALUE) {
1147 /* No packets written yet, vc1_info isn't authoritative yet. */
1148 /* Assume inline sequence and entry headers. */
1149 packet_seq = packet_entry = 1;
1150 av_log(NULL, AV_LOG_WARNING,
1151 "moov atom written before any packets, unable to write correct "
1152 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1153 }
1154
1155 unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1156 if (!unescaped)
1157 return AVERROR(ENOMEM);
1158 start = find_next_marker(track->extradata[track->last_stsd_index], end);
1159 for (next = start; next < end; start = next) {
1160 GetBitContext gb;
1161 int size;
1162 next = find_next_marker(start + 4, end);
1163 size = next - start - 4;
1164 if (size <= 0)
1165 continue;
1166 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1167 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1168 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1169 int profile = get_bits(&gb, 2);
1170 if (profile != PROFILE_ADVANCED) {
1171 av_free(unescaped);
1172 return AVERROR(ENOSYS);
1173 }
1174 seq_found = 1;
1175 level = get_bits(&gb, 3);
1176 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1177 * width, height */
1178 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1179 skip_bits(&gb, 1); /* broadcast */
1180 interlace = get_bits1(&gb);
1181 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1182 }
1183 }
1184 if (!seq_found) {
1185 av_free(unescaped);
1186 return AVERROR(ENOSYS);
1187 }
1188
1189 init_put_bits(&pbc, buf, 7);
1190 /* VC1DecSpecStruc */
1191 put_bits(&pbc, 4, 12); /* profile - advanced */
1192 put_bits(&pbc, 3, level);
1193 put_bits(&pbc, 1, 0); /* reserved */
1194 /* VC1AdvDecSpecStruc */
1195 put_bits(&pbc, 3, level);
1196 put_bits(&pbc, 1, 0); /* cbr */
1197 put_bits(&pbc, 6, 0); /* reserved */
1198 put_bits(&pbc, 1, !interlace); /* no interlace */
1199 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1200 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1201 put_bits(&pbc, 1, !slices); /* no slice code */
1202 put_bits(&pbc, 1, 0); /* no bframe */
1203 put_bits(&pbc, 1, 0); /* reserved */
1204
1205 /* framerate */
1206 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1207 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1208 else
1209 put_bits32(&pbc, 0xffffffff);
1210
1211 flush_put_bits(&pbc);
1212
1213 av_free(unescaped);
1214
1215 return 0;
1216 }
1217
1218 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1219 {
1220 uint8_t buf[7] = { 0 };
1221 int ret;
1222
1223 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1224 return ret;
1225
1226 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1227 ffio_wfourcc(pb, "dvc1");
1228 avio_write(pb, buf, sizeof(buf));
1229 avio_write(pb, track->extradata[track->last_stsd_index],
1230 track->extradata_size[track->last_stsd_index]);
1231
1232 return 0;
1233 }
1234
1235 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1236 {
1237 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1238 4 ffio_wfourcc(pb, "glbl");
1239 4 avio_write(pb, track->extradata[track->last_stsd_index],
1240 4 track->extradata_size[track->last_stsd_index]);
1241 4 return 8 + track->extradata_size[track->last_stsd_index];
1242 }
1243
1244 /**
1245 * Compute flags for 'lpcm' tag.
1246 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1247 */
1248 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1249 {
1250
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 switch (codec_id) {
1251 case AV_CODEC_ID_PCM_F32BE:
1252 case AV_CODEC_ID_PCM_F64BE:
1253 return 11;
1254 case AV_CODEC_ID_PCM_F32LE:
1255 case AV_CODEC_ID_PCM_F64LE:
1256 return 9;
1257 case AV_CODEC_ID_PCM_U8:
1258 return 10;
1259 case AV_CODEC_ID_PCM_S16BE:
1260 case AV_CODEC_ID_PCM_S24BE:
1261 case AV_CODEC_ID_PCM_S32BE:
1262 return 14;
1263 case AV_CODEC_ID_PCM_S8:
1264 case AV_CODEC_ID_PCM_S16LE:
1265 case AV_CODEC_ID_PCM_S24LE:
1266 case AV_CODEC_ID_PCM_S32LE:
1267 return 12;
1268 8 default:
1269 8 return 0;
1270 }
1271 }
1272
1273 32940 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1274 {
1275 int64_t next_dts;
1276
1277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32940 times.
32940 if (cluster_idx >= track->entry)
1278 return 0;
1279
1280
2/2
✓ Branch 0 taken 924 times.
✓ Branch 1 taken 32016 times.
32940 if (cluster_idx + 1 == track->entry)
1281 924 next_dts = track->track_duration + track->start_dts;
1282 else
1283 32016 next_dts = track->cluster[cluster_idx + 1].dts;
1284
1285 32940 next_dts -= track->cluster[cluster_idx].dts;
1286
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32940 times.
32940 av_assert0(next_dts >= 0);
1288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32940 times.
32940 av_assert0(next_dts <= INT_MAX);
1289
1290 32940 return next_dts;
1291 }
1292
1293 4 static int get_samples_per_packet(MOVTrack *track)
1294 {
1295 int i, first_duration;
1296
1297 /* use 1 for raw PCM */
1298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1299 return 1;
1300
1301 /* check to see if duration is constant for all clusters */
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1303 return 0;
1304 4 first_duration = get_cluster_duration(track, 0);
1305
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1306
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1307 4 return 0;
1308 }
1309 return first_duration;
1310 }
1311
1312 175 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1313 {
1314 175 int64_t pos = avio_tell(pb);
1315 175 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1316
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
175 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1317
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 !bit_rates.buffer_size)
1318 // no useful data to be written, skip
1319 86 return 0;
1320
1321 89 avio_wb32(pb, 0); /* size */
1322 89 ffio_wfourcc(pb, "btrt");
1323
1324 89 avio_wb32(pb, bit_rates.buffer_size);
1325 89 avio_wb32(pb, bit_rates.max_bit_rate);
1326 89 avio_wb32(pb, bit_rates.avg_bit_rate);
1327
1328 89 return update_size(pb, pos);
1329 }
1330
1331 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1332 {
1333 7 int64_t pos = avio_tell(pb);
1334 7 int config = 0;
1335 int ret;
1336 7 uint8_t *speaker_pos = NULL;
1337 7 const AVChannelLayout *layout = &track->par->ch_layout;
1338
1339 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1340
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
7 if (ret || !config) {
1341 4 config = 0;
1342 4 speaker_pos = av_malloc(layout->nb_channels);
1343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1344 return AVERROR(ENOMEM);
1345 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1346 4 speaker_pos, layout->nb_channels);
1347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1348 char buf[128] = {0};
1349
1350 av_freep(&speaker_pos);
1351 av_channel_layout_describe(layout, buf, sizeof(buf));
1352 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1353 return ret;
1354 }
1355 }
1356
1357 7 avio_wb32(pb, 0); /* size */
1358 7 ffio_wfourcc(pb, "chnl");
1359 7 avio_wb32(pb, 0); /* version & flags */
1360
1361 7 avio_w8(pb, 1); /* stream_structure */
1362 7 avio_w8(pb, config);
1363
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1364 3 avio_wb64(pb, 0);
1365 } else {
1366 4 avio_write(pb, speaker_pos, layout->nb_channels);
1367 4 av_freep(&speaker_pos);
1368 }
1369
1370 7 return update_size(pb, pos);
1371 }
1372
1373 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1374 {
1375 9 int64_t pos = avio_tell(pb);
1376 int format_flags;
1377 int sample_size;
1378
1379 9 avio_wb32(pb, 0); /* size */
1380 9 ffio_wfourcc(pb, "pcmC");
1381 9 avio_wb32(pb, 0); /* version & flags */
1382
1383 /* 0x01: indicates little-endian format */
1384 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1385
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1387
2/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1388 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1389 9 avio_w8(pb, format_flags);
1390 9 sample_size = track->par->bits_per_raw_sample;
1391
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1392 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1394 9 avio_w8(pb, sample_size);
1395
1396 9 return update_size(pb, pos);
1397 }
1398
1399 5 static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track)
1400 {
1401 5 int64_t pos = avio_tell(pb);
1402 5 avio_wb32(pb, 0); /* size */
1403 5 ffio_wfourcc(pb, "srat");
1404 5 avio_wb32(pb, 0); /* version & flags */
1405
1406 5 avio_wb32(pb, track->par->sample_rate);
1407
1408 5 return update_size(pb, pos);
1409 }
1410
1411 128 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1412 {
1413 128 int64_t pos = avio_tell(pb);
1414 128 int version = 0;
1415 128 uint32_t tag = track->tag;
1416 128 int ret = 0;
1417
1418
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
128 if (track->mode == MODE_MOV) {
1419
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
39 if (track->par->sample_rate > UINT16_MAX || !track->par->ch_layout.nb_channels ||
1420
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 track->par->ch_layout.nb_channels > 2) {
1422
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1423 tag = AV_RL32("lpcm");
1424 4 version = 2;
1425
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
61 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1426 26 mov_pcm_be_gt16(track->par->codec_id) ||
1427
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1428
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1430 11 version = 1;
1431 }
1432
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 3 times.
89 } else if (track->mode == MODE_MP4) {
1433
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
86 if (track->par->sample_rate > UINT16_MAX &&
1434 (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG))
1435 5 version = 1;
1436 }
1437
1438 128 avio_wb32(pb, 0); /* size */
1439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (mov->encryption_scheme != MOV_ENC_NONE) {
1440 ffio_wfourcc(pb, "enca");
1441 } else {
1442 128 avio_wl32(pb, tag); // store it byteswapped
1443 }
1444 128 avio_wb32(pb, 0); /* Reserved */
1445 128 avio_wb16(pb, 0); /* Reserved */
1446 128 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1447
1448 /* SoundDescription */
1449 128 avio_wb16(pb, version); /* Version */
1450 128 avio_wb16(pb, 0); /* Revision level */
1451 128 avio_wb32(pb, 0); /* Reserved */
1452
1453
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 124 times.
128 if (version == 2) {
1454 4 avio_wb16(pb, 3);
1455 4 avio_wb16(pb, 16);
1456 4 avio_wb16(pb, 0xfffe);
1457 4 avio_wb16(pb, 0);
1458 4 avio_wb32(pb, 0x00010000);
1459 4 avio_wb32(pb, 72);
1460 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1461 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1462 4 avio_wb32(pb, 0x7F000000);
1463 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1464 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1465 4 avio_wb32(pb, track->sample_size);
1466 4 avio_wb32(pb, get_samples_per_packet(track));
1467 } else {
1468 124 unsigned sample_rate = track->par->sample_rate;
1469
1470
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 89 times.
124 if (track->mode == MODE_MOV) {
1471 35 avio_wb16(pb, track->par->ch_layout.nb_channels);
1472
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1473
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1474 1 avio_wb16(pb, 8); /* bits per sample */
1475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1476 avio_wb16(pb, track->par->bits_per_coded_sample);
1477 else
1478 34 avio_wb16(pb, 16);
1479
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26 times.
35 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1480 } else { /* reserved for mp4/3gp */
1481
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 5 times.
173 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1482 84 0 : track->par->ch_layout.nb_channels);
1483
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 5 times.
89 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 track->par->codec_id == AV_CODEC_ID_ALAC) {
1485 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1486 } else {
1487 84 avio_wb16(pb, 16);
1488 }
1489 89 avio_wb16(pb, 0);
1490
1491
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 89 times.
94 while (sample_rate > UINT16_MAX)
1492 5 sample_rate >>= 1;
1493 }
1494
1495 124 avio_wb16(pb, 0); /* packet size (= 0) */
1496
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 119 times.
124 if (track->tag == MKTAG('i','a','m','f'))
1497 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1499 avio_wb16(pb, 48000);
1500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1501 avio_wb32(pb, track->par->sample_rate);
1502 else
1503 119 avio_wb16(pb, sample_rate);
1504
1505
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
124 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1506 124 avio_wb16(pb, 0); /* Reserved */
1507 }
1508
1509
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 28 times.
128 if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */
1510
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 9 times.
22 if (mov_pcm_le_gt16(track->par->codec_id) ||
1511 11 mov_pcm_be_gt16(track->par->codec_id))
1512 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1513 else
1514 9 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1515 11 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1516 11 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1517 11 avio_wb32(pb, 2); /* Bytes per sample */
1518 }
1519
1520
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
128 if (track->mode == MODE_MOV &&
1521
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
39 (track->par->codec_id == AV_CODEC_ID_AAC ||
1522
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AC3 ||
1523
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1524
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1525
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1526
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1527
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1528
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1529
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
54 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1530
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1531 14 ret = mov_write_wave_tag(s, pb, track);
1532
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 50 times.
114 else if (track->tag == MKTAG('m','p','4','a'))
1533 64 ret = mov_write_esds_tag(pb, track);
1534 #if CONFIG_IAMFENC
1535
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 45 times.
50 else if (track->tag == MKTAG('i','a','m','f'))
1536 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1537 #endif
1538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1539 ret = mov_write_amr_tag(pb, track);
1540
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 38 times.
45 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1541 7 ret = mov_write_ac3_tag(s, pb, track);
1542
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34 times.
38 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1543 4 ret = mov_write_eac3_tag(s, pb, track);
1544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1545 ret = mov_write_extradata_tag(pb, track);
1546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1547 ret = mov_write_wfex_tag(s, pb, track);
1548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1549 ret = mov_write_dfla_tag(pb, track);
1550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1551 ret = mov_write_dops_tag(s, pb, track);
1552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1553 ret = mov_write_dmlp_tag(s, pb, track);
1554
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
34 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1555
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (track->par->sample_rate > UINT16_MAX)
1556 5 mov_write_srat_tag(pb, track);
1557
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1558 7 ret = mov_write_chnl_tag(s, pb, track);
1559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1560 return ret;
1561 9 ret = mov_write_pcmc_tag(s, pb, track);
1562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1563 ret = mov_write_glbl_tag(pb, track);
1564
1565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (ret < 0)
1566 return ret;
1567
1568
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
128 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1569
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 86 times.
86 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1570 return ret;
1571 }
1572
1573
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
128 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1574
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1575 return ret;
1576 }
1577
1578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if (mov->encryption_scheme != MOV_ENC_NONE
1579 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1580 return ret;
1581 }
1582
1583
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
214 if (mov->write_btrt &&
1584 86 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1585 return ret;
1586
1587
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 42 times.
128 if (track->mode == MODE_MP4)
1588 86 track->entry_version = version;
1589
1590 128 ret = update_size(pb, pos);
1591 128 return ret;
1592 }
1593
1594 static int mov_write_d263_tag(AVIOContext *pb)
1595 {
1596 avio_wb32(pb, 0xf); /* size */
1597 ffio_wfourcc(pb, "d263");
1598 ffio_wfourcc(pb, "FFMP");
1599 avio_w8(pb, 0); /* decoder version */
1600 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1601 avio_w8(pb, 0xa); /* level */
1602 avio_w8(pb, 0); /* profile */
1603 return 0xf;
1604 }
1605
1606 2 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1607 {
1608 2 int64_t pos = avio_tell(pb);
1609
1610 2 avio_wb32(pb, 0);
1611 2 ffio_wfourcc(pb, "av1C");
1612 2 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1613 2 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1614 2 return update_size(pb, pos);
1615 }
1616
1617 59 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1618 {
1619 59 int64_t pos = avio_tell(pb);
1620
1621 59 avio_wb32(pb, 0);
1622 59 ffio_wfourcc(pb, "avcC");
1623 59 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1624 59 track->extradata_size[track->last_stsd_index]);
1625 59 return update_size(pb, pos);
1626 }
1627
1628 /* AVS3 Intelligent Media Coding
1629 * Information Technology - Intelligent Media Coding
1630 * Part 6: Intelligent Media Format
1631 */
1632 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1633 {
1634 if (len < 4)
1635 return AVERROR_INVALIDDATA;
1636
1637 if (data[0] == 1) {
1638 // In Avs3DecoderConfigurationRecord format
1639 avio_write(pb, data, len);
1640 return 0;
1641 }
1642
1643 avio_w8(pb, 1); // version
1644 avio_wb16(pb, len); // sequence_header_length
1645 avio_write(pb, data, len); // sequence_header
1646 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1647
1648 return 0;
1649 }
1650
1651 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1652 {
1653 int64_t pos = avio_tell(pb);
1654 avio_wb32(pb, 0);
1655 ffio_wfourcc(pb, "av3c");
1656 mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1657 track->extradata_size[track->last_stsd_index]);
1658 return update_size(pb, pos);
1659 }
1660
1661 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1662 {
1663 int64_t pos = avio_tell(pb);
1664
1665 avio_wb32(pb, 0);
1666 ffio_wfourcc(pb, "vpcC");
1667 ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1668 track->extradata_size[track->last_stsd_index], track->par);
1669 return update_size(pb, pos);
1670 }
1671
1672 11 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1673 {
1674 11 int64_t pos = avio_tell(pb);
1675
1676 11 avio_wb32(pb, 0);
1677 11 ffio_wfourcc(pb, "hvcC");
1678
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (track->tag == MKTAG('h','v','c','1'))
1679 3 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1680 3 track->extradata_size[track->last_stsd_index], 1, s);
1681 else
1682 8 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1683 8 track->extradata_size[track->last_stsd_index], 0, s);
1684 11 return update_size(pb, pos);
1685 }
1686
1687 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1688 {
1689 1 int64_t pos = avio_tell(pb);
1690 int ret;
1691
1692 1 avio_wb32(pb, 0);
1693 1 ffio_wfourcc(pb, "lhvC");
1694
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1695 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1696 1 track->extradata_size[track->last_stsd_index], 1, s);
1697 else
1698 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1699 track->extradata_size[track->last_stsd_index], 0, s);
1700
1701
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1702 avio_seek(pb, pos, SEEK_SET);
1703 return ret;
1704 }
1705
1706 1 return update_size(pb, pos);
1707 }
1708
1709 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1710 {
1711 1 int64_t pos = avio_tell(pb);
1712
1713 1 avio_wb32(pb, 0);
1714 1 ffio_wfourcc(pb, "evcC");
1715
1716
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1717 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1718 1 track->extradata_size[track->last_stsd_index], 1);
1719 else
1720 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1721 track->extradata_size[track->last_stsd_index], 0);
1722
1723 1 return update_size(pb, pos);
1724 }
1725
1726 static int mov_write_lvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1727 {
1728 int64_t pos = avio_tell(pb);
1729
1730 avio_wb32(pb, 0);
1731 ffio_wfourcc(pb, "lvcC");
1732
1733 ff_isom_write_lvcc(pb, track->extradata[track->last_stsd_index],
1734 track->extradata_size[track->last_stsd_index], s);
1735
1736 return update_size(pb, pos);
1737 }
1738
1739 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1740 {
1741 1 int64_t pos = avio_tell(pb);
1742
1743 1 avio_wb32(pb, 0);
1744 1 ffio_wfourcc(pb, "vvcC");
1745
1746 1 avio_w8 (pb, 0); /* version */
1747 1 avio_wb24(pb, 0); /* flags */
1748
1749
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1750 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1751 1 track->extradata_size[track->last_stsd_index], 1);
1752 else
1753 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1754 track->extradata_size[track->last_stsd_index], 0);
1755 1 return update_size(pb, pos);
1756 }
1757
1758 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1759 {
1760 1 int64_t pos = avio_tell(pb);
1761
1762 1 avio_wb32(pb, 0);
1763 1 ffio_wfourcc(pb, "apvC");
1764
1765 1 avio_w8 (pb, 0); /* version */
1766 1 avio_wb24(pb, 0); /* flags */
1767
1768 1 ff_isom_write_apvc(pb, track->apv, s);
1769
1770 1 return update_size(pb, pos);
1771 }
1772
1773 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1774 /* https://community.avid.com/forums/t/136517.aspx */
1775 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1776 {
1777 int interlaced;
1778 int cid;
1779 23 int display_width = track->par->width;
1780 const uint8_t *extradata;
1781
1782
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (track->extradata[track->last_stsd_index] && track->extradata_size[track->last_stsd_index] > 0x29) {
1783
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->extradata[track->last_stsd_index]) != 0) {
1784 /* looks like a DNxHD bit stream */
1785 23 extradata = track->extradata[track->last_stsd_index];
1786 } else {
1787 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1788 return 0;
1789 }
1790 } else {
1791 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1792 return 0;
1793 }
1794
1795 23 cid = AV_RB32(extradata + 0x28);
1796
1797 23 avio_wb32(pb, 24); /* size */
1798 23 ffio_wfourcc(pb, "ACLR");
1799 23 ffio_wfourcc(pb, "ACLR");
1800 23 ffio_wfourcc(pb, "0001");
1801 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1802 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1804 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1805 23 avio_wb32(pb, 1);
1806 } else {
1807 avio_wb32(pb, 2);
1808 }
1809 23 avio_wb32(pb, 0); /* reserved */
1810
1811
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1812 12 int alp = extradata[0x07] & 1;
1813 12 int pma = (extradata[0x07] >> 2) & 1;
1814 12 int sbd = (extradata[0x21] >> 5) & 3;
1815 12 int ssc = (extradata[0x2C] >> 5) & 3;
1816 12 int clv = (extradata[0x2C] >> 1) & 3;
1817 12 int clf = extradata[0x2C] & 1;
1818
1819 12 avio_wb32(pb, 32);
1820 12 ffio_wfourcc(pb, "ADHR");
1821 12 ffio_wfourcc(pb, "0001");
1822 12 avio_wb32(pb, cid); // Compression ID
1823 // 0: 4:2:2 Sub Sampling
1824 // 1: 4:2:0 Sub Sampling
1825 // 2: 4:4:4 Sub Sampling
1826 12 avio_wb32(pb, ssc); // Sub Sampling Control
1827 // 1: 8-bits per sample
1828 // 2: 10-bits per sample
1829 // 3: 12-bits per sample
1830 12 avio_wb32(pb, sbd); // Sample Bit Depth
1831 // 0: Bitstream is encoded using the YCBCR format rules and tables
1832 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1833 12 avio_wb16(pb, clf); // Color Format
1834 // 0: ITU-R BT.709
1835 // 1: ITU-R BT.2020
1836 // 2: ITU-R BT.2020 C
1837 // 3: Out-of-band
1838 12 avio_wb16(pb, clv); // Color Volume
1839 // 0: Alpha channel not present
1840 // 1: Alpha channel present
1841 12 avio_wb16(pb, alp); // Alpha Present
1842 // 0: Alpha has not been applied to video channels
1843 // 1: Alpha has been applied to the video channels prior to encoding
1844 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1845 12 return 0;
1846 }
1847
1848 11 interlaced = extradata[5] & 2;
1849
1850 11 avio_wb32(pb, 24); /* size */
1851 11 ffio_wfourcc(pb, "APRG");
1852 11 ffio_wfourcc(pb, "APRG");
1853 11 ffio_wfourcc(pb, "0001");
1854 // 1 for progressive or 2 for interlaced
1855
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1856 11 avio_wb32(pb, 2);
1857 else
1858 avio_wb32(pb, 1);
1859 11 avio_wb32(pb, 0); /* reserved */
1860
1861 11 avio_wb32(pb, 120); /* size */
1862 11 ffio_wfourcc(pb, "ARES");
1863 11 ffio_wfourcc(pb, "ARES");
1864 11 ffio_wfourcc(pb, "0001");
1865 11 avio_wb32(pb, cid); /* cid */
1866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1867 && track->par->sample_aspect_ratio.den > 0)
1868 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1869 11 avio_wb32(pb, display_width); // field width
1870
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1871 11 avio_wb32(pb, track->par->height / 2); // field height
1872 11 avio_wb32(pb, 2); // num fields
1873 11 avio_wb32(pb, 0); // num black lines (must be 0)
1874 // 4: HD1080i
1875 // 5: HD1080P
1876 // 6: HD720P
1877 11 avio_wb32(pb, 4); // video format
1878 } else {
1879 avio_wb32(pb, track->par->height);
1880 avio_wb32(pb, 1); // num fields
1881 avio_wb32(pb, 0);
1882 if (track->par->height == 1080)
1883 avio_wb32(pb, 5);
1884 else
1885 avio_wb32(pb, 6);
1886 }
1887 /* padding */
1888 11 ffio_fill(pb, 0, 10 * 8);
1889
1890 11 return 0;
1891 }
1892
1893 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1894 {
1895 avio_wb32(pb, 12);
1896 ffio_wfourcc(pb, "DpxE");
1897 if (track->extradata_size[track->last_stsd_index] >= 12 &&
1898 !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1899 avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1900 } else {
1901 avio_wb32(pb, 1);
1902 }
1903 return 0;
1904 }
1905
1906 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1907 {
1908 int tag;
1909
1910
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1911
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
1913 1 else tag = MKTAG('d','v','c',' ');
1914 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1915 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1916 else tag = MKTAG('d','v','p','p');
1917 } else if (track->par->height == 720) { /* HD 720 line */
1918 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1919 else tag = MKTAG('d','v','h','p');
1920 } else if (track->par->height == 1080) { /* HD 1080 line */
1921 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1922 else tag = MKTAG('d','v','h','6');
1923 } else {
1924 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1925 return 0;
1926 }
1927
1928 1 return tag;
1929 }
1930
1931 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1932 {
1933 3 AVRational rational_framerate = st->avg_frame_rate;
1934 3 int rate = 0;
1935
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1936 3 rate = av_q2d(rational_framerate);
1937 3 return rate;
1938 }
1939
1940 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1941 {
1942 1 int tag = track->par->codec_tag;
1943 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1944 1 AVStream *st = track->st;
1945 1 int rate = defined_frame_rate(s, st);
1946
1947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1948 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1949
1950
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1951
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (track->par->width == 1280 && track->par->height == 720) {
1952 if (!interlaced) {
1953 if (rate == 24) tag = MKTAG('x','d','v','4');
1954 else if (rate == 25) tag = MKTAG('x','d','v','5');
1955 else if (rate == 30) tag = MKTAG('x','d','v','1');
1956 else if (rate == 50) tag = MKTAG('x','d','v','a');
1957 else if (rate == 60) tag = MKTAG('x','d','v','9');
1958 }
1959
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1440 && track->par->height == 1080) {
1960 if (!interlaced) {
1961 if (rate == 24) tag = MKTAG('x','d','v','6');
1962 else if (rate == 25) tag = MKTAG('x','d','v','7');
1963 else if (rate == 30) tag = MKTAG('x','d','v','8');
1964 } else {
1965 if (rate == 25) tag = MKTAG('x','d','v','3');
1966 else if (rate == 30) tag = MKTAG('x','d','v','2');
1967 }
1968
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1920 && track->par->height == 1080) {
1969 if (!interlaced) {
1970 if (rate == 24) tag = MKTAG('x','d','v','d');
1971 else if (rate == 25) tag = MKTAG('x','d','v','e');
1972 else if (rate == 30) tag = MKTAG('x','d','v','f');
1973 } else {
1974 if (rate == 25) tag = MKTAG('x','d','v','c');
1975 else if (rate == 30) tag = MKTAG('x','d','v','b');
1976 }
1977 }
1978 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1979 if (track->par->width == 1280 && track->par->height == 720) {
1980 if (!interlaced) {
1981 if (rate == 24) tag = MKTAG('x','d','5','4');
1982 else if (rate == 25) tag = MKTAG('x','d','5','5');
1983 else if (rate == 30) tag = MKTAG('x','d','5','1');
1984 else if (rate == 50) tag = MKTAG('x','d','5','a');
1985 else if (rate == 60) tag = MKTAG('x','d','5','9');
1986 }
1987 } else if (track->par->width == 1920 && track->par->height == 1080) {
1988 if (!interlaced) {
1989 if (rate == 24) tag = MKTAG('x','d','5','d');
1990 else if (rate == 25) tag = MKTAG('x','d','5','e');
1991 else if (rate == 30) tag = MKTAG('x','d','5','f');
1992 } else {
1993 if (rate == 25) tag = MKTAG('x','d','5','c');
1994 else if (rate == 30) tag = MKTAG('x','d','5','b');
1995 }
1996 }
1997 }
1998
1999 1 return tag;
2000 }
2001
2002 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
2003 {
2004 2 int tag = track->par->codec_tag;
2005 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2006 2 AVStream *st = track->st;
2007 2 int rate = defined_frame_rate(s, st);
2008
2009
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
2010 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
2011
2012
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
2013
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
2014 2 return tag;
2015
2016 if (track->par->format == AV_PIX_FMT_YUV420P10) {
2017 if (track->par->width == 960 && track->par->height == 720) {
2018 if (!interlaced) {
2019 if (rate == 24) tag = MKTAG('a','i','5','p');
2020 else if (rate == 25) tag = MKTAG('a','i','5','q');
2021 else if (rate == 30) tag = MKTAG('a','i','5','p');
2022 else if (rate == 50) tag = MKTAG('a','i','5','q');
2023 else if (rate == 60) tag = MKTAG('a','i','5','p');
2024 }
2025 } else if (track->par->width == 1440 && track->par->height == 1080) {
2026 if (!interlaced) {
2027 if (rate == 24) tag = MKTAG('a','i','5','3');
2028 else if (rate == 25) tag = MKTAG('a','i','5','2');
2029 else if (rate == 30) tag = MKTAG('a','i','5','3');
2030 } else {
2031 if (rate == 50) tag = MKTAG('a','i','5','5');
2032 else if (rate == 60) tag = MKTAG('a','i','5','6');
2033 }
2034 }
2035 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
2036 if (track->par->width == 1280 && track->par->height == 720) {
2037 if (!interlaced) {
2038 if (rate == 24) tag = MKTAG('a','i','1','p');
2039 else if (rate == 25) tag = MKTAG('a','i','1','q');
2040 else if (rate == 30) tag = MKTAG('a','i','1','p');
2041 else if (rate == 50) tag = MKTAG('a','i','1','q');
2042 else if (rate == 60) tag = MKTAG('a','i','1','p');
2043 }
2044 } else if (track->par->width == 1920 && track->par->height == 1080) {
2045 if (!interlaced) {
2046 if (rate == 24) tag = MKTAG('a','i','1','3');
2047 else if (rate == 25) tag = MKTAG('a','i','1','2');
2048 else if (rate == 30) tag = MKTAG('a','i','1','3');
2049 } else {
2050 if (rate == 25) tag = MKTAG('a','i','1','5');
2051 else if (rate == 50) tag = MKTAG('a','i','1','5');
2052 else if (rate == 60) tag = MKTAG('a','i','1','6');
2053 }
2054 } else if ( track->par->width == 4096 && track->par->height == 2160
2055 || track->par->width == 3840 && track->par->height == 2160
2056 || track->par->width == 2048 && track->par->height == 1080) {
2057 tag = MKTAG('a','i','v','x');
2058 }
2059 }
2060
2061 return tag;
2062 }
2063
2064 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
2065 {
2066 int tag = track->par->codec_tag;
2067
2068 if (!tag)
2069 tag = MKTAG('e', 'v', 'c', '1');
2070
2071 return tag;
2072 }
2073
2074 static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
2075 {
2076 int tag = track->par->codec_tag;
2077
2078 if (!tag)
2079 tag = MKTAG('a', 'p', 'v', '1');
2080
2081 return tag;
2082 }
2083
2084
2085 static const struct {
2086 enum AVPixelFormat pix_fmt;
2087 uint32_t tag;
2088 unsigned bps;
2089 } mov_pix_fmt_tags[] = {
2090 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
2091 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2092 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2093 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2094 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2095 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2096 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2097 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2098 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2099 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2100 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2101 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2102 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2103 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2104 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2105 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2106 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2107 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2108 };
2109
2110 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2111 {
2112 23 int tag = MKTAG('A','V','d','n');
2113
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2114
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2115 12 tag = MKTAG('A','V','d','h');
2116 23 return tag;
2117 }
2118
2119 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2120 {
2121 17 int tag = track->par->codec_tag;
2122 int i;
2123 enum AVPixelFormat pix_fmt;
2124
2125
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 12 times.
264 for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
2126
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2127 17 tag = mov_pix_fmt_tags[i].tag;
2128 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2129
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2130 5 break;
2131 }
2132 }
2133
2134 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2135 17 track->par->bits_per_coded_sample);
2136
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2138 track->par->format != AV_PIX_FMT_GRAY8 &&
2139 track->par->format != AV_PIX_FMT_NONE)
2140 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2141 av_get_pix_fmt_name(track->par->format));
2142 17 return tag;
2143 }
2144
2145 170 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2146 {
2147 170 unsigned int tag = track->par->codec_tag;
2148
2149 // "rtp " is used to distinguish internally created RTP-hint tracks
2150 // (with rtp_ctx) from other tracks.
2151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (tag == MKTAG('r','t','p',' '))
2152 tag = 0;
2153
3/4
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 36 times.
170 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
2154
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2155
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 17 times.
133 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2156
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 track->par->codec_id == AV_CODEC_ID_H263 ||
2157
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 2 times.
116 track->par->codec_id == AV_CODEC_ID_H264 ||
2158
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 23 times.
114 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2159
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 72 times.
181 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
2160 90 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2161
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2162 1 tag = mov_get_dv_codec_tag(s, track);
2163
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2164 17 tag = mov_get_rawvideo_codec_tag(s, track);
2165
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2166 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2167
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2168 2 tag = mov_get_h264_codec_tag(s, track);
2169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2170 tag = mov_get_evc_codec_tag(s, track);
2171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2172 tag = mov_get_apv_codec_tag(s, track);
2173
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2174 23 tag = mov_get_dnxhd_codec_tag(s, track);
2175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2176 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2177 if (!tag) { // if no mac fcc found, try with Microsoft tags
2178 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2179 if (tag)
2180 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2181 "the file may be unplayable!\n");
2182 }
2183
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2184 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2186 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2187 if (ms_tag) {
2188 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2189 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2190 "the file may be unplayable!\n");
2191 }
2192 }
2193 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2194 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2195 }
2196
2197 170 return tag;
2198 }
2199
2200 static const AVCodecTag codec_cover_image_tags[] = {
2201 { AV_CODEC_ID_MJPEG, 0xD },
2202 { AV_CODEC_ID_PNG, 0xE },
2203 { AV_CODEC_ID_BMP, 0x1B },
2204 { AV_CODEC_ID_NONE, 0 },
2205 };
2206
2207 132 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2208 unsigned int tag, int codec_id)
2209 {
2210 int i;
2211
2212 /**
2213 * Check that tag + id is in the table
2214 */
2215
2/4
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
132 for (i = 0; tags && tags[i]; i++) {
2216 132 const AVCodecTag *codec_tags = tags[i];
2217
1/2
✓ Branch 0 taken 2064 times.
✗ Branch 1 not taken.
2064 while (codec_tags->id != AV_CODEC_ID_NONE) {
2218
2/2
✓ Branch 2 taken 154 times.
✓ Branch 3 taken 1910 times.
2064 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2219
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 22 times.
154 codec_tags->id == codec_id)
2220 132 return codec_tags->tag;
2221 1932 codec_tags++;
2222 }
2223 }
2224 return 0;
2225 }
2226
2227 304 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2228 {
2229
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 302 times.
304 if (is_cover_image(track->st))
2230 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2231
2232
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 301 times.
302 if (track->mode == MODE_IPOD)
2233
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 if (!av_match_ext(s->url, "m4a") &&
2234
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2235 1 !av_match_ext(s->url, "m4b"))
2236 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2237 "Quicktime/Ipod might not play the file\n");
2238
2239
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 132 times.
302 if (track->mode == MODE_MOV) {
2240 170 return mov_get_codec_tag(s, track);
2241 } else
2242 132 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2243 132 track->par->codec_id);
2244 }
2245
2246 /** Write uuid atom.
2247 * Needed to make file play in iPods running newest firmware
2248 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2249 */
2250 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2251 {
2252 avio_wb32(pb, 28);
2253 ffio_wfourcc(pb, "uuid");
2254 avio_wb32(pb, 0x6b6840f2);
2255 avio_wb32(pb, 0x5f244fc5);
2256 avio_wb32(pb, 0xba39a51b);
2257 avio_wb32(pb, 0xcf0323f3);
2258 avio_wb32(pb, 0x0);
2259 return 28;
2260 }
2261
2262 static const uint16_t fiel_data[] = {
2263 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2264 };
2265
2266 101 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2267 {
2268 101 unsigned mov_field_order = 0;
2269
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2270 101 mov_field_order = fiel_data[field_order];
2271 else
2272 return 0;
2273 101 avio_wb32(pb, 10);
2274 101 ffio_wfourcc(pb, "fiel");
2275 101 avio_wb16(pb, mov_field_order);
2276 101 return 10;
2277 }
2278
2279 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2280 {
2281 6 MOVMuxContext *mov = s->priv_data;
2282 6 int ret = AVERROR_BUG;
2283 6 int64_t pos = avio_tell(pb);
2284 6 avio_wb32(pb, 0); /* size */
2285 6 avio_wl32(pb, track->tag); // store it byteswapped
2286 6 avio_wb32(pb, 0); /* Reserved */
2287 6 avio_wb16(pb, 0); /* Reserved */
2288 6 avio_wb16(pb, 1); /* Data-reference index */
2289
2290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2291 mov_write_esds_tag(pb, track);
2292
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2293
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2294 2 case MOV_ISMV_TTML_TAG:
2295 // ISMV dfxp requires no extradata.
2296 4 break;
2297 2 case MOV_MP4_TTML_TAG:
2298 // As specified in 14496-30, XMLSubtitleSampleEntry
2299 // Namespace
2300 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2301 // Empty schema_location
2302 2 avio_w8(pb, 0);
2303 // Empty auxiliary_mime_types
2304 2 avio_w8(pb, 0);
2305 2 break;
2306 default:
2307 av_log(NULL, AV_LOG_ERROR,
2308 "Unknown codec tag '%s' utilized for TTML stream with "
2309 "index %d (track id %d)!\n",
2310 av_fourcc2str(track->par->codec_tag), track->st->index,
2311 track->track_id);
2312 return AVERROR(EINVAL);
2313 }
2314
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2315 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2316
2317
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
11 if (mov->write_btrt &&
2318 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2319 return ret;
2320
2321 6 return update_size(pb, pos);
2322 }
2323
2324 1 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2325 {
2326 int8_t stereo_mode;
2327
2328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo_3d->flags != 0) {
2329 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2330 return 0;
2331 }
2332
2333
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo_3d->type) {
2334 case AV_STEREO3D_2D:
2335 stereo_mode = 0;
2336 break;
2337 case AV_STEREO3D_TOPBOTTOM:
2338 stereo_mode = 1;
2339 break;
2340 1 case AV_STEREO3D_SIDEBYSIDE:
2341 1 stereo_mode = 2;
2342 1 break;
2343 default:
2344 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2345 return 0;
2346 }
2347 1 avio_wb32(pb, 13); /* size */
2348 1 ffio_wfourcc(pb, "st3d");
2349 1 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2350 1 avio_w8(pb, stereo_mode);
2351 1 return 13;
2352 }
2353
2354 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2355 {
2356 int64_t sv3d_pos, svhd_pos, proj_pos;
2357 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2358
2359 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2360 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2361 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2362 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2363 return 0;
2364 }
2365
2366 sv3d_pos = avio_tell(pb);
2367 avio_wb32(pb, 0); /* size */
2368 ffio_wfourcc(pb, "sv3d");
2369
2370 svhd_pos = avio_tell(pb);
2371 avio_wb32(pb, 0); /* size */
2372 ffio_wfourcc(pb, "svhd");
2373 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2374 avio_put_str(pb, metadata_source);
2375 update_size(pb, svhd_pos);
2376
2377 proj_pos = avio_tell(pb);
2378 avio_wb32(pb, 0); /* size */
2379 ffio_wfourcc(pb, "proj");
2380
2381 avio_wb32(pb, 24); /* size */
2382 ffio_wfourcc(pb, "prhd");
2383 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2384 avio_wb32(pb, spherical_mapping->yaw);
2385 avio_wb32(pb, spherical_mapping->pitch);
2386 avio_wb32(pb, spherical_mapping->roll);
2387
2388 switch (spherical_mapping->projection) {
2389 case AV_SPHERICAL_EQUIRECTANGULAR:
2390 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2391 avio_wb32(pb, 28); /* size */
2392 ffio_wfourcc(pb, "equi");
2393 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2394 avio_wb32(pb, spherical_mapping->bound_top);
2395 avio_wb32(pb, spherical_mapping->bound_bottom);
2396 avio_wb32(pb, spherical_mapping->bound_left);
2397 avio_wb32(pb, spherical_mapping->bound_right);
2398 break;
2399 case AV_SPHERICAL_CUBEMAP:
2400 avio_wb32(pb, 20); /* size */
2401 ffio_wfourcc(pb, "cbmp");
2402 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2403 avio_wb32(pb, 0); /* layout */
2404 avio_wb32(pb, spherical_mapping->padding); /* padding */
2405 break;
2406 }
2407 update_size(pb, proj_pos);
2408
2409 return update_size(pb, sv3d_pos);
2410 }
2411
2412 5 static inline int64_t rescale_rational(AVRational q, int b)
2413 {
2414 5 return av_rescale(q.num, b, q.den);
2415 }
2416
2417 2 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2418 const AVStereo3D *stereo3d)
2419 {
2420
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!stereo3d->horizontal_field_of_view.num)
2421 1 return;
2422
2423 1 avio_wb32(pb, 12); /* size */
2424 1 ffio_wfourcc(pb, "hfov");
2425 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2426 }
2427
2428 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2429 const AVSphericalMapping *spherical_mapping)
2430 {
2431 1 avio_wb32(pb, 24); /* size */
2432 1 ffio_wfourcc(pb, "proj");
2433 1 avio_wb32(pb, 16); /* size */
2434 1 ffio_wfourcc(pb, "prji");
2435 1 avio_wb32(pb, 0); /* version + flags */
2436
2437
1/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (spherical_mapping->projection) {
2438 1 case AV_SPHERICAL_RECTILINEAR:
2439 1 ffio_wfourcc(pb, "rect");
2440 1 break;
2441 case AV_SPHERICAL_EQUIRECTANGULAR:
2442 ffio_wfourcc(pb, "equi");
2443 break;
2444 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2445 ffio_wfourcc(pb, "hequ");
2446 break;
2447 case AV_SPHERICAL_FISHEYE:
2448 ffio_wfourcc(pb, "fish");
2449 break;
2450 default:
2451 av_assert0(0);
2452 }
2453 1 }
2454
2455 2 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2456 const AVStereo3D *stereo3d)
2457 {
2458 2 int64_t pos = avio_tell(pb);
2459 2 int view = 0;
2460
2461 2 avio_wb32(pb, 0); /* size */
2462 2 ffio_wfourcc(pb, "eyes");
2463
2464 // stri is mandatory
2465 2 avio_wb32(pb, 13); /* size */
2466 2 ffio_wfourcc(pb, "stri");
2467 2 avio_wb32(pb, 0); /* version + flags */
2468
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 switch (stereo3d->view) {
2469 case AV_STEREO3D_VIEW_LEFT:
2470 view |= 1 << 0;
2471 break;
2472 case AV_STEREO3D_VIEW_RIGHT:
2473 view |= 1 << 1;
2474 break;
2475 2 case AV_STEREO3D_VIEW_PACKED:
2476 2 view |= (1 << 0) | (1 << 1);
2477 2 break;
2478 }
2479 2 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2480 2 avio_w8(pb, view);
2481
2482 // hero is optional
2483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2484 avio_wb32(pb, 13); /* size */
2485 ffio_wfourcc(pb, "hero");
2486 avio_wb32(pb, 0); /* version + flags */
2487 avio_w8(pb, stereo3d->primary_eye);
2488 }
2489
2490 // it's not clear if cams is mandatory or optional
2491
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->baseline) {
2492 1 avio_wb32(pb, 24); /* size */
2493 1 ffio_wfourcc(pb, "cams");
2494 1 avio_wb32(pb, 16); /* size */
2495 1 ffio_wfourcc(pb, "blin");
2496 1 avio_wb32(pb, 0); /* version + flags */
2497 1 avio_wb32(pb, stereo3d->baseline);
2498 }
2499
2500 // it's not clear if cmfy is mandatory or optional
2501
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->horizontal_disparity_adjustment.num) {
2502 1 avio_wb32(pb, 24); /* size */
2503 1 ffio_wfourcc(pb, "cmfy");
2504 1 avio_wb32(pb, 16); /* size */
2505 1 ffio_wfourcc(pb, "dadj");
2506 1 avio_wb32(pb, 0); /* version + flags */
2507 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2508 }
2509
2510 2 return update_size(pb, pos);
2511 }
2512
2513 2 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2514 const AVStereo3D *stereo3d,
2515 const AVSphericalMapping *spherical_mapping)
2516 {
2517 int64_t pos;
2518
2519
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping &&
2520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2521 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2522 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2523 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2524 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2525 spherical_mapping->projection);
2526 spherical_mapping = NULL;
2527 }
2528
2529
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2530
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2532 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2533 !stereo3d->baseline &&
2534 !stereo3d->horizontal_disparity_adjustment.num))) {
2535 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2536 stereo3d = NULL;
2537 }
2538
2539
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (!spherical_mapping && !stereo3d)
2540 return 0;
2541
2542 2 pos = avio_tell(pb);
2543 2 avio_wb32(pb, 0); /* size */
2544 2 ffio_wfourcc(pb, "vexu");
2545
2546
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping)
2547 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2548
2549
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (stereo3d)
2550 2 mov_write_eyes_tag(s, pb, stereo3d);
2551
2552 2 return update_size(pb, pos);
2553 }
2554
2555 2 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2556 {
2557 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2558
2559 2 avio_wb32(pb, 32); /* size = 8 + 24 */
2560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (dovi->dv_profile > 10)
2561 ffio_wfourcc(pb, "dvwC");
2562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (dovi->dv_profile > 7)
2563 ffio_wfourcc(pb, "dvvC");
2564 else
2565 2 ffio_wfourcc(pb, "dvcC");
2566
2567 2 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2568 2 avio_write(pb, buf, sizeof(buf));
2569
2570 2 return 32; /* 8 + 24 */
2571 }
2572
2573 2 static int mov_write_hvce_tag(AVIOContext *pb, const AVPacketSideData *sd)
2574 {
2575 2 avio_wb32(pb, 8 + sd->size);
2576 2 ffio_wfourcc(pb, "hvcE");
2577 2 avio_write(pb, sd->data, sd->size);
2578 2 return 8 + sd->size;
2579 }
2580
2581 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2582 uint32_t top, uint32_t bottom,
2583 uint32_t left, uint32_t right)
2584 {
2585 5 uint32_t cropped_width = track->par->width - left - right;
2586 5 uint32_t cropped_height = track->height - top - bottom;
2587 AVRational horizOff =
2588 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2589 5 (AVRational) { left, 1 });
2590 AVRational vertOff =
2591 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2592 5 (AVRational) { top, 1 });
2593
2594 5 avio_wb32(pb, 40);
2595 5 ffio_wfourcc(pb, "clap");
2596 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2597 5 avio_wb32(pb, 1); /* apertureWidthD */
2598 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2599 5 avio_wb32(pb, 1); /* apertureHeightD */
2600
2601 5 avio_wb32(pb, -horizOff.num);
2602 5 avio_wb32(pb, horizOff.den);
2603 5 avio_wb32(pb, -vertOff.num);
2604 5 avio_wb32(pb, vertOff.den);
2605
2606 5 return 40;
2607 }
2608
2609 26 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2610 {
2611 AVRational sar;
2612 26 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2613 26 track->par->sample_aspect_ratio.den, INT_MAX);
2614
2615 26 avio_wb32(pb, 16);
2616 26 ffio_wfourcc(pb, "pasp");
2617 26 avio_wb32(pb, sar.num);
2618 26 avio_wb32(pb, sar.den);
2619 26 return 16;
2620 }
2621
2622 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2623 {
2624 uint32_t gama = 0;
2625 if (gamma <= 0.0)
2626 gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2627 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2628
2629 if (gamma > 1e-6) {
2630 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2631 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2632
2633 av_assert0(track->mode == MODE_MOV);
2634 avio_wb32(pb, 12);
2635 ffio_wfourcc(pb, "gama");
2636 avio_wb32(pb, gama);
2637 return 12;
2638 } else {
2639 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2640 }
2641 return 0;
2642 }
2643
2644 12 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2645 {
2646 12 int64_t pos = avio_tell(pb);
2647
2648 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2649 // Ref (MP4): ISO/IEC 14496-12:2012
2650
2651
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (prefer_icc) {
2652 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2653 4 track->st->codecpar->nb_coded_side_data,
2654 AV_PKT_DATA_ICC_PROFILE);
2655
2656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2657 avio_wb32(pb, 12 + sd->size);
2658 ffio_wfourcc(pb, "colr");
2659 ffio_wfourcc(pb, "prof");
2660 avio_write(pb, sd->data, sd->size);
2661 return 12 + sd->size;
2662 }
2663 else {
2664 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2665 }
2666 }
2667
2668 /* We should only ever be called for MOV, MP4 and AVIF. */
2669
3/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
12 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2670 track->mode == MODE_AVIF);
2671
2672 12 avio_wb32(pb, 0); /* size */
2673 12 ffio_wfourcc(pb, "colr");
2674
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2675 4 ffio_wfourcc(pb, "nclx");
2676 else
2677 8 ffio_wfourcc(pb, "nclc");
2678 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2679 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2680 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2681 12 avio_wb16(pb, track->par->color_primaries);
2682 12 avio_wb16(pb, track->par->color_trc);
2683 12 avio_wb16(pb, track->par->color_space);
2684
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2685 4 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2686 4 avio_w8(pb, full_range << 7);
2687 }
2688
2689 12 return update_size(pb, pos);
2690 }
2691
2692 228 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2693 {
2694 const AVPacketSideData *side_data;
2695 const AVContentLightMetadata *content_light_metadata;
2696
2697 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2698 228 track->st->codecpar->nb_coded_side_data,
2699 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2700
1/2
✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
228 if (!side_data) {
2701 228 return 0;
2702 }
2703 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2704
2705 avio_wb32(pb, 12); // size
2706 ffio_wfourcc(pb, "clli");
2707 avio_wb16(pb, content_light_metadata->MaxCLL);
2708 avio_wb16(pb, content_light_metadata->MaxFALL);
2709 return 12;
2710 }
2711
2712 228 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2713 {
2714 228 const int chroma_den = 50000;
2715 228 const int luma_den = 10000;
2716 const AVPacketSideData *side_data;
2717 228 const AVMasteringDisplayMetadata *metadata = NULL;
2718
2719 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2720 228 track->st->codecpar->nb_coded_side_data,
2721 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 228 times.
228 if (side_data)
2723 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2724
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
228 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2725 228 return 0;
2726 }
2727
2728 avio_wb32(pb, 32); // size
2729 ffio_wfourcc(pb, "mdcv");
2730 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2731 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2732 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2733 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2734 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2735 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2736 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2737 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2738 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2739 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2740 return 32;
2741 }
2742
2743 228 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2744 {
2745 228 const int illuminance_den = 10000;
2746 228 const int ambient_den = 50000;
2747 const AVPacketSideData *side_data;
2748 const AVAmbientViewingEnvironment *ambient;
2749
2750
2751 228 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2752 228 track->st->codecpar->nb_coded_side_data,
2753 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2754
2755
2/2
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 1 times.
228 if (!side_data)
2756 227 return 0;
2757
2758 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2759
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ambient || !ambient->ambient_illuminance.num)
2760 return 0;
2761
2762 1 avio_wb32(pb, 16); // size
2763 1 ffio_wfourcc(pb, "amve");
2764 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2765 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2766 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2767 1 return 16;
2768 }
2769
2770 234 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2771 {
2772 AVDictionaryEntry *encoder;
2773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2774
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
233 || (track->par->width == 1440 && track->par->height == 1080)
2775
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
468 || (track->par->width == 1920 && track->par->height == 1080);
2776
2777
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if ((track->mode == MODE_AVIF ||
2778
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
234 track->mode == MODE_MOV ||
2779
4/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 69 times.
318 track->mode == MODE_MP4) &&
2780 228 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2781 159 av_strlcpy(compressor_name, encoder->value, 32);
2782
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
75 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2783 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2784 AVStream *st = track->st;
2785 int rate = defined_frame_rate(NULL, st);
2786 av_strlcatf(compressor_name, len, "XDCAM");
2787 if (track->par->format == AV_PIX_FMT_YUV422P) {
2788 av_strlcatf(compressor_name, len, " HD422");
2789 } else if(track->par->width == 1440) {
2790 av_strlcatf(compressor_name, len, " HD");
2791 } else
2792 av_strlcatf(compressor_name, len, " EX");
2793
2794 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2795
2796 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2797 }
2798 234 }
2799
2800 static int mov_write_ccst_tag(AVIOContext *pb)
2801 {
2802 int64_t pos = avio_tell(pb);
2803 // Write sane defaults:
2804 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2805 // intra_pred_used = 1 : intra prediction may or may not be used.
2806 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2807 // reference images can be used.
2808 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2809 (1 << 6) | /* intra_pred_used */
2810 (15 << 2); /* max_ref_per_pic */
2811 avio_wb32(pb, 0); /* size */
2812 ffio_wfourcc(pb, "ccst");
2813 avio_wb32(pb, 0); /* Version & flags */
2814 avio_w8(pb, ccstValue);
2815 avio_wb24(pb, 0); /* reserved */
2816 return update_size(pb, pos);
2817 }
2818
2819 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2820 {
2821 int64_t pos = avio_tell(pb);
2822 avio_wb32(pb, 0); /* size */
2823 ffio_wfourcc(pb, aux_type);
2824 avio_wb32(pb, 0); /* Version & flags */
2825 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2826 return update_size(pb, pos);
2827 }
2828
2829 234 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2830 {
2831 234 int ret = AVERROR_BUG;
2832 234 int64_t pos = avio_tell(pb);
2833 const AVPacketSideData *sd;
2834 234 char compressor_name[32] = { 0 };
2835 234 int avid = 0;
2836
2837
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422)
2838
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2839
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2840
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2841
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
234 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2842
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 217 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 230 times.
468 || track->par->codec_id == AV_CODEC_ID_V210);
2843
2844 234 avio_wb32(pb, 0); /* size */
2845
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 228 times.
234 if (mov->encryption_scheme != MOV_ENC_NONE) {
2846 6 ffio_wfourcc(pb, "encv");
2847 } else {
2848 228 avio_wl32(pb, track->tag); // store it byteswapped
2849 }
2850 234 avio_wb32(pb, 0); /* Reserved */
2851 234 avio_wb16(pb, 0); /* Reserved */
2852 234 avio_wb16(pb, 1); /* Data-reference index */
2853
2854
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 230 times.
234 if (uncompressed_ycbcr) {
2855 4 avio_wb16(pb, 2); /* Codec stream version */
2856 } else {
2857 230 avio_wb16(pb, 0); /* Codec stream version */
2858 }
2859 234 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2860
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
234 if (track->mode == MODE_MOV) {
2861 144 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2862
3/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 127 times.
144 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2863 17 avio_wb32(pb, 0); /* Temporal Quality */
2864 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2865 } else {
2866 127 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2867 127 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2868 }
2869 } else {
2870 90 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2871 }
2872 234 avio_wb16(pb, track->par->width); /* Video width */
2873 234 avio_wb16(pb, track->height); /* Video height */
2874 234 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2875 234 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2876 234 avio_wb32(pb, 0); /* Data size (= 0) */
2877 234 avio_wb16(pb, 1); /* Frame count (= 1) */
2878
2879 234 find_compressor(compressor_name, 32, track);
2880 234 avio_w8(pb, strlen(compressor_name));
2881 234 avio_write(pb, compressor_name, 31);
2882
2883
3/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
234 if (track->mode == MODE_MOV && track->par->codec_id == AV_CODEC_ID_V210)
2884 avio_wb16(pb, 0x18);
2885
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 111 times.
234 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2886 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2887
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2888 else
2889 201 avio_wb16(pb, 0x18); /* Reserved */
2890
2891
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 139 times.
239 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2892 int pal_size, i;
2893 5 avio_wb16(pb, 0); /* Color table ID */
2894 5 avio_wb32(pb, 0); /* Color table seed */
2895 5 avio_wb16(pb, 0x8000); /* Color table flags */
2896
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (track->par->bits_per_coded_sample < 0 || track->par->bits_per_coded_sample > 8)
2897 return AVERROR(EINVAL);
2898 5 pal_size = 1 << track->par->bits_per_coded_sample;
2899 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2900
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2901 1040 uint32_t rgb = track->palette[i];
2902 1040 uint16_t r = (rgb >> 16) & 0xff;
2903 1040 uint16_t g = (rgb >> 8) & 0xff;
2904 1040 uint16_t b = rgb & 0xff;
2905 1040 avio_wb16(pb, 0);
2906 1040 avio_wb16(pb, (r << 8) | r);
2907 1040 avio_wb16(pb, (g << 8) | g);
2908 1040 avio_wb16(pb, (b << 8) | b);
2909 }
2910 } else
2911 229 avio_wb16(pb, 0xffff); /* Reserved */
2912
2913
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 198 times.
234 if (track->tag == MKTAG('m','p','4','v'))
2914 36 mov_write_esds_tag(pb, track);
2915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 else if (track->par->codec_id == AV_CODEC_ID_H263)
2916 mov_write_d263_tag(pb);
2917
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 3 times.
198 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2919 3 mov_write_extradata_tag(pb, track);
2920 3 avio_wb32(pb, 0);
2921
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 172 times.
195 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2922 23 mov_write_avid_tag(pb, track);
2923 23 avid = 1;
2924
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 161 times.
172 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2925 11 mov_write_hvcc_tag(mov->fc, pb, track);
2926
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2927 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2929 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2930 }
2931
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160 times.
161 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2932 1 mov_write_vvcc_tag(pb, track);
2933
16/30
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 101 times.
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 59 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 59 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 59 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 59 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 59 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 59 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 59 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 59 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 59 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 59 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 59 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 59 times.
✗ Branch 29 not taken.
160 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2934 59 mov_write_avcc_tag(pb, track);
2935
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 if (track->mode == MODE_IPOD)
2936 mov_write_uuid_tag_ipod(pb);
2937 }
2938
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2939 1 mov_write_evcc_tag(pb, track);
2940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 } else if (track->par->codec_id == AV_CODEC_ID_LCEVC) {
2941 mov_write_lvcc_tag(mov->fc, pb, track);
2942
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2943 1 mov_write_apvc_tag(mov->fc, pb, track);
2944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2945 mov_write_vpcc_tag(mov->fc, pb, track);
2946
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 97 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2947 2 mov_write_av1c_tag(pb, track);
2948
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
97 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->extradata_size[track->last_stsd_index] > 0)
2949 mov_write_dvc1_tag(pb, track);
2950
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2951
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2952 /* Don't write any potential extradata here - the cropping
2953 * is signalled via the normal width/height fields. */
2954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2955 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2956 mov_write_dpxe_tag(pb, track);
2957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2958 mov_write_av3c_tag(pb, track);
2959
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
2960 4 mov_write_glbl_tag(pb, track);
2961
2962
2/2
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 59 times.
234 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2963
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2964
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 23 times.
145 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2965 122 int field_order = track->par->field_order;
2966
2967
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 21 times.
122 if (field_order != AV_FIELD_UNKNOWN)
2968 101 mov_write_fiel_tag(pb, track, field_order);
2969 }
2970
2971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2972 if (track->mode == MODE_MOV)
2973 mov_write_gama_tag(s, pb, track, mov->gamma);
2974 else
2975 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2976 }
2977
5/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 84 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
462 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2978 464 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2979
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
236 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2980
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2981
5/6
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 216 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 216 times.
444 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2982 216 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2983 AV_PKT_DATA_ICC_PROFILE)) {
2984
3/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
12 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2985 12 mov_write_colr_tag(pb, track, prefer_icc);
2986 }
2987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2988 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2989 }
2990
2991
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 6 times.
234 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2992 228 mov_write_clli_tag(pb, track);
2993 228 mov_write_mdcv_tag(pb, track);
2994 228 mov_write_amve_tag(pb, track);
2995 }
2996
2997
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
234 if (track->mode == MODE_MP4) {
2998 84 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2999 84 track->st->codecpar->nb_coded_side_data,
3000 AV_PKT_DATA_STEREO3D);
3001 84 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3002 84 track->st->codecpar->nb_coded_side_data,
3003 AV_PKT_DATA_SPHERICAL);
3004
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
84 if (stereo_3d && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3005 1 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
3006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 else if (stereo_3d)
3007 av_log(s, AV_LOG_WARNING, "Writing supported 'st3d' metadata requires -strict unofficial.\n");
3008
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
84 if (spherical_mapping && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3009 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
3010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 else if (spherical_mapping)
3011 av_log(s, AV_LOG_WARNING, "Writing supported 'sv3d' metadata requires -strict unofficial.\n");
3012 }
3013
3014
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 6 times.
234 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
3015
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 81 times.
84 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
3016 147 const AVStereo3D *stereo3d = NULL;
3017 147 const AVSphericalMapping *spherical_mapping = NULL;
3018
3019 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3020 147 track->st->codecpar->nb_coded_side_data,
3021 AV_PKT_DATA_STEREO3D);
3022
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (sd)
3023 2 stereo3d = (AVStereo3D *)sd->data;
3024
3025 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3026 147 track->st->codecpar->nb_coded_side_data,
3027 AV_PKT_DATA_SPHERICAL);
3028
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 146 times.
147 if (sd)
3029 1 spherical_mapping = (AVSphericalMapping *)sd->data;
3030
3031
3/4
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 145 times.
147 if (stereo3d || spherical_mapping)
3032 2 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
3033
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (stereo3d)
3034 2 mov_write_hfov_tag(s, pb, stereo3d);
3035 }
3036
3037
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
234 if (track->mode == MODE_MP4) {
3038 84 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3039 84 track->st->codecpar->nb_coded_side_data,
3040 AV_PKT_DATA_DOVI_CONF);
3041
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
84 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3042 2 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
3043
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (dovi) {
3044 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
3045 }
3046
3047 84 const AVPacketSideData *hvce = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3048 84 track->st->codecpar->nb_coded_side_data,
3049 AV_PKT_DATA_HEVC_CONF);
3050
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
84 if (hvce && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3051 2 mov_write_hvce_tag(pb, hvce);
3052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (hvce) {
3053 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'hvcE' box. Requires -strict unofficial.\n");
3054 }
3055 }
3056
3057
3/4
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 208 times.
234 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
3058 26 mov_write_pasp_tag(pb, track);
3059 }
3060
3061 234 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3062 234 track->st->codecpar->nb_coded_side_data,
3063 AV_PKT_DATA_FRAME_CROPPING);
3064
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
235 if (sd && sd->size >= sizeof(uint32_t) * 4) {
3065 1 uint64_t top = AV_RL32(sd->data + 0);
3066 1 uint64_t bottom = AV_RL32(sd->data + 4);
3067 1 uint64_t left = AV_RL32(sd->data + 8);
3068 1 uint64_t right = AV_RL32(sd->data + 12);
3069
3070
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
3071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
3072 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
3073 return AVERROR(EINVAL);
3074 }
3075
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (top || bottom || left || right)
3076 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
3077
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 229 times.
233 } else if (uncompressed_ycbcr)
3078 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
3079
3080
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 228 times.
234 if (mov->encryption_scheme != MOV_ENC_NONE) {
3081 6 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
3082 }
3083
3084
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
318 if (mov->write_btrt &&
3085 84 ((ret = mov_write_btrt_tag(pb, track)) < 0))
3086 return ret;
3087
3088 /* extra padding for avid stsd */
3089 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3090
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 211 times.
234 if (avid)
3091 23 avio_wb32(pb, 0);
3092
3093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (track->mode == MODE_AVIF) {
3094 mov_write_ccst_tag(pb);
3095 if (mov->nb_streams > 0 && track == &mov->tracks[1])
3096 mov_write_aux_tag(pb, "auxi");
3097 }
3098
3099 234 return update_size(pb, pos);
3100 }
3101
3102 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
3103 {
3104 2 int64_t pos = avio_tell(pb);
3105 2 avio_wb32(pb, 0); /* size */
3106 2 ffio_wfourcc(pb, "rtp ");
3107 2 avio_wb32(pb, 0); /* Reserved */
3108 2 avio_wb16(pb, 0); /* Reserved */
3109 2 avio_wb16(pb, 1); /* Data-reference index */
3110
3111 2 avio_wb16(pb, 1); /* Hint track version */
3112 2 avio_wb16(pb, 1); /* Highest compatible version */
3113 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3114
3115 2 avio_wb32(pb, 12); /* size */
3116 2 ffio_wfourcc(pb, "tims");
3117 2 avio_wb32(pb, track->timescale);
3118
3119 2 return update_size(pb, pos);
3120 }
3121
3122 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3123 {
3124 2 uint64_t str_size =strlen(reel_name);
3125 2 int64_t pos = avio_tell(pb);
3126
3127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3128 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3129 avio_wb16(pb, 0);
3130 return AVERROR(EINVAL);
3131 }
3132
3133 2 avio_wb32(pb, 0); /* size */
3134 2 ffio_wfourcc(pb, "name"); /* Data format */
3135 2 avio_wb16(pb, str_size); /* string size */
3136 2 avio_wb16(pb, track->language); /* langcode */
3137 2 avio_write(pb, reel_name, str_size); /* reel name */
3138 2 return update_size(pb,pos);
3139 }
3140
3141 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3142 {
3143 13 int64_t pos = avio_tell(pb);
3144 #if 1
3145 int frame_duration;
3146 int nb_frames;
3147 13 AVDictionaryEntry *t = NULL;
3148
3149
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 if (!track->st->avg_frame_rate.num || !track->st->avg_frame_rate.den) {
3150 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3151 return AVERROR(EINVAL);
3152 } else {
3153 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3154
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 nb_frames = ROUNDED_DIV(track->st->avg_frame_rate.num, track->st->avg_frame_rate.den);
3155 }
3156
3157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3158 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3159 return AVERROR(EINVAL);
3160 }
3161
3162 13 avio_wb32(pb, 0); /* size */
3163 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3164 13 avio_wb32(pb, 0); /* Reserved */
3165 13 avio_wb32(pb, 1); /* Data reference index */
3166 13 avio_wb32(pb, 0); /* Flags */
3167 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3168 13 avio_wb32(pb, track->timescale); /* Timescale */
3169 13 avio_wb32(pb, frame_duration); /* Frame duration */
3170 13 avio_w8(pb, nb_frames); /* Number of frames */
3171 13 avio_w8(pb, 0); /* Reserved */
3172
3173 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3174
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
13 if (t && utf8len(t->value) && track->mode != MODE_MP4)
3175 2 mov_write_source_reference_tag(pb, track, t->value);
3176 else
3177 11 avio_wb16(pb, 0); /* zero size */
3178 #else
3179
3180 avio_wb32(pb, 0); /* size */
3181 ffio_wfourcc(pb, "tmcd"); /* Data format */
3182 avio_wb32(pb, 0); /* Reserved */
3183 avio_wb32(pb, 1); /* Data reference index */
3184 if (track->par->extradata_size)
3185 avio_write(pb, track->par->extradata, track->par->extradata_size);
3186 #endif
3187 13 return update_size(pb, pos);
3188 }
3189
3190 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3191 {
3192 1 int64_t pos = avio_tell(pb);
3193 1 avio_wb32(pb, 0); /* size */
3194 1 ffio_wfourcc(pb, "gpmd");
3195 1 avio_wb32(pb, 0); /* Reserved */
3196 1 avio_wb16(pb, 0); /* Reserved */
3197 1 avio_wb16(pb, 1); /* Data-reference index */
3198 1 avio_wb32(pb, 0); /* Reserved */
3199 1 return update_size(pb, pos);
3200 }
3201
3202 382 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3203 {
3204 382 int64_t pos = avio_tell(pb);
3205 382 int ret = 0;
3206 382 avio_wb32(pb, 0); /* size */
3207 382 ffio_wfourcc(pb, "stsd");
3208 382 avio_wb32(pb, 0); /* version & flags */
3209 382 avio_wb32(pb, track->stsd_count);
3210
3211 382 int stsd_index_back = track->last_stsd_index;
3212 382 for (track->last_stsd_index = 0;
3213
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 382 times.
766 track->last_stsd_index < track->stsd_count;
3214 384 track->last_stsd_index++) {
3215
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 150 times.
384 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3216 234 ret = mov_write_video_tag(s, pb, mov, track);
3217
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 22 times.
150 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3218 128 ret = mov_write_audio_tag(s, pb, mov, track);
3219
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3220 6 ret = mov_write_subtitle_tag(s, pb, track);
3221
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3222 2 ret = mov_write_rtp_tag(pb, track);
3223
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3224 13 ret = mov_write_tmcd_tag(pb, track);
3225
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3226 1 ret = mov_write_gpmd_tag(pb, track);
3227
3228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 384 times.
384 if (ret < 0)
3229 return ret;
3230 }
3231
3232 382 track->last_stsd_index = stsd_index_back;
3233
3234 382 return update_size_and_version(pb, pos, track->entry_version);
3235 }
3236
3237 15 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3238 {
3239 15 MOVMuxContext *mov = s->priv_data;
3240 MOVCtts *ctts_entries;
3241 15 uint32_t entries = 0;
3242 uint32_t atom_size;
3243 int i;
3244
3245 15 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!ctts_entries)
3247 return AVERROR(ENOMEM);
3248 15 ctts_entries[0].count = 1;
3249 15 ctts_entries[0].offset = track->cluster[0].cts;
3250
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 15 times.
775 for (i = 1; i < track->entry; i++) {
3251
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 629 times.
760 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3252 131 ctts_entries[entries].count++; /* compress */
3253 } else {
3254 629 entries++;
3255 629 ctts_entries[entries].offset = track->cluster[i].cts;
3256 629 ctts_entries[entries].count = 1;
3257 }
3258 }
3259 15 entries++; /* last one */
3260 15 atom_size = 16 + (entries * 8);
3261 15 avio_wb32(pb, atom_size); /* size */
3262 15 ffio_wfourcc(pb, "ctts");
3263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3264 avio_w8(pb, 1); /* version */
3265 else
3266 15 avio_w8(pb, 0); /* version */
3267 15 avio_wb24(pb, 0); /* flags */
3268 15 avio_wb32(pb, entries); /* entry count */
3269
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 15 times.
659 for (i = 0; i < entries; i++) {
3270 644 avio_wb32(pb, ctts_entries[i].count);
3271 644 avio_wb32(pb, ctts_entries[i].offset);
3272 }
3273 15 av_free(ctts_entries);
3274 15 return atom_size;
3275 }
3276
3277 /* Time to sample atom */
3278 382 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3279 {
3280 382 MOVStts *stts_entries = NULL;
3281 382 uint32_t entries = -1;
3282 uint32_t atom_size;
3283 int i;
3284
3285
4/4
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 93 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3286 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3288 return AVERROR(ENOMEM);
3289 35 stts_entries[0].count = track->sample_count;
3290 35 stts_entries[0].duration = 1;
3291 35 entries = 1;
3292 } else {
3293
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 106 times.
347 if (track->entry) {
3294 241 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 241 times.
241 if (!stts_entries)
3296 return AVERROR(ENOMEM);
3297 }
3298
2/2
✓ Branch 0 taken 15829 times.
✓ Branch 1 taken 347 times.
16176 for (i = 0; i < track->entry; i++) {
3299 15829 int duration = get_cluster_duration(track, i);
3300 #if CONFIG_IAMFENC
3301
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 15774 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
15829 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3302 duration = av_rescale(duration, 48000, track->par->sample_rate);
3303 #endif
3304
4/4
✓ Branch 0 taken 15588 times.
✓ Branch 1 taken 241 times.
✓ Branch 2 taken 15158 times.
✓ Branch 3 taken 430 times.
15829 if (i && duration == stts_entries[entries].duration) {
3305 15158 stts_entries[entries].count++; /* compress */
3306 } else {
3307 671 entries++;
3308 671 stts_entries[entries].duration = duration;
3309 671 stts_entries[entries].count = 1;
3310 }
3311 }
3312 347 entries++; /* last one */
3313 }
3314 382 atom_size = 16 + (entries * 8);
3315 382 avio_wb32(pb, atom_size); /* size */
3316 382 ffio_wfourcc(pb, "stts");
3317 382 avio_wb32(pb, 0); /* version & flags */
3318 382 avio_wb32(pb, entries); /* entry count */
3319
2/2
✓ Branch 0 taken 706 times.
✓ Branch 1 taken 382 times.
1088 for (i = 0; i < entries; i++) {
3320 706 avio_wb32(pb, stts_entries[i].count);
3321 706 avio_wb32(pb, stts_entries[i].duration);
3322 }
3323 382 av_free(stts_entries);
3324 382 return atom_size;
3325 }
3326
3327 382 static int mov_write_dref_tag(AVIOContext *pb)
3328 {
3329 382 avio_wb32(pb, 28); /* size */
3330 382 ffio_wfourcc(pb, "dref");
3331 382 avio_wb32(pb, 0); /* version & flags */
3332 382 avio_wb32(pb, 1); /* entry count */
3333
3334 382 avio_wb32(pb, 0xc); /* size */
3335 //FIXME add the alis and rsrc atom
3336 382 ffio_wfourcc(pb, "url ");
3337 382 avio_wb32(pb, 1); /* version & flags */
3338
3339 382 return 28;
3340 }
3341
3342 65 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3343 {
3344 struct sgpd_entry {
3345 int count;
3346 int16_t roll_distance;
3347 int group_description_index;
3348 };
3349
3350 65 struct sgpd_entry *sgpd_entries = NULL;
3351 65 int entries = -1;
3352 65 int group = 0;
3353 int i, j;
3354
3355 65 const int OPUS_SEEK_PREROLL_MS = 80;
3356 65 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3357 65 (AVRational){1, 1000},
3358 65 (AVRational){1, 48000});
3359
3360
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 20 times.
65 if (!track->entry)
3361 45 return 0;
3362
3363 20 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!sgpd_entries)
3365 return AVERROR(ENOMEM);
3366
3367
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3368
3369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3370 for (i = 0; i < track->entry; i++) {
3371 int roll_samples_remaining = roll_samples;
3372 int distance = 0;
3373 for (j = i - 1; j >= 0; j--) {
3374 roll_samples_remaining -= get_cluster_duration(track, j);
3375 distance++;
3376 if (roll_samples_remaining <= 0)
3377 break;
3378 }
3379 /* We don't have enough preceding samples to compute a valid
3380 roll_distance here, so this sample can't be independently
3381 decoded. */
3382 if (roll_samples_remaining > 0)
3383 distance = 0;
3384 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3385 if (distance > 32) {
3386 av_freep(&sgpd_entries);
3387 return AVERROR_INVALIDDATA;
3388 }
3389 if (i && distance == sgpd_entries[entries].roll_distance) {
3390 sgpd_entries[entries].count++;
3391 } else {
3392 entries++;
3393 sgpd_entries[entries].count = 1;
3394 sgpd_entries[entries].roll_distance = distance;
3395 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3396 }
3397 }
3398 } else {
3399 20 entries++;
3400 20 sgpd_entries[entries].count = track->sample_count;
3401 20 sgpd_entries[entries].roll_distance = 1;
3402 20 sgpd_entries[entries].group_description_index = ++group;
3403 }
3404 20 entries++;
3405
3406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!group) {
3407 av_free(sgpd_entries);
3408 return 0;
3409 }
3410
3411 /* Write sgpd tag */
3412 20 avio_wb32(pb, 24 + (group * 2)); /* size */
3413 20 ffio_wfourcc(pb, "sgpd");
3414 20 avio_wb32(pb, 1 << 24); /* fullbox */
3415 20 ffio_wfourcc(pb, "roll");
3416 20 avio_wb32(pb, 2); /* default_length */
3417 20 avio_wb32(pb, group); /* entry_count */
3418
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for (i = 0; i < entries; i++) {
3419
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (sgpd_entries[i].group_description_index) {
3420 20 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3421 }
3422 }
3423
3424 /* Write sbgp tag */
3425 20 avio_wb32(pb, 20 + (entries * 8)); /* size */
3426 20 ffio_wfourcc(pb, "sbgp");
3427 20 avio_wb32(pb, 0); /* fullbox */
3428 20 ffio_wfourcc(pb, "roll");
3429 20 avio_wb32(pb, entries); /* entry_count */
3430
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for (i = 0; i < entries; i++) {
3431 20 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3432 20 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3433 }
3434
3435 20 av_free(sgpd_entries);
3436 20 return 0;
3437 }
3438
3439 382 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3440 {
3441 382 int64_t pos = avio_tell(pb);
3442 382 int ret = 0;
3443
3444 382 avio_wb32(pb, 0); /* size */
3445 382 ffio_wfourcc(pb, "stbl");
3446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3447 return ret;
3448 382 mov_write_stts_tag(pb, track);
3449
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 232 times.
382 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3450
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3451
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3452
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
150 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3453
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 148 times.
150 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3454
4/4
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 111 times.
234 track->has_keyframes && track->has_keyframes < track->entry)
3455 68 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3456
5/6
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 229 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3457 3 mov_write_sdtp_tag(pb, track);
3458
3/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
382 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3459 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3460
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3461
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24 times.
232 track->flags & MOV_TRACK_CTTS && track->entry) {
3462
3463
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3464 return ret;
3465 }
3466 382 mov_write_stsc_tag(pb, track);
3467 382 mov_write_stsz_tag(pb, track);
3468 382 mov_write_stco_tag(pb, track);
3469
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 377 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
382 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3470 5 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3471 }
3472
3/4
✓ Branch 0 taken 382 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 317 times.
382 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3473 65 mov_preroll_write_stbl_atoms(pb, track);
3474 }
3475 382 return update_size(pb, pos);
3476 }
3477
3478 382 static int mov_write_dinf_tag(AVIOContext *pb)
3479 {
3480 382 int64_t pos = avio_tell(pb);
3481 382 avio_wb32(pb, 0); /* size */
3482 382 ffio_wfourcc(pb, "dinf");
3483 382 mov_write_dref_tag(pb);
3484 382 return update_size(pb, pos);
3485 }
3486
3487 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3488 {
3489 7 avio_wb32(pb, 12);
3490 7 ffio_wfourcc(pb, "nmhd");
3491 7 avio_wb32(pb, 0);
3492 7 return 12;
3493 }
3494
3495 2 static int mov_write_sthd_tag(AVIOContext *pb)
3496 {
3497 2 avio_wb32(pb, 12);
3498 2 ffio_wfourcc(pb, "sthd");
3499 2 avio_wb32(pb, 0);
3500 2 return 12;
3501 }
3502
3503 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3504 {
3505 9 int64_t pos = avio_tell(pb);
3506 9 const char *font = "Lucida Grande";
3507 9 avio_wb32(pb, 0); /* size */
3508 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3509 9 avio_wb32(pb, 0); /* version & flags */
3510 9 avio_wb16(pb, 0); /* text font */
3511 9 avio_wb16(pb, 0); /* text face */
3512 9 avio_wb16(pb, 12); /* text size */
3513 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3514 9 avio_wb16(pb, 0x0000); /* text color (red) */
3515 9 avio_wb16(pb, 0x0000); /* text color (green) */
3516 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3517 9 avio_wb16(pb, 0xffff); /* background color (red) */
3518 9 avio_wb16(pb, 0xffff); /* background color (green) */
3519 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3520 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3521 9 avio_write(pb, font, strlen(font)); /* font name */
3522 9 return update_size(pb, pos);
3523 }
3524
3525 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3526 {
3527 11 int64_t pos = avio_tell(pb);
3528 11 avio_wb32(pb, 0); /* size */
3529 11 ffio_wfourcc(pb, "gmhd");
3530 11 avio_wb32(pb, 0x18); /* gmin size */
3531 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3532 11 avio_wb32(pb, 0); /* version & flags */
3533 11 avio_wb16(pb, 0x40); /* graphics mode = */
3534 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3535 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3536 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3537 11 avio_wb16(pb, 0); /* balance */
3538 11 avio_wb16(pb, 0); /* reserved */
3539
3540 /*
3541 * This special text atom is required for
3542 * Apple Quicktime chapters. The contents
3543 * don't appear to be documented, so the
3544 * bytes are copied verbatim.
3545 */
3546
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3547 11 avio_wb32(pb, 0x2C); /* size */
3548 11 ffio_wfourcc(pb, "text");
3549 11 avio_wb16(pb, 0x01);
3550 11 avio_wb32(pb, 0x00);
3551 11 avio_wb32(pb, 0x00);
3552 11 avio_wb32(pb, 0x00);
3553 11 avio_wb32(pb, 0x01);
3554 11 avio_wb32(pb, 0x00);
3555 11 avio_wb32(pb, 0x00);
3556 11 avio_wb32(pb, 0x00);
3557 11 avio_wb32(pb, 0x00004000);
3558 11 avio_wb16(pb, 0x0000);
3559 }
3560
3561
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3562 9 int64_t tmcd_pos = avio_tell(pb);
3563 9 avio_wb32(pb, 0); /* size */
3564 9 ffio_wfourcc(pb, "tmcd");
3565 9 mov_write_tcmi_tag(pb, track);
3566 9 update_size(pb, tmcd_pos);
3567
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3568 1 int64_t gpmd_pos = avio_tell(pb);
3569 1 avio_wb32(pb, 0); /* size */
3570 1 ffio_wfourcc(pb, "gpmd");
3571 1 avio_wb32(pb, 0); /* version */
3572 1 update_size(pb, gpmd_pos);
3573 }
3574 11 return update_size(pb, pos);
3575 }
3576
3577 128 static int mov_write_smhd_tag(AVIOContext *pb)
3578 {
3579 128 avio_wb32(pb, 16); /* size */
3580 128 ffio_wfourcc(pb, "smhd");
3581 128 avio_wb32(pb, 0); /* version & flags */
3582 128 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3583 128 avio_wb16(pb, 0); /* reserved */
3584 128 return 16;
3585 }
3586
3587 232 static int mov_write_vmhd_tag(AVIOContext *pb)
3588 {
3589 232 avio_wb32(pb, 0x14); /* size (always 0x14) */
3590 232 ffio_wfourcc(pb, "vmhd");
3591 232 avio_wb32(pb, 0x01); /* version & flags */
3592 232 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3593 232 return 0x14;
3594 }
3595
3596 229 static int is_clcp_track(MOVTrack *track)
3597 {
3598
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
458 return track->tag == MKTAG('c','7','0','8') ||
3599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 track->tag == MKTAG('c','6','0','8');
3600 }
3601
3602 574 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3603 {
3604 574 MOVMuxContext *mov = s->priv_data;
3605 574 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3606 574 int64_t pos = avio_tell(pb);
3607 size_t descr_len;
3608
3609 574 hdlr = "dhlr";
3610 574 hdlr_type = "url ";
3611 574 descr = "DataHandler";
3612
3613
2/2
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 192 times.
574 if (track) {
3614
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
382 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3615
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
232 if (track->mode == MODE_AVIF) {
3617 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3618 descr = "PictureHandler";
3619 } else {
3620 232 hdlr_type = "vide";
3621 232 descr = "VideoHandler";
3622 }
3623
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 22 times.
150 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3624 128 hdlr_type = "soun";
3625 128 descr = "SoundHandler";
3626
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3627
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3628 hdlr_type = "clcp";
3629 descr = "ClosedCaptionHandler";
3630 } else {
3631
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3632 1 hdlr_type = "sbtl";
3633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3634 hdlr_type = "subp";
3635
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3636 2 hdlr_type = "subt";
3637 } else {
3638 3 hdlr_type = "text";
3639 }
3640 6 descr = "SubtitleHandler";
3641 }
3642
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3643 2 hdlr_type = "hint";
3644 2 descr = "HintHandler";
3645
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3646 13 hdlr_type = "tmcd";
3647 13 descr = "TimeCodeHandler";
3648
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3649 1 hdlr_type = "meta";
3650 1 descr = "GoPro MET"; // GoPro Metadata
3651 } else {
3652 av_log(s, AV_LOG_WARNING,
3653 "Unknown hdlr_type for %s, writing dummy values\n",
3654 av_fourcc2str(track->par->codec_tag));
3655 }
3656
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 3 times.
382 if (track->st) {
3657 // hdlr.name is used by some players to identify the content title
3658 // of the track. So if an alternate handler description is
3659 // specified, use it.
3660 AVDictionaryEntry *t;
3661 379 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3662
3/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 352 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
379 if (t && utf8len(t->value))
3663 27 descr = t->value;
3664 }
3665 }
3666
3667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 574 times.
574 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3668 descr = "";
3669
3670 574 avio_wb32(pb, 0); /* size */
3671 574 ffio_wfourcc(pb, "hdlr");
3672 574 avio_wb32(pb, 0); /* Version & flags */
3673 574 avio_write(pb, hdlr, 4); /* handler */
3674 574 ffio_wfourcc(pb, hdlr_type); /* handler type */
3675 574 avio_wb32(pb, 0); /* reserved */
3676 574 avio_wb32(pb, 0); /* reserved */
3677 574 avio_wb32(pb, 0); /* reserved */
3678 574 descr_len = strlen(descr);
3679
4/4
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 190 times.
574 if (!track || track->mode == MODE_MOV)
3680 384 avio_w8(pb, descr_len); /* pascal string */
3681 574 avio_write(pb, descr, descr_len); /* handler description */
3682
4/4
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 192 times.
574 if (track && track->mode != MODE_MOV)
3683 190 avio_w8(pb, 0); /* c string */
3684 574 return update_size(pb, pos);
3685 }
3686
3687 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3688 {
3689 int64_t pos = avio_tell(pb);
3690 avio_wb32(pb, 0); /* size */
3691 ffio_wfourcc(pb, "pitm");
3692 avio_wb32(pb, 0); /* Version & flags */
3693 avio_wb16(pb, item_id); /* item_id */
3694 return update_size(pb, pos);
3695 }
3696
3697 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3698 {
3699 int64_t pos = avio_tell(pb);
3700 avio_wb32(pb, 0); /* size */
3701 ffio_wfourcc(pb, "iloc");
3702 avio_wb32(pb, 0); /* Version & flags */
3703 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3704 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3705 avio_wb16(pb, mov->nb_streams); /* item_count */
3706
3707 for (int i = 0; i < mov->nb_streams; i++) {
3708 avio_wb16(pb, i + 1); /* item_id */
3709 avio_wb16(pb, 0); /* data_reference_index */
3710 avio_wb16(pb, 1); /* extent_count */
3711 mov->avif_extent_pos[i] = avio_tell(pb);
3712 avio_wb32(pb, 0); /* extent_offset (written later) */
3713 // For animated AVIF, we simply write the first packet's size.
3714 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3715 }
3716
3717 return update_size(pb, pos);
3718 }
3719
3720 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3721 {
3722 int64_t iinf_pos = avio_tell(pb);
3723 avio_wb32(pb, 0); /* size */
3724 ffio_wfourcc(pb, "iinf");
3725 avio_wb32(pb, 0); /* Version & flags */
3726 avio_wb16(pb, mov->nb_streams); /* entry_count */
3727
3728 for (int i = 0; i < mov->nb_streams; i++) {
3729 int64_t infe_pos = avio_tell(pb);
3730 avio_wb32(pb, 0); /* size */
3731 ffio_wfourcc(pb, "infe");
3732 avio_w8(pb, 0x2); /* Version */
3733 avio_wb24(pb, 0); /* flags */
3734 avio_wb16(pb, i + 1); /* item_id */
3735 avio_wb16(pb, 0); /* item_protection_index */
3736 avio_write(pb, "av01", 4); /* item_type */
3737 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3738 update_size(pb, infe_pos);
3739 }
3740
3741 return update_size(pb, iinf_pos);
3742 }
3743
3744
3745 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3746 {
3747 int64_t auxl_pos;
3748 int64_t iref_pos = avio_tell(pb);
3749 avio_wb32(pb, 0); /* size */
3750 ffio_wfourcc(pb, "iref");
3751 avio_wb32(pb, 0); /* Version & flags */
3752
3753 auxl_pos = avio_tell(pb);
3754 avio_wb32(pb, 0); /* size */
3755 ffio_wfourcc(pb, "auxl");
3756 avio_wb16(pb, 2); /* from_item_ID */
3757 avio_wb16(pb, 1); /* reference_count */
3758 avio_wb16(pb, 1); /* to_item_ID */
3759 update_size(pb, auxl_pos);
3760
3761 return update_size(pb, iref_pos);
3762 }
3763
3764 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3765 int stream_index)
3766 {
3767 int64_t pos = avio_tell(pb);
3768 avio_wb32(pb, 0); /* size */
3769 ffio_wfourcc(pb, "ispe");
3770 avio_wb32(pb, 0); /* Version & flags */
3771 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3772 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3773 return update_size(pb, pos);
3774 }
3775
3776 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3777 int stream_index)
3778 {
3779 int64_t pos = avio_tell(pb);
3780 const AVPixFmtDescriptor *pixdesc =
3781 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3782 avio_wb32(pb, 0); /* size */
3783 ffio_wfourcc(pb, "pixi");
3784 avio_wb32(pb, 0); /* Version & flags */
3785 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3786 for (int i = 0; i < pixdesc->nb_components; ++i) {
3787 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3788 }
3789 return update_size(pb, pos);
3790 }
3791
3792 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3793 {
3794 int64_t pos = avio_tell(pb);
3795 avio_wb32(pb, 0); /* size */
3796 ffio_wfourcc(pb, "ipco");
3797 for (int i = 0; i < mov->nb_streams; i++) {
3798 mov_write_ispe_tag(pb, mov, s, i);
3799 mov_write_pixi_tag(pb, mov, s, i);
3800 mov_write_av1c_tag(pb, &mov->tracks[i]);
3801 if (!i)
3802 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3803 else
3804 mov_write_aux_tag(pb, "auxC");
3805 }
3806 return update_size(pb, pos);
3807 }
3808
3809 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3810 {
3811 int64_t pos = avio_tell(pb);
3812 avio_wb32(pb, 0); /* size */
3813 ffio_wfourcc(pb, "ipma");
3814 avio_wb32(pb, 0); /* Version & flags */
3815 avio_wb32(pb, mov->nb_streams); /* entry_count */
3816
3817 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3818 avio_wb16(pb, i + 1); /* item_ID */
3819 avio_w8(pb, 4); /* association_count */
3820
3821 // ispe association.
3822 avio_w8(pb, index++); /* essential and property_index */
3823 // pixi association.
3824 avio_w8(pb, index++); /* essential and property_index */
3825 // av1C association.
3826 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3827 // colr/auxC association.
3828 avio_w8(pb, index++); /* essential and property_index */
3829 }
3830 return update_size(pb, pos);
3831 }
3832
3833 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3834 {
3835 int64_t pos = avio_tell(pb);
3836 avio_wb32(pb, 0); /* size */
3837 ffio_wfourcc(pb, "iprp");
3838 mov_write_ipco_tag(pb, mov, s);
3839 mov_write_ipma_tag(pb, mov, s);
3840 return update_size(pb, pos);
3841 }
3842
3843 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3844 {
3845 /* This atom must be present, but leaving the values at zero
3846 * seems harmless. */
3847 2 avio_wb32(pb, 28); /* size */
3848 2 ffio_wfourcc(pb, "hmhd");
3849 2 avio_wb32(pb, 0); /* version, flags */
3850 2 avio_wb16(pb, 0); /* maxPDUsize */
3851 2 avio_wb16(pb, 0); /* avgPDUsize */
3852 2 avio_wb32(pb, 0); /* maxbitrate */
3853 2 avio_wb32(pb, 0); /* avgbitrate */
3854 2 avio_wb32(pb, 0); /* reserved */
3855 2 return 28;
3856 }
3857
3858 382 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3859 {
3860 382 int64_t pos = avio_tell(pb);
3861 int ret;
3862
3863 382 avio_wb32(pb, 0); /* size */
3864 382 ffio_wfourcc(pb, "minf");
3865
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 150 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3866 232 mov_write_vmhd_tag(pb);
3867
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 22 times.
150 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3868 128 mov_write_smhd_tag(pb);
3869
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3870
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
6 if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
3871 1 mov_write_gmhd_tag(pb, track);
3872
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3873 2 mov_write_sthd_tag(pb);
3874 } else {
3875 3 mov_write_nmhd_tag(pb);
3876 }
3877
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3878 2 mov_write_hmhd_tag(pb);
3879
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3880
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3881 4 mov_write_nmhd_tag(pb);
3882 else
3883 9 mov_write_gmhd_tag(pb, track);
3884
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3885 1 mov_write_gmhd_tag(pb, track);
3886 }
3887
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
382 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3888 192 mov_write_hdlr_tag(s, pb, NULL);
3889 382 mov_write_dinf_tag(pb);
3890
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3891 return ret;
3892 382 return update_size(pb, pos);
3893 }
3894
3895 1466 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3896 int64_t *start, int64_t *end, int elst, int mdhd)
3897 {
3898
5/6
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1416 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
1466 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd && track->nb_src_track) {
3899 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3900 // another track's duration, while the end_pts may be left at zero.
3901 // Calculate the pts duration for that track instead.
3902 38 get_pts_range(mov, &mov->tracks[*track->src_track], start, end, elst, mdhd);
3903 38 *start = av_rescale(*start, track->timescale,
3904 38 mov->tracks[*track->src_track].timescale);
3905 38 *end = av_rescale(*end, track->timescale,
3906 38 mov->tracks[*track->src_track].timescale);
3907 38 return;
3908 }
3909
4/4
✓ Branch 0 taken 1046 times.
✓ Branch 1 taken 382 times.
✓ Branch 2 taken 1005 times.
✓ Branch 3 taken 41 times.
1428 if (!mdhd && track->end_pts != AV_NOPTS_VALUE &&
3910
1/2
✓ Branch 0 taken 1005 times.
✗ Branch 1 not taken.
1005 track->start_dts != AV_NOPTS_VALUE &&
3911
1/2
✓ Branch 0 taken 1005 times.
✗ Branch 1 not taken.
1005 track->start_cts != AV_NOPTS_VALUE) {
3912 1005 *start = track->start_dts + track->start_cts;
3913
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 686 times.
1005 *end = elst ? track->elst_end_pts : track->end_pts;
3914 1005 return;
3915 }
3916 423 *start = 0;
3917 423 *end = track->track_duration;
3918 }
3919
3920 382 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3921 {
3922 int64_t start, end;
3923 382 get_pts_range(mov, track, &start, &end, 0, 1);
3924 382 return end - start;
3925 }
3926
3927 // Calculate the actual duration of the track, after edits.
3928 // If it starts with a pts < 0, that is removed by the edit list.
3929 // If it starts with a pts > 0, the edit list adds a delay before that.
3930 // Thus, with edit lists enabled, the post-edit output of the file is
3931 // starting with pts=0.
3932 727 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3933 {
3934 int64_t start, end;
3935 727 get_pts_range(mov, track, &start, &end, 0, 0);
3936
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 83 times.
727 if (mov->use_editlist != 0)
3937 644 start = 0;
3938 727 return end - start;
3939 }
3940
3941 319 static int64_t calc_elst_duration(MOVMuxContext *mov, MOVTrack *track)
3942 {
3943 int64_t start, end;
3944 319 get_pts_range(mov, track, &start, &end, 1, 0);
3945 319 return end - start;
3946 }
3947
3948 1044 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3949 {
3950
4/4
✓ Branch 0 taken 764 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 746 times.
1044 if (track && track->mode == MODE_ISM)
3951 18 return 1;
3952
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 8 times.
1026 if (duration < INT32_MAX)
3953 1018 return 0;
3954 8 return 1;
3955 }
3956
3957 382 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3958 MOVTrack *track)
3959 {
3960 382 int64_t duration = calc_samples_pts_duration(mov, track);
3961 382 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3962
3963
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3964 382 ffio_wfourcc(pb, "mdhd");
3965 382 avio_w8(pb, version);
3966 382 avio_wb24(pb, 0); /* flags */
3967
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 if (version == 1) {
3968 13 avio_wb64(pb, track->time);
3969 13 avio_wb64(pb, track->time);
3970 } else {
3971 369 avio_wb32(pb, track->time); /* creation time */
3972 369 avio_wb32(pb, track->time); /* modification time */
3973 }
3974 382 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3975
4/4
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 98 times.
382 if (!track->entry && mov->mode == MODE_ISM)
3976
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3977
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 275 times.
373 else if (!track->entry)
3978
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 94 times.
98 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3979 else
3980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3981 382 avio_wb16(pb, track->language); /* language */
3982 382 avio_wb16(pb, 0); /* reserved (quality) */
3983
3984
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
382 if (version != 0 && track->mode == MODE_MOV) {
3985 av_log(NULL, AV_LOG_ERROR,
3986 "FATAL error, file duration too long for timebase, this file will not be\n"
3987 "playable with QuickTime. Choose a different timebase with "
3988 "-video_track_timescale or a different container format\n");
3989 }
3990
3991 382 return 32;
3992 }
3993
3994 382 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3995 MOVMuxContext *mov, MOVTrack *track)
3996 {
3997 382 int64_t pos = avio_tell(pb);
3998 int ret;
3999
4000 382 avio_wb32(pb, 0); /* size */
4001 382 ffio_wfourcc(pb, "mdia");
4002 382 mov_write_mdhd_tag(pb, mov, track);
4003 382 mov_write_hdlr_tag(s, pb, track);
4004
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
4005 return ret;
4006 382 return update_size(pb, pos);
4007 }
4008
4009 /* transformation matrix
4010 |a b u|
4011 |c d v|
4012 |tx ty w| */
4013 661 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
4014 int16_t d, int16_t tx, int16_t ty)
4015 {
4016 661 avio_wb32(pb, a << 16); /* 16.16 format */
4017 661 avio_wb32(pb, b << 16); /* 16.16 format */
4018 661 avio_wb32(pb, 0); /* u in 2.30 format */
4019 661 avio_wb32(pb, c << 16); /* 16.16 format */
4020 661 avio_wb32(pb, d << 16); /* 16.16 format */
4021 661 avio_wb32(pb, 0); /* v in 2.30 format */
4022 661 avio_wb32(pb, tx << 16); /* 16.16 format */
4023 661 avio_wb32(pb, ty << 16); /* 16.16 format */
4024 661 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
4025 661 }
4026
4027 382 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4028 MOVTrack *track, AVStream *st)
4029 {
4030 764 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
4031 382 mov->movie_timescale, track->timescale,
4032 AV_ROUND_UP);
4033 int version;
4034 382 int flags = MOV_TKHD_FLAG_IN_MOVIE;
4035 382 int group = 0;
4036
4037 382 uint32_t *display_matrix = NULL;
4038 int i;
4039
4040
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (mov->mode == MODE_AVIF)
4041 if (!mov->avif_loop_count)
4042 duration = INT64_MAX;
4043 else
4044 duration *= mov->avif_loop_count;
4045
4046
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 13 times.
382 if (st) {
4047 const AVPacketSideData *sd;
4048
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 367 times.
369 if (mov->per_stream_grouping)
4049 2 group = st->index;
4050 else
4051 367 group = st->codecpar->codec_type;
4052
4053 369 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4054 369 st->codecpar->nb_coded_side_data,
4055 AV_PKT_DATA_DISPLAYMATRIX);
4056
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 368 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
369 if (sd && sd->size == 9 * sizeof(*display_matrix))
4057 1 display_matrix = (uint32_t *)sd->data;
4058 }
4059
4060
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 25 times.
382 if (track->flags & MOV_TRACK_ENABLED)
4061 357 flags |= MOV_TKHD_FLAG_ENABLED;
4062
4063 382 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4064
4065
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
4066 382 ffio_wfourcc(pb, "tkhd");
4067 382 avio_w8(pb, version);
4068 382 avio_wb24(pb, flags);
4069
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 if (version == 1) {
4070 13 avio_wb64(pb, track->time);
4071 13 avio_wb64(pb, track->time);
4072 } else {
4073 369 avio_wb32(pb, track->time); /* creation time */
4074 369 avio_wb32(pb, track->time); /* modification time */
4075 }
4076 382 avio_wb32(pb, track->track_id); /* track-id */
4077 382 avio_wb32(pb, 0); /* reserved */
4078
4/4
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 98 times.
382 if (!track->entry && mov->mode == MODE_ISM)
4079
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4080
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 275 times.
373 else if (!track->entry)
4081
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 94 times.
98 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4082 else
4083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
4084
4085 382 avio_wb32(pb, 0); /* reserved */
4086 382 avio_wb32(pb, 0); /* reserved */
4087 382 avio_wb16(pb, 0); /* layer */
4088 382 avio_wb16(pb, group); /* alternate group) */
4089 /* Volume, only for audio */
4090
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 254 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
4091 128 avio_wb16(pb, 0x0100);
4092 else
4093 254 avio_wb16(pb, 0);
4094 382 avio_wb16(pb, 0); /* reserved */
4095
4096 /* Matrix structure */
4097
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 381 times.
382 if (display_matrix) {
4098
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
4099 9 avio_wb32(pb, display_matrix[i]);
4100 } else {
4101 381 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4102 }
4103 /* Track width and height, for visual only */
4104
4/4
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 232 times.
382 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
4105
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 132 times.
374 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
4106 int64_t track_width_1616;
4107
3/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
237 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
4108 144 track_width_1616 = track->par->width * 0x10000ULL;
4109 } else {
4110 93 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
4111 93 track->par->width * 0x10000LL,
4112 93 st->sample_aspect_ratio.den);
4113
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 74 times.
93 if (!track_width_1616 ||
4114
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
19 track->height != track->par->height ||
4115 track_width_1616 > UINT32_MAX)
4116 74 track_width_1616 = track->par->width * 0x10000ULL;
4117 }
4118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track_width_1616 > UINT32_MAX) {
4119 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4120 track_width_1616 = 0;
4121 }
4122 237 avio_wb32(pb, track_width_1616);
4123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track->height > 0xFFFF) {
4124 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4125 avio_wb32(pb, 0);
4126 } else
4127 237 avio_wb32(pb, track->height * 0x10000U);
4128 } else {
4129 145 avio_wb32(pb, 0);
4130 145 avio_wb32(pb, 0);
4131 }
4132 382 return 0x5c;
4133 }
4134
4135 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4136 {
4137 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4138 1 track->par->sample_aspect_ratio.den);
4139
4140 1 int64_t pos = avio_tell(pb);
4141
4142 1 avio_wb32(pb, 0); /* size */
4143 1 ffio_wfourcc(pb, "tapt");
4144
4145 1 avio_wb32(pb, 20);
4146 1 ffio_wfourcc(pb, "clef");
4147 1 avio_wb32(pb, 0);
4148 1 avio_wb32(pb, width << 16);
4149 1 avio_wb32(pb, track->par->height << 16);
4150
4151 1 avio_wb32(pb, 20);
4152 1 ffio_wfourcc(pb, "prof");
4153 1 avio_wb32(pb, 0);
4154 1 avio_wb32(pb, width << 16);
4155 1 avio_wb32(pb, track->par->height << 16);
4156
4157 1 avio_wb32(pb, 20);
4158 1 ffio_wfourcc(pb, "enof");
4159 1 avio_wb32(pb, 0);
4160 1 avio_wb32(pb, track->par->width << 16);
4161 1 avio_wb32(pb, track->par->height << 16);
4162
4163 1 return update_size(pb, pos);
4164 }
4165
4166 // This box is written in the following cases:
4167 // * Seems important for the psp playback. Without it the movie seems to hang.
4168 // * Used for specifying the looping behavior of animated AVIF (as specified
4169 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4170 319 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4171 MOVTrack *track)
4172 {
4173 638 int64_t duration = av_rescale_rnd(calc_elst_duration(mov, track),
4174 319 mov->movie_timescale, track->timescale,
4175 AV_ROUND_UP);
4176 319 int version = duration < INT32_MAX ? 0 : 1;
4177 int entry_size, entry_count, size;
4178 319 int64_t delay, start_ct = track->start_cts;
4179 319 int64_t start_dts = track->start_dts;
4180 319 int flags = 0;
4181
4182
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 60 times.
319 if (track->entry) {
4183
4/6
✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 256 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
259 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4184
4185 av_log(mov->fc, AV_LOG_DEBUG,
4186 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4187 track->cluster[0].dts, track->cluster[0].cts,
4188 start_dts, start_ct, track->track_id);
4189 start_dts = track->cluster[0].dts;
4190 start_ct = track->cluster[0].cts;
4191 }
4192 }
4193
4194 319 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4195 319 track->timescale, AV_ROUND_DOWN);
4196
4197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 319 times.
319 if (mov->mode == MODE_AVIF) {
4198 delay = 0;
4199 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4200 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4201 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4202 // edit list is repeated.
4203 flags = mov->avif_loop_count != 1;
4204 start_ct = 0;
4205 }
4206
4207 319 version |= delay < INT32_MAX ? 0 : 1;
4208
4209
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 entry_size = (version == 1) ? 20 : 12;
4210
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 entry_count = 1 + (delay > 0);
4211 319 size = 24 + entry_count * entry_size;
4212
4213 /* write the atom data */
4214 319 avio_wb32(pb, size);
4215 319 ffio_wfourcc(pb, "edts");
4216 319 avio_wb32(pb, size - 8);
4217 319 ffio_wfourcc(pb, "elst");
4218 319 avio_w8(pb, version);
4219 319 avio_wb24(pb, flags); /* flags */
4220
4221 319 avio_wb32(pb, entry_count);
4222
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 if (delay > 0) { /* add an empty edit to delay presentation */
4223 /* In the positive delay case, the delay includes the cts
4224 * offset, and the second edit list entry below trims out
4225 * the same amount from the actual content. This makes sure
4226 * that the offset last sample is included in the edit
4227 * list duration as well. */
4228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (version == 1) {
4229 avio_wb64(pb, delay);
4230 avio_wb64(pb, -1);
4231 } else {
4232 4 avio_wb32(pb, delay);
4233 4 avio_wb32(pb, -1);
4234 }
4235 4 avio_wb32(pb, 0x00010000);
4236
1/2
✓ Branch 0 taken 315 times.
✗ Branch 1 not taken.
315 } else if (mov->mode != MODE_AVIF) {
4237 /* Avoid accidentally ending up with start_ct = -1 which has got a
4238 * special meaning. Normally start_ct should end up positive or zero
4239 * here, but use FFMIN in case dts is a small positive integer
4240 * rounded to 0 when represented in movie timescale units. */
4241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
315 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4242 315 start_ct = -FFMIN(start_dts, 0);
4243
4244 #if CONFIG_IAMFENC
4245
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 310 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
315 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4246 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4247 #endif
4248 /* Note, this delay is calculated from the pts of the first sample,
4249 * ensuring that we don't reduce the duration for cases with
4250 * dts<0 pts=0. */
4251 315 duration += delay;
4252 }
4253
4254 /* For fragmented files, we don't know the full length yet. Setting
4255 * duration to 0 allows us to only specify the offset, including
4256 * the rest of the content (from all future fragments) without specifying
4257 * an explicit duration.
4258 *
4259 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4260 * don't reset duration to zero.
4261 */
4262
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 255 times.
319 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4263
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
64 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4264 64 duration = 0;
4265
4266 /* duration */
4267
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315 times.
319 if (version == 1) {
4268 4 avio_wb64(pb, duration);
4269 4 avio_wb64(pb, start_ct);
4270 } else {
4271 315 avio_wb32(pb, duration);
4272 315 avio_wb32(pb, start_ct);
4273 }
4274 319 avio_wb32(pb, 0x00010000);
4275 319 return size;
4276 }
4277
4278 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4279 {
4280 14 int64_t pos = avio_tell(pb);
4281 14 avio_wb32(pb, 0); // size placeholder
4282 14 ffio_wfourcc(pb, "tref");
4283
4284
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 for (int i = 0; i < track->nb_tref_tags; i++) {
4285 14 MovTag *tag = &track->tref_tags[i];
4286 14 avio_wb32(pb, 8 + tag->nb_id * sizeof(*tag->id)); // size (subatom)
4287 14 avio_wl32(pb, tag->name);
4288
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 14 times.
30 for (int j = 0; j < tag->nb_id; j++)
4289 16 avio_wb32(pb, tag->id[j]);
4290 }
4291 14 return update_size(pb, pos);
4292 }
4293
4294 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4295 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4296 {
4297 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4298 2 ffio_wfourcc(pb, "uuid");
4299 2 ffio_wfourcc(pb, "USMT");
4300 2 avio_wb32(pb, 0x21d24fce);
4301 2 avio_wb32(pb, 0xbb88695c);
4302 2 avio_wb32(pb, 0xfac9c740);
4303 2 avio_wb32(pb, 0x1c); // another size here!
4304 2 ffio_wfourcc(pb, "MTDT");
4305 2 avio_wb32(pb, 0x00010012);
4306 2 avio_wb32(pb, 0x0a);
4307 2 avio_wb32(pb, 0x55c40000);
4308 2 avio_wb32(pb, 0x1);
4309 2 avio_wb32(pb, 0x0);
4310 2 return 0x34;
4311 }
4312
4313 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4314 {
4315 2 AVFormatContext *ctx = track->rtp_ctx;
4316 2 char buf[1000] = "";
4317 int len;
4318
4319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
4320 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], *track->src_track,
4321 NULL, NULL, 0, 0, ctx);
4322 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4323 2 len = strlen(buf);
4324
4325 2 avio_wb32(pb, len + 24);
4326 2 ffio_wfourcc(pb, "udta");
4327 2 avio_wb32(pb, len + 16);
4328 2 ffio_wfourcc(pb, "hnti");
4329 2 avio_wb32(pb, len + 8);
4330 2 ffio_wfourcc(pb, "sdp ");
4331 2 avio_write(pb, buf, len);
4332 2 return len + 24;
4333 }
4334
4335 359 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4336 const char *tag, const char *str)
4337 {
4338 359 int64_t pos = avio_tell(pb);
4339 359 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4340
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 358 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
359 if (!t || !utf8len(t->value))
4341 358 return 0;
4342
4343 1 avio_wb32(pb, 0); /* size */
4344 1 ffio_wfourcc(pb, tag); /* type */
4345 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4346 1 return update_size(pb, pos);
4347 }
4348
4349 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4350 const char *value)
4351 {
4352 2 int64_t pos = avio_tell(pb);
4353
4354 /* Box|FullBox basics */
4355 2 avio_wb32(pb, 0); /* size placeholder */
4356 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4357 2 avio_w8(pb, 0); /* version = 0 */
4358 2 avio_wb24(pb, 0); /* flags = 0 */
4359
4360 /* Required null-terminated scheme URI */
4361 2 avio_write(pb, (const unsigned char *)scheme_uri,
4362 2 strlen(scheme_uri));
4363 2 avio_w8(pb, 0);
4364
4365 /* Optional value string */
4366
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])
4367 2 avio_write(pb, (const unsigned char *)value,
4368 2 strlen(value));
4369
4370 2 avio_w8(pb, 0);
4371
4372 2 return update_size(pb, pos);
4373 }
4374
4375 173 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4376 {
4377 173 int ret = AVERROR_BUG;
4378
4379
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 173 times.
346 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4380 173 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4381
4382
2/2
✓ Branch 0 taken 865 times.
✓ Branch 1 taken 173 times.
1038 for (int j = 0; map.value_maps[j].disposition; j++) {
4383 865 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4384
2/2
✓ Branch 0 taken 863 times.
✓ Branch 1 taken 2 times.
865 if (!(st->disposition & value_map.disposition))
4385 863 continue;
4386
4387
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)
4388 return ret;
4389 }
4390 }
4391
4392 173 return 0;
4393 }
4394
4395 382 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4396 AVStream *st)
4397 {
4398 AVIOContext *pb_buf;
4399 int ret, size;
4400 uint8_t *buf;
4401
4402
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 369 times.
382 if (!st)
4403 13 return 0;
4404
4405 369 ret = avio_open_dyn_buf(&pb_buf);
4406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
369 if (ret < 0)
4407 return ret;
4408
4409
2/2
✓ Branch 0 taken 359 times.
✓ Branch 1 taken 10 times.
369 if (mov->mode & (MODE_MP4|MODE_MOV))
4410 359 mov_write_track_metadata(pb_buf, st, "name", "title");
4411
4412
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 196 times.
369 if (mov->mode & MODE_MP4) {
4413
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4414 goto end;
4415 }
4416
4417
2/2
✓ Branch 1 taken 366 times.
✓ Branch 2 taken 3 times.
369 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4418 3 avio_wb32(pb, size + 8);
4419 3 ffio_wfourcc(pb, "udta");
4420 3 avio_write(pb, buf, size);
4421 }
4422 366 end:
4423 369 ffio_free_dyn_buf(&pb_buf);
4424
4425 369 return ret;
4426 }
4427
4428 382 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4429 MOVTrack *track, AVStream *st)
4430 {
4431 382 int64_t pos = avio_tell(pb);
4432 382 int entry_backup = track->entry;
4433 382 int chunk_backup = track->chunkCount;
4434 int ret;
4435
4436 /* If we want to have an empty moov, but some samples already have been
4437 * buffered (delay_moov), pretend that no samples have been written yet. */
4438
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 279 times.
382 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4439 103 track->chunkCount = track->entry = 0;
4440
4441 382 avio_wb32(pb, 0); /* size */
4442 382 ffio_wfourcc(pb, "trak");
4443 382 mov_write_tkhd_tag(pb, mov, track, st);
4444
4445 av_assert2(mov->use_editlist >= 0);
4446
4447
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 37 times.
382 if (track->start_dts != AV_NOPTS_VALUE) {
4448
2/2
✓ Branch 0 taken 319 times.
✓ Branch 1 taken 26 times.
345 if (mov->use_editlist)
4449 319 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4450
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))
4451 av_log(mov->fc, AV_LOG_WARNING,
4452 "Not writing any edit list even though one would have been required\n");
4453 }
4454
4455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (mov->is_animated_avif)
4456 mov_write_edts_tag(pb, mov, track);
4457
4458
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 368 times.
382 if (track->nb_tref_tags)
4459 14 mov_write_tref_tag(pb, track);
4460
4461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
382 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4462 return ret;
4463
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 380 times.
382 if (track->mode == MODE_PSP)
4464 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4465
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 380 times.
382 if (track->tag == MKTAG('r','t','p',' '))
4466 2 mov_write_udta_sdp(pb, track);
4467
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 190 times.
382 if (track->mode == MODE_MOV) {
4468
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 48 times.
192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4469 144 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4470
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
144 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4471 1 mov_write_tapt_tag(pb, track);
4472 }
4473 }
4474
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
192 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4475 mov_write_tapt_tag(pb, track);
4476 }
4477 }
4478 382 mov_write_track_udta_tag(pb, mov, st);
4479 382 track->entry = entry_backup;
4480 382 track->chunkCount = chunk_backup;
4481 382 return update_size(pb, pos);
4482 }
4483
4484 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4485 {
4486 int i, has_audio = 0, has_video = 0;
4487 int64_t pos = avio_tell(pb);
4488 int audio_profile = mov->iods_audio_profile;
4489 int video_profile = mov->iods_video_profile;
4490 for (i = 0; i < mov->nb_tracks; i++) {
4491 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4492 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4493 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4494 }
4495 }
4496 if (audio_profile < 0)
4497 audio_profile = 0xFF - has_audio;
4498 if (video_profile < 0)
4499 video_profile = 0xFF - has_video;
4500 avio_wb32(pb, 0x0); /* size */
4501 ffio_wfourcc(pb, "iods");
4502 avio_wb32(pb, 0); /* version & flags */
4503 put_descr(pb, 0x10, 7);
4504 avio_wb16(pb, 0x004f);
4505 avio_w8(pb, 0xff);
4506 avio_w8(pb, 0xff);
4507 avio_w8(pb, audio_profile);
4508 avio_w8(pb, video_profile);
4509 avio_w8(pb, 0xff);
4510 return update_size(pb, pos);
4511 }
4512
4513 123 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4514 {
4515 123 avio_wb32(pb, 0x20); /* size */
4516 123 ffio_wfourcc(pb, "trex");
4517 123 avio_wb32(pb, 0); /* version & flags */
4518 123 avio_wb32(pb, track->track_id); /* track ID */
4519 123 avio_wb32(pb, 1); /* default sample description index */
4520 123 avio_wb32(pb, 0); /* default sample duration */
4521 123 avio_wb32(pb, 0); /* default sample size */
4522 123 avio_wb32(pb, 0); /* default sample flags */
4523 123 return 0;
4524 }
4525
4526 67 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4527 {
4528 67 int64_t pos = avio_tell(pb);
4529 int i;
4530 67 avio_wb32(pb, 0x0); /* size */
4531 67 ffio_wfourcc(pb, "mvex");
4532
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 67 times.
190 for (i = 0; i < mov->nb_tracks; i++)
4533 123 mov_write_trex_tag(pb, &mov->tracks[i]);
4534 67 return update_size(pb, pos);
4535 }
4536
4537 280 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4538 {
4539 280 int max_track_id = 1, i;
4540 280 int64_t max_track_len = 0;
4541 int version;
4542 int timescale;
4543
4544
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
4545
3/4
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 345 times.
✗ Branch 3 not taken.
384 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4546 690 int64_t max_track_len_temp = av_rescale_rnd(
4547 345 calc_pts_duration(mov, &mov->tracks[i]),
4548 345 mov->movie_timescale,
4549 345 mov->tracks[i].timescale,
4550 AV_ROUND_UP);
4551
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 70 times.
345 if (max_track_len < max_track_len_temp)
4552 275 max_track_len = max_track_len_temp;
4553
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 261 times.
345 if (max_track_id < mov->tracks[i].track_id)
4554 84 max_track_id = mov->tracks[i].track_id;
4555 }
4556 }
4557 /* If using delay_moov, make sure the output is the same as if no
4558 * samples had been written yet. */
4559
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 223 times.
280 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4560 57 max_track_len = 0;
4561 57 max_track_id = 1;
4562 }
4563
4564 280 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4566
4567 280 ffio_wfourcc(pb, "mvhd");
4568 280 avio_w8(pb, version);
4569 280 avio_wb24(pb, 0); /* flags */
4570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 if (version == 1) {
4571 avio_wb64(pb, mov->time);
4572 avio_wb64(pb, mov->time);
4573 } else {
4574 280 avio_wb32(pb, mov->time); /* creation time */
4575 280 avio_wb32(pb, mov->time); /* modification time */
4576 }
4577
4578 280 timescale = mov->movie_timescale;
4579
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
280 if (mov->mode == MODE_AVIF && !timescale)
4580 timescale = mov->tracks[0].timescale;
4581
4582 280 avio_wb32(pb, timescale);
4583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4584
4585 280 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4586 280 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4587 280 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4588
4589 /* Matrix structure */
4590 280 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4591
4592 280 avio_wb32(pb, 0); /* reserved (preview time) */
4593 280 avio_wb32(pb, 0); /* reserved (preview duration) */
4594 280 avio_wb32(pb, 0); /* reserved (poster time) */
4595 280 avio_wb32(pb, 0); /* reserved (selection time) */
4596 280 avio_wb32(pb, 0); /* reserved (selection duration) */
4597 280 avio_wb32(pb, 0); /* reserved (current time) */
4598 280 avio_wb32(pb, max_track_id + 1); /* Next track id */
4599 280 return 0x6c;
4600 }
4601
4602 120 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4603 AVFormatContext *s)
4604 {
4605 120 avio_wb32(pb, 33); /* size */
4606 120 ffio_wfourcc(pb, "hdlr");
4607 120 avio_wb32(pb, 0);
4608 120 avio_wb32(pb, 0);
4609 120 ffio_wfourcc(pb, "mdir");
4610 120 ffio_wfourcc(pb, "appl");
4611 120 avio_wb32(pb, 0);
4612 120 avio_wb32(pb, 0);
4613 120 avio_w8(pb, 0);
4614 120 return 33;
4615 }
4616
4617 /* helper function to write a data tag with the specified string as data */
4618 75 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4619 {
4620 75 size_t data_len = strlen(data);
4621
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 34 times.
75 if (long_style) {
4622 41 int size = 16 + data_len;
4623 41 avio_wb32(pb, size); /* size */
4624 41 ffio_wfourcc(pb, "data");
4625 41 avio_wb32(pb, 1);
4626 41 avio_wb32(pb, 0);
4627 41 avio_write(pb, data, data_len);
4628 41 return size;
4629 } else {
4630 34 avio_wb16(pb, data_len); /* string length */
4631
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4632 26 lang = ff_mov_iso639_to_lang("und", 1);
4633 34 avio_wb16(pb, lang);
4634 34 avio_write(pb, data, data_len);
4635 34 return data_len + 4;
4636 }
4637 }
4638
4639 74 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4640 const char *value, int lang, int long_style)
4641 {
4642 74 int size = 0;
4643
2/4
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
✗ Branch 3 not taken.
74 if (value && value[0]) {
4644 74 int64_t pos = avio_tell(pb);
4645 74 avio_wb32(pb, 0); /* size */
4646 74 ffio_wfourcc(pb, name);
4647 74 mov_write_string_data_tag(pb, value, lang, long_style);
4648 74 size = update_size(pb, pos);
4649 }
4650 74 return size;
4651 }
4652
4653 1 static int mov_write_freeform_tag(AVIOContext *pb, const char *mean,
4654 const char *name, const char *data)
4655 {
4656
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!data || !data[0])
4657 return 0;
4658
4659 static const char stub_flags[4] = {0, 0, 0, 0};
4660
4661 1 int64_t entry_pos = avio_tell(pb);
4662 1 avio_wb32(pb, 0); /* size */
4663 1 ffio_wfourcc(pb, "----"); /* freeform */
4664
4665 1 size_t mean_len = strlen(mean);
4666 1 avio_wb32(pb, 12 + mean_len);
4667 1 ffio_wfourcc(pb, "mean");
4668 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4669 1 avio_write(pb, mean, mean_len);
4670
4671 1 size_t name_len = strlen(name);
4672 1 avio_wb32(pb, 12 + name_len);
4673 1 ffio_wfourcc(pb, "name");
4674 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4675 1 avio_write(pb, name, name_len);
4676
4677 1 mov_write_string_data_tag(pb, data, 0, 1);
4678
4679 1 return update_size(pb, entry_pos);
4680 }
4681
4682 4506 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4683 const char *tag, int *lang)
4684 {
4685 int l, len, len2;
4686 4506 AVDictionaryEntry *t, *t2 = NULL;
4687 char tag2[16];
4688
4689 4506 *lang = 0;
4690
4691
2/2
✓ Branch 1 taken 4443 times.
✓ Branch 2 taken 63 times.
4506 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4692 4443 return NULL;
4693
4694 63 len = strlen(t->key);
4695 63 snprintf(tag2, sizeof(tag2), "%s-", tag);
4696
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 55 times.
63 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4697 8 len2 = strlen(t2->key);
4698
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)
4699
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4700 8 *lang = l;
4701 8 return t;
4702 }
4703 }
4704 55 return t;
4705 }
4706
4707 4386 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4708 const char *name, const char *tag,
4709 int long_style)
4710 {
4711 int lang;
4712 4386 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4713
2/2
✓ Branch 0 taken 4323 times.
✓ Branch 1 taken 63 times.
4386 if (!t)
4714 4323 return 0;
4715 63 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4716 }
4717
4718 120 static int mov_write_custom_metadata(AVFormatContext *s, AVIOContext *pb,
4719 const char *mean, const char *name,
4720 const char *tag)
4721 {
4722 120 AVDictionaryEntry *t = av_dict_get(s->metadata, tag, NULL, 0);
4723
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 1 times.
120 if (!t)
4724 119 return 0;
4725 1 return mov_write_freeform_tag(pb, mean, name, t->value);
4726 }
4727
4728 /* iTunes bpm number */
4729 120 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4730 {
4731 120 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 int size = 0, tmpo = t ? atoi(t->value) : 0;
4733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (tmpo) {
4734 size = 26;
4735 avio_wb32(pb, size);
4736 ffio_wfourcc(pb, "tmpo");
4737 avio_wb32(pb, size-8); /* size */
4738 ffio_wfourcc(pb, "data");
4739 avio_wb32(pb, 0x15); //type specifier
4740 avio_wb32(pb, 0);
4741 avio_wb16(pb, tmpo); // data
4742 }
4743 120 return size;
4744 }
4745
4746 /* 3GPP TS 26.244 */
4747 120 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4748 {
4749 int lang;
4750 120 int64_t pos = avio_tell(pb);
4751 double latitude, longitude, altitude;
4752 int32_t latitude_fix, longitude_fix, altitude_fix;
4753 120 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4754 120 const char *ptr, *place = "";
4755 char *end;
4756 static const char *astronomical_body = "earth";
4757
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 if (!t)
4758 120 return 0;
4759
4760 ptr = t->value;
4761 latitude = strtod(ptr, &end);
4762 if (end == ptr) {
4763 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4764 return 0;
4765 }
4766 ptr = end;
4767 longitude = strtod(ptr, &end);
4768 if (end == ptr) {
4769 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4770 return 0;
4771 }
4772 ptr = end;
4773 altitude = strtod(ptr, &end);
4774 /* If no altitude was present, the default 0 should be fine */
4775 if (*end == '/')
4776 place = end + 1;
4777
4778 latitude_fix = (int32_t) ((1 << 16) * latitude);
4779 longitude_fix = (int32_t) ((1 << 16) * longitude);
4780 altitude_fix = (int32_t) ((1 << 16) * altitude);
4781
4782 avio_wb32(pb, 0); /* size */
4783 ffio_wfourcc(pb, "loci"); /* type */
4784 avio_wb32(pb, 0); /* version + flags */
4785 avio_wb16(pb, lang);
4786 avio_write(pb, place, strlen(place) + 1);
4787 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4788 avio_wb32(pb, longitude_fix);
4789 avio_wb32(pb, latitude_fix);
4790 avio_wb32(pb, altitude_fix);
4791 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4792 avio_w8(pb, 0); /* additional notes, null terminated string */
4793
4794 return update_size(pb, pos);
4795 }
4796
4797 /* iTunes track or disc number */
4798 240 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4799 AVFormatContext *s, int disc)
4800 {
4801
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 120 times.
240 AVDictionaryEntry *t = av_dict_get(s->metadata,
4802 disc ? "disc" : "track",
4803 NULL, 0);
4804
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 236 times.
240 int size = 0, track = t ? atoi(t->value) : 0;
4805
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 236 times.
240 if (track) {
4806 4 int tracks = 0;
4807 4 char *slash = strchr(t->value, '/');
4808
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (slash)
4809 3 tracks = atoi(slash + 1);
4810 4 avio_wb32(pb, 32); /* size */
4811
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4812 4 avio_wb32(pb, 24); /* size */
4813 4 ffio_wfourcc(pb, "data");
4814 4 avio_wb32(pb, 0); // 8 bytes empty
4815 4 avio_wb32(pb, 0);
4816 4 avio_wb16(pb, 0); // empty
4817 4 avio_wb16(pb, track); // track / disc number
4818 4 avio_wb16(pb, tracks); // total track / disc number
4819 4 avio_wb16(pb, 0); // empty
4820 4 size = 32;
4821 }
4822 240 return size;
4823 }
4824
4825 720 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4826 const char *name, const char *tag,
4827 int len)
4828 {
4829 720 AVDictionaryEntry *t = NULL;
4830 uint8_t num;
4831 720 int size = 24 + len;
4832
4833
3/4
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 480 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
720 if (len != 1 && len != 4)
4834 return -1;
4835
4836
2/2
✓ Branch 1 taken 718 times.
✓ Branch 2 taken 2 times.
720 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4837 718 return 0;
4838 2 num = atoi(t->value);
4839
4840 2 avio_wb32(pb, size);
4841 2 ffio_wfourcc(pb, name);
4842 2 avio_wb32(pb, size - 8);
4843 2 ffio_wfourcc(pb, "data");
4844 2 avio_wb32(pb, 0x15);
4845 2 avio_wb32(pb, 0);
4846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4847 2 else avio_w8 (pb, num);
4848
4849 2 return size;
4850 }
4851
4852 120 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4853 {
4854 120 MOVMuxContext *mov = s->priv_data;
4855 120 int64_t pos = 0;
4856
4857
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 120 times.
303 for (int i = 0; i < mov->nb_streams; i++) {
4858 183 MOVTrack *trk = &mov->tracks[i];
4859
4860
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 181 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
183 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4861 181 continue;
4862
4863
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4864 1 pos = avio_tell(pb);
4865 1 avio_wb32(pb, 0);
4866 1 ffio_wfourcc(pb, "covr");
4867 }
4868 2 avio_wb32(pb, 16 + trk->cover_image->size);
4869 2 ffio_wfourcc(pb, "data");
4870 2 avio_wb32(pb, trk->tag);
4871 2 avio_wb32(pb , 0);
4872 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4873 }
4874
4875
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 119 times.
120 return pos ? update_size(pb, pos) : 0;
4876 }
4877
4878 /* iTunes meta data list */
4879 120 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4880 AVFormatContext *s)
4881 {
4882 120 int64_t pos = avio_tell(pb);
4883 120 avio_wb32(pb, 0); /* size */
4884 120 ffio_wfourcc(pb, "ilst");
4885 120 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4886 120 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4887 120 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4888 120 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4889 120 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4890 120 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4891
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4892
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 109 times.
120 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4893 11 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4894 }
4895 120 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4896 120 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4897 120 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4898 120 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4899 120 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4900 120 mov_write_string_metadata(s, pb, "desc", "description",1);
4901 120 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4902 120 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4903 120 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4904 120 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4905 120 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4906 120 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4907 120 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4908 120 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4909 120 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4910 120 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4911 120 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4912 120 mov_write_covr(pb, s);
4913 120 mov_write_trkn_tag(pb, mov, s, 0); // track number
4914 120 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4915 120 mov_write_tmpo_tag(pb, s);
4916 120 mov_write_custom_metadata(s, pb, "com.apple.iTunes", "DISCSUBTITLE", "disc_subtitle");
4917 120 return update_size(pb, pos);
4918 }
4919
4920 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4921 AVFormatContext *s)
4922 {
4923 avio_wb32(pb, 33); /* size */
4924 ffio_wfourcc(pb, "hdlr");
4925 avio_wb32(pb, 0);
4926 avio_wb32(pb, 0);
4927 ffio_wfourcc(pb, "mdta");
4928 avio_wb32(pb, 0);
4929 avio_wb32(pb, 0);
4930 avio_wb32(pb, 0);
4931 avio_w8(pb, 0);
4932 return 33;
4933 }
4934
4935 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4936 AVFormatContext *s)
4937 {
4938 const AVDictionaryEntry *t = NULL;
4939 int64_t pos = avio_tell(pb);
4940 int64_t curpos, entry_pos;
4941 int count = 0;
4942
4943 avio_wb32(pb, 0); /* size */
4944 ffio_wfourcc(pb, "keys");
4945 avio_wb32(pb, 0);
4946 entry_pos = avio_tell(pb);
4947 avio_wb32(pb, 0); /* entry count */
4948
4949 while (t = av_dict_iterate(s->metadata, t)) {
4950 size_t key_len = strlen(t->key);
4951 avio_wb32(pb, key_len + 8);
4952 ffio_wfourcc(pb, "mdta");
4953 avio_write(pb, t->key, key_len);
4954 count += 1;
4955 }
4956 curpos = avio_tell(pb);
4957 avio_seek(pb, entry_pos, SEEK_SET);
4958 avio_wb32(pb, count); // rewrite entry count
4959 avio_seek(pb, curpos, SEEK_SET);
4960
4961 return update_size(pb, pos);
4962 }
4963
4964 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4965 AVFormatContext *s)
4966 {
4967 const AVDictionaryEntry *t = NULL;
4968 int64_t pos = avio_tell(pb);
4969 int count = 1; /* keys are 1-index based */
4970
4971 avio_wb32(pb, 0); /* size */
4972 ffio_wfourcc(pb, "ilst");
4973
4974 while (t = av_dict_iterate(s->metadata, t)) {
4975 int64_t entry_pos = avio_tell(pb);
4976 avio_wb32(pb, 0); /* size */
4977 avio_wb32(pb, count); /* key */
4978 mov_write_string_data_tag(pb, t->value, 0, 1);
4979 update_size(pb, entry_pos);
4980 count += 1;
4981 }
4982 return update_size(pb, pos);
4983 }
4984
4985 /* meta data tags */
4986 120 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4987 AVFormatContext *s)
4988 {
4989 120 int size = 0;
4990 120 int64_t pos = avio_tell(pb);
4991 120 avio_wb32(pb, 0); /* size */
4992 120 ffio_wfourcc(pb, "meta");
4993 120 avio_wb32(pb, 0);
4994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4995 mov_write_mdta_hdlr_tag(pb, mov, s);
4996 mov_write_mdta_keys_tag(pb, mov, s);
4997 mov_write_mdta_ilst_tag(pb, mov, s);
4998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 } else if (mov->mode == MODE_AVIF) {
4999 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
5000 // We always write the primary item id as 1 since only one track is
5001 // supported for AVIF.
5002 mov_write_pitm_tag(pb, 1);
5003 mov_write_iloc_tag(pb, mov, s);
5004 mov_write_iinf_tag(pb, mov, s);
5005 if (mov->nb_streams > 1)
5006 mov_write_iref_tag(pb, mov, s);
5007 mov_write_iprp_tag(pb, mov, s);
5008 } else {
5009 /* iTunes metadata tag */
5010 120 mov_write_itunes_hdlr_tag(pb, mov, s);
5011 120 mov_write_ilst_tag(pb, mov, s);
5012 }
5013 120 size = update_size(pb, pos);
5014 120 return size;
5015 }
5016
5017 159 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
5018 const char *name, const char *key)
5019 {
5020 int len;
5021 AVDictionaryEntry *t;
5022
5023
1/2
✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
159 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
5024 159 return 0;
5025
5026 len = strlen(t->value);
5027 if (len > 0) {
5028 int size = len + 8;
5029 avio_wb32(pb, size);
5030 ffio_wfourcc(pb, name);
5031 avio_write(pb, t->value, len);
5032 return size;
5033 }
5034 return 0;
5035 }
5036
5037 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
5038 {
5039 int val;
5040 while (*b) {
5041 GET_UTF8(val, *b++, return -1;)
5042 avio_wb16(pb, val);
5043 }
5044 avio_wb16(pb, 0x00);
5045 return 0;
5046 }
5047
5048 static uint16_t language_code(const char *str)
5049 {
5050 return (((str[0] - 0x60) & 0x1F) << 10) +
5051 (((str[1] - 0x60) & 0x1F) << 5) +
5052 (( str[2] - 0x60) & 0x1F);
5053 }
5054
5055 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
5056 const char *tag, const char *str)
5057 {
5058 int64_t pos = avio_tell(pb);
5059 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
5060 if (!t || !utf8len(t->value))
5061 return 0;
5062 avio_wb32(pb, 0); /* size */
5063 ffio_wfourcc(pb, tag); /* type */
5064 avio_wb32(pb, 0); /* version + flags */
5065 if (!strcmp(tag, "yrrc"))
5066 avio_wb16(pb, atoi(t->value));
5067 else {
5068 avio_wb16(pb, language_code("eng")); /* language */
5069 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
5070 if (!strcmp(tag, "albm") &&
5071 (t = av_dict_get(s->metadata, "track", NULL, 0)))
5072 avio_w8(pb, atoi(t->value));
5073 }
5074 return update_size(pb, pos);
5075 }
5076
5077 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
5078 {
5079 1 int64_t pos = avio_tell(pb);
5080 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
5081
5082 1 avio_wb32(pb, 0); // size
5083 1 ffio_wfourcc(pb, "chpl");
5084 1 avio_wb32(pb, 0x01000000); // version + flags
5085 1 avio_wb32(pb, 0); // unknown
5086 1 avio_w8(pb, nb_chapters);
5087
5088
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
5089 4 AVChapter *c = s->chapters[i];
5090 AVDictionaryEntry *t;
5091 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
5092
5093
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
5094
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
5095 4 avio_w8(pb, len);
5096 4 avio_write(pb, t->value, len);
5097 } else
5098 avio_w8(pb, 0);
5099 }
5100 1 return update_size(pb, pos);
5101 }
5102
5103 279 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
5104 AVFormatContext *s)
5105 {
5106 AVIOContext *pb_buf;
5107 int ret, size;
5108 uint8_t *buf;
5109
5110 279 ret = avio_open_dyn_buf(&pb_buf);
5111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 if (ret < 0)
5112 return ret;
5113
5114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 if (mov->mode & MODE_3GP) {
5115 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
5116 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
5117 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
5118 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
5119 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
5120 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
5121 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
5122 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
5123 mov_write_loci_tag(s, pb_buf);
5124
3/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
279 } else if (mov->mode == MODE_MOV && !(mov->flags & FF_MOV_FLAG_USE_MDTA)) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
5125 159 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
5126 159 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
5127 159 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
5128 159 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
5129 159 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
5130 159 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
5131 // currently ignored by mov.c
5132 159 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
5133 // add support for libquicktime, this atom is also actually read by mov.c
5134 159 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
5135 159 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
5136 159 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
5137 159 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
5138 159 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
5139 159 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
5140 159 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
5141 159 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
5142 } else {
5143 /* iTunes meta data */
5144 120 mov_write_meta_tag(pb_buf, mov, s);
5145 120 mov_write_loci_tag(s, pb_buf);
5146 }
5147
5148
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
279 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
5149 1 mov_write_chpl_tag(pb_buf, s);
5150
5151
2/2
✓ Branch 1 taken 148 times.
✓ Branch 2 taken 131 times.
279 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
5152 148 avio_wb32(pb, size + 8);
5153 148 ffio_wfourcc(pb, "udta");
5154 148 avio_write(pb, buf, size);
5155 }
5156 279 ffio_free_dyn_buf(&pb_buf);
5157
5158 279 return 0;
5159 }
5160
5161 static void mov_write_psp_udta_tag(AVIOContext *pb,
5162 const char *str, const char *lang, int type)
5163 {
5164 int len = utf8len(str) + 1;
5165 if (len <= 0)
5166 return;
5167 avio_wb16(pb, len * 2 + 10); /* size */
5168 avio_wb32(pb, type); /* type */
5169 avio_wb16(pb, language_code(lang)); /* language */
5170 avio_wb16(pb, 0x01); /* ? */
5171 ascii_to_wc(pb, str);
5172 }
5173
5174 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5175 {
5176 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5177 int64_t pos, pos2;
5178
5179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5180 pos = avio_tell(pb);
5181 avio_wb32(pb, 0); /* size placeholder*/
5182 ffio_wfourcc(pb, "uuid");
5183 ffio_wfourcc(pb, "USMT");
5184 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5185 avio_wb32(pb, 0xbb88695c);
5186 avio_wb32(pb, 0xfac9c740);
5187
5188 pos2 = avio_tell(pb);
5189 avio_wb32(pb, 0); /* size placeholder*/
5190 ffio_wfourcc(pb, "MTDT");
5191 avio_wb16(pb, 4);
5192
5193 // ?
5194 avio_wb16(pb, 0x0C); /* size */
5195 avio_wb32(pb, 0x0B); /* type */
5196 avio_wb16(pb, language_code("und")); /* language */
5197 avio_wb16(pb, 0x0); /* ? */
5198 avio_wb16(pb, 0x021C); /* data */
5199
5200 if (!(s->flags & AVFMT_FLAG_BITEXACT))
5201 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5202 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5203 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5204
5205 update_size(pb, pos2);
5206 return update_size(pb, pos);
5207 }
5208
5209 1 return 0;
5210 }
5211
5212 371 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5213 {
5214 AVEncryptionInitInfo *info;
5215 371 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5216 371 st->codecpar->nb_coded_side_data,
5217 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5218
1/2
✓ Branch 0 taken 371 times.
✗ Branch 1 not taken.
371 if (!sd)
5219 371 return 0;
5220
5221 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5222 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5223 int64_t pos;
5224
5225 if (!copy->data_size && !copy->num_key_ids)
5226 continue;
5227
5228 pos = avio_tell(pb);
5229 avio_wb32(pb, 0); /* size placeholder */
5230 ffio_wfourcc(pb, "pssh");
5231 avio_w8(pb, 1); /* version */
5232 avio_wb24(pb, 0);
5233 for (int i = 0; i < copy->system_id_size; i++)
5234 avio_w8(pb, copy->system_id[i]);
5235 avio_wb32(pb, copy->num_key_ids);
5236 for (int i = 0; i < copy->num_key_ids; i++)
5237 for (int j = 0; j < copy->key_id_size; j++)
5238 avio_w8(pb, copy->key_ids[i][j]);
5239 avio_wb32(pb, copy->data_size);
5240 avio_write(pb, copy->data, copy->data_size);
5241 update_size(pb, pos);
5242 }
5243
5244 av_encryption_init_info_free(info);
5245
5246 return 0;
5247 }
5248
5249 345 static void build_chunks(MOVTrack *trk)
5250 {
5251 int i;
5252 345 MOVIentry *chunk = &trk->cluster[0];
5253 345 uint64_t chunkSize = chunk->size;
5254 345 chunk->chunkNum = 1;
5255
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 287 times.
345 if (trk->chunkCount)
5256 58 return;
5257 287 trk->chunkCount = 1;
5258
2/2
✓ Branch 0 taken 18504 times.
✓ Branch 1 taken 287 times.
18791 for (i = 1; i<trk->entry; i++){
5259
2/2
✓ Branch 0 taken 16765 times.
✓ Branch 1 taken 1739 times.
18504 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5260
2/2
✓ Branch 0 taken 16763 times.
✓ Branch 1 taken 2 times.
16765 chunk->stsd_index == trk->cluster[i].stsd_index &&
5261
2/2
✓ Branch 0 taken 16118 times.
✓ Branch 1 taken 645 times.
16763 chunkSize + trk->cluster[i].size < (1<<20)){
5262 16118 chunkSize += trk->cluster[i].size;
5263 16118 chunk->samples_in_chunk += trk->cluster[i].entries;
5264 } else {
5265 2386 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5266 2386 chunk=&trk->cluster[i];
5267 2386 chunkSize = chunk->size;
5268 2386 trk->chunkCount++;
5269 }
5270 }
5271 }
5272
5273 /**
5274 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5275 * the stream ids are used as track ids.
5276 *
5277 * This assumes mov->tracks and s->streams are in the same order and
5278 * there are no gaps in either of them (so mov->tracks[n] refers to
5279 * s->streams[n]).
5280 *
5281 * As an exception, there can be more entries in
5282 * s->streams than in mov->tracks, in which case new track ids are
5283 * generated (starting after the largest found stream id).
5284 */
5285 280 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5286 {
5287 int i;
5288
5289
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 247 times.
280 if (mov->track_ids_ok)
5290 33 return 0;
5291
5292
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->use_stream_ids_as_track_ids) {
5293 1 int next_generated_track_id = 0;
5294
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5295 2 AVStream *st = mov->tracks[i].st;
5296
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5297 2 next_generated_track_id = st->id;
5298 }
5299
5300
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5301
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))
5302 continue;
5303
5304
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;
5305 }
5306 } else {
5307 246 int last_track_id = 0;
5308
2/2
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 246 times.
562 for (i = 0; i < mov->nb_tracks; i++) {
5309
4/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 33 times.
316 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5310 2 continue;
5311
5312 314 last_track_id =
5313 314 mov->tracks[i].track_id = (mov->tracks[i].st
5314 311 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5315
2/2
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 3 times.
314 : FFMAX(i, last_track_id)) + 1;
5316 }
5317 }
5318
5319 247 mov->track_ids_ok = 1;
5320
5321 247 return 0;
5322 }
5323
5324 16 static int mov_find_tref_id(MOVMuxContext *mov, const MovTag *tag, uint32_t id)
5325 {
5326
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12 times.
19 for (int i = 0; i < tag->nb_id; i++) {
5327
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (tag->id[i] == id)
5328 4 return 1;
5329 }
5330 12 return 0;
5331 }
5332
5333 16 static int mov_add_tref_id(MOVMuxContext *mov, MovTag *tag, uint32_t id)
5334 {
5335 16 int ret = mov_find_tref_id(mov, tag, id);
5336
5337
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 if (!ret) {
5338 12 uint32_t *tmp = av_realloc_array(tag->id, tag->nb_id + 1, sizeof(*tag->id));
5339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!tmp)
5340 return AVERROR(ENOMEM);
5341 12 tag->id = tmp;
5342 12 tag->id[tag->nb_id++] = id;
5343 }
5344
5345 16 return 0;
5346 }
5347
5348 16 static MovTag *mov_find_tref_tag(MOVMuxContext *mov, const MOVTrack *trk, uint32_t name)
5349 {
5350
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 for (int i = 0; i < trk->nb_tref_tags; i++) {
5351 6 MovTag *entry = &trk->tref_tags[i];
5352
5353
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (entry->name == name)
5354 6 return entry;
5355 }
5356 10 return NULL;
5357 }
5358
5359 16 static MovTag *mov_add_tref_tag(MOVMuxContext *mov, MOVTrack *trk, uint32_t name)
5360 {
5361 16 MovTag *tag = mov_find_tref_tag(mov, trk, name);
5362
5363
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if (!tag) {
5364 10 MovTag *tmp = av_realloc_array(trk->tref_tags, trk->nb_tref_tags + 1,
5365 sizeof(*trk->tref_tags));
5366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!tmp)
5367 return NULL;
5368 10 trk->tref_tags = tmp;
5369 10 tag = &trk->tref_tags[trk->nb_tref_tags++];
5370 10 *tag = (MovTag){ .name = name };
5371 }
5372
5373 16 return tag;
5374 }
5375
5376 280 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5377 AVFormatContext *s)
5378 {
5379 int i;
5380 280 int64_t pos = avio_tell(pb);
5381 280 avio_wb32(pb, 0); /* size placeholder*/
5382 280 ffio_wfourcc(pb, "moov");
5383
5384 280 mov_setup_track_ids(mov, s);
5385
5386
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
5387
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 345 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 37 times.
384 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5388 2 continue;
5389
5390 382 mov->tracks[i].time = mov->time;
5391
5392
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 37 times.
382 if (mov->tracks[i].entry)
5393 345 build_chunks(&mov->tracks[i]);
5394 }
5395
5396
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
280 if (mov->chapter_track)
5397
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5398 1 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[i], MKTAG('c','h','a','p'));
5399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
5400 return AVERROR(ENOMEM);
5401
5402 1 int ret = mov_add_tref_id(mov, tag, mov->tracks[mov->chapter_track].track_id);
5403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
5404 return ret;
5405 }
5406
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
5407 384 MOVTrack *track = &mov->tracks[i];
5408
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 382 times.
384 if (track->tag == MKTAG('r','t','p',' ')) {
5409 2 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('h','i','n','t'));
5410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
5411 return AVERROR(ENOMEM);
5412
5413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
5414 2 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
5416 return ret;
5417
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
382 } else if (track->tag == MKTAG('l','v','c','1') && track->nb_src_track) {
5418 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('s','b','a','s'));
5419 if (!tag)
5420 return AVERROR(ENOMEM);
5421
5422 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5423 if (ret < 0)
5424 return ret;
5425 } else {
5426
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 254 times.
382 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5427 128 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5428 128 track->st->codecpar->nb_coded_side_data,
5429 AV_PKT_DATA_FALLBACK_TRACK );
5430
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
128 if (sd && sd->size == sizeof(int)) {
5431 int *fallback = (int *)sd->data;
5432 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5433 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('f','a','l','l'));
5434 if (!tag)
5435 return AVERROR(ENOMEM);
5436
5437 int ret = mov_add_tref_id(mov, tag, mov->tracks[*fallback].track_id);
5438 if (ret < 0)
5439 return ret;
5440 }
5441 }
5442 }
5443
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 382 times.
395 for (int j = 0; j < track->nb_src_track; j++) {
5444 13 int src_trk = track->src_track[j];
5445 13 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[src_trk], track->tag);
5446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tag)
5447 return AVERROR(ENOMEM);
5448 13 int ret = mov_add_tref_id(mov, tag, track->track_id);
5449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (ret < 0)
5450 return ret;
5451 }
5452
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 356 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
382 if (mov->nb_meta_tmcd && track->nb_src_track) {
5453 /* Derive the duration from the first source track, matching
5454 * the convention used by get_pts_range() and the rtp/lvc1
5455 * branches above. The source may use a different timescale. */
5456 10 int src_trk = track->src_track[0];
5457 10 track->track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5458 10 track->timescale,
5459 10 mov->tracks[src_trk].timescale);
5460 }
5461 }
5462 }
5463
5464 280 mov_write_mvhd_tag(pb, mov);
5465
4/6
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 121 times.
280 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5466 mov_write_iods_tag(pb, mov);
5467
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 280 times.
664 for (i = 0; i < mov->nb_tracks; i++) {
5468
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 345 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 37 times.
384 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5470
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 13 times.
382 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (ret < 0)
5472 return ret;
5473 }
5474 }
5475 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5476 * (mov->moov_written != 0)
5477 */
5478
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 211 times.
280 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5479
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
69 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
5480 67 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5481
5482
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
280 if (mov->mode == MODE_PSP)
5483 1 mov_write_uuidusmt_tag(pb, s);
5484
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
279 else if (mov->mode != MODE_AVIF)
5485 279 mov_write_udta_tag(pb, mov, s);
5486
2/2
✓ Branch 0 taken 371 times.
✓ Branch 1 taken 280 times.
651 for (i = 0; i < mov->nb_streams; i++)
5487 371 mov_write_pssh_tag(pb, mov->tracks[i].st);
5488
5489 280 return update_size(pb, pos);
5490 }
5491
5492 static void param_write_int(AVIOContext *pb, const char *name, int value)
5493 {
5494 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5495 }
5496
5497 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5498 {
5499 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5500 }
5501
5502 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5503 {
5504 char buf[150];
5505 len = FFMIN(sizeof(buf) / 2 - 1, len);
5506 ff_data_to_hex(buf, value, len, 0);
5507 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5508 }
5509
5510 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5511 {
5512 int64_t pos = avio_tell(pb);
5513 int i;
5514
5515 static const AVUUID uuid = {
5516 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5517 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5518 };
5519
5520 avio_wb32(pb, 0);
5521 ffio_wfourcc(pb, "uuid");
5522 avio_write(pb, uuid, AV_UUID_LEN);
5523 avio_wb32(pb, 0);
5524
5525 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5526 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5527 avio_printf(pb, "<head>\n");
5528 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5529 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5530 LIBAVFORMAT_IDENT);
5531 avio_printf(pb, "</head>\n");
5532 avio_printf(pb, "<body>\n");
5533 avio_printf(pb, "<switch>\n");
5534
5535 mov_setup_track_ids(mov, s);
5536
5537 for (i = 0; i < mov->nb_tracks; i++) {
5538 MOVTrack *track = &mov->tracks[i];
5539 struct mpeg4_bit_rate_values bit_rates =
5540 calculate_mpeg4_bit_rates(track);
5541 const char *type;
5542 int track_id = track->track_id;
5543 char track_name_buf[32] = { 0 };
5544
5545 AVStream *st = track->st;
5546 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5547
5548 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5549 type = "video";
5550 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5551 type = "audio";
5552 } else {
5553 continue;
5554 }
5555
5556 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5557 bit_rates.avg_bit_rate);
5558 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5559 param_write_int(pb, "trackID", track_id);
5560 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5561
5562 /* Build track name piece by piece: */
5563 /* 1. track type */
5564 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5565 /* 2. track language, if available */
5566 if (lang)
5567 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5568 "_%s", lang->value);
5569 /* 3. special type suffix */
5570 /* "_cc" = closed captions, "_ad" = audio_description */
5571 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5572 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5573 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5574 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5575
5576 param_write_string(pb, "trackName", track_name_buf);
5577
5578 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5579 if (track->par->codec_id == AV_CODEC_ID_H264) {
5580 uint8_t *ptr;
5581 int size = track->extradata_size[track->last_stsd_index];
5582 if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5583 &size)) {
5584 param_write_hex(pb, "CodecPrivateData",
5585 ptr ? ptr : track->extradata[track->last_stsd_index],
5586 size);
5587 av_free(ptr);
5588 }
5589 param_write_string(pb, "FourCC", "H264");
5590 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5591 param_write_string(pb, "FourCC", "WVC1");
5592 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5593 track->extradata_size[track->last_stsd_index]);
5594 }
5595 param_write_int(pb, "MaxWidth", track->par->width);
5596 param_write_int(pb, "MaxHeight", track->par->height);
5597 param_write_int(pb, "DisplayWidth", track->par->width);
5598 param_write_int(pb, "DisplayHeight", track->par->height);
5599 } else {
5600 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5601 switch (track->par->profile) {
5602 case AV_PROFILE_AAC_HE_V2:
5603 param_write_string(pb, "FourCC", "AACP");
5604 break;
5605 case AV_PROFILE_AAC_HE:
5606 param_write_string(pb, "FourCC", "AACH");
5607 break;
5608 default:
5609 param_write_string(pb, "FourCC", "AACL");
5610 }
5611 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5612 param_write_string(pb, "FourCC", "WMAP");
5613 }
5614 param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5615 track->extradata_size[track->last_stsd_index]);
5616 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5617 track->par->codec_id));
5618 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5619 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5620 0 : track->par->sample_rate);
5621 param_write_int(pb, "BitsPerSample", 16);
5622 param_write_int(pb, "PacketSize", track->par->block_align ?
5623 track->par->block_align : 4);
5624 }
5625 avio_printf(pb, "</%s>\n", type);
5626 }
5627 avio_printf(pb, "</switch>\n");
5628 avio_printf(pb, "</body>\n");
5629 avio_printf(pb, "</smil>\n");
5630
5631 return update_size(pb, pos);
5632 }
5633
5634 238 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5635 {
5636 238 avio_wb32(pb, 16);
5637 238 ffio_wfourcc(pb, "mfhd");
5638 238 avio_wb32(pb, 0);
5639 238 avio_wb32(pb, mov->fragments);
5640 238 return 0;
5641 }
5642
5643 13566 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5644 {
5645
2/2
✓ Branch 0 taken 7652 times.
✓ Branch 1 taken 5914 times.
13566 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5646 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5647 }
5648
5649 358 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5650 MOVTrack *track, int64_t moof_offset)
5651 {
5652 358 int64_t pos = avio_tell(pb);
5653 358 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5654 MOV_TFHD_BASE_DATA_OFFSET;
5655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 if (!track->entry) {
5656 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5657 } else {
5658 358 flags |= MOV_TFHD_DEFAULT_FLAGS;
5659 }
5660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
358 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5661 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5662
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 214 times.
358 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5663 144 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5664 144 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5665 }
5666 /* CMAF requires all values to be explicit in tfhd atoms */
5667
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 298 times.
358 if (mov->flags & FF_MOV_FLAG_CMAF)
5668 60 flags |= MOV_TFHD_STSD_ID;
5669
5670 /* Don't set a default sample size, the silverlight player refuses
5671 * to play files with that set. Don't set a default sample duration,
5672 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5673 * file format says it MUST NOT be set. */
5674
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 276 times.
358 if (track->mode == MODE_ISM)
5675 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5676 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5677
5678 358 avio_wb32(pb, 0); /* size placeholder */
5679 358 ffio_wfourcc(pb, "tfhd");
5680 358 avio_w8(pb, 0); /* version */
5681 358 avio_wb24(pb, flags);
5682
5683 358 avio_wb32(pb, track->track_id); /* track-id */
5684
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 226 times.
358 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5685 132 avio_wb64(pb, moof_offset);
5686
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 298 times.
358 if (flags & MOV_TFHD_STSD_ID) {
5687 60 avio_wb32(pb, 1);
5688 }
5689
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5690 276 track->default_duration = get_cluster_duration(track, 0);
5691 276 avio_wb32(pb, track->default_duration);
5692 }
5693
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5694
1/2
✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
276 track->default_size = track->entry ? track->cluster[0].size : 1;
5695 276 avio_wb32(pb, track->default_size);
5696 } else
5697 82 track->default_size = -1;
5698
5699
1/2
✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
358 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5700 /* Set the default flags based on the second sample, if available.
5701 * If the first sample is different, that can be signaled via a separate field. */
5702
2/2
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 72 times.
358 if (track->entry > 1)
5703 286 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5704 else
5705 72 track->default_sample_flags =
5706 72 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5707
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 56 times.
72 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5708 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5709 358 avio_wb32(pb, track->default_sample_flags);
5710 }
5711
5712 358 return update_size(pb, pos);
5713 }
5714
5715 360 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5716 MOVTrack *track, int moof_size,
5717 int first, int end)
5718 {
5719 360 int64_t pos = avio_tell(pb);
5720 360 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5721 int i;
5722
5723
2/2
✓ Branch 0 taken 12740 times.
✓ Branch 1 taken 360 times.
13100 for (i = first; i < end; i++) {
5724
2/2
✓ Branch 1 taken 1838 times.
✓ Branch 2 taken 10902 times.
12740 if (get_cluster_duration(track, i) != track->default_duration)
5725 1838 flags |= MOV_TRUN_SAMPLE_DURATION;
5726
2/2
✓ Branch 0 taken 2956 times.
✓ Branch 1 taken 9784 times.
12740 if (track->cluster[i].size != track->default_size)
5727 2956 flags |= MOV_TRUN_SAMPLE_SIZE;
5728
4/4
✓ Branch 0 taken 12380 times.
✓ Branch 1 taken 360 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 12370 times.
12740 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5729 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5730 }
5731
3/4
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
360 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5732
2/2
✓ Branch 1 taken 176 times.
✓ Branch 2 taken 176 times.
352 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5733 176 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5734
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 260 times.
360 if (track->flags & MOV_TRACK_CTTS)
5735 100 flags |= MOV_TRUN_SAMPLE_CTS;
5736
5737 360 avio_wb32(pb, 0); /* size placeholder */
5738 360 ffio_wfourcc(pb, "trun");
5739
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 202 times.
360 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5740 158 avio_w8(pb, 1); /* version */
5741 else
5742 202 avio_w8(pb, 0); /* version */
5743 360 avio_wb24(pb, flags);
5744
5745 360 avio_wb32(pb, end - first); /* sample count */
5746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5747 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5748 !mov->first_trun)
5749 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5750 else
5751 360 avio_wb32(pb, moof_size + 8 + track->data_offset +
5752 360 track->cluster[first].pos); /* data offset */
5753
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 184 times.
360 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5754 176 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5755
5756
2/2
✓ Branch 0 taken 12740 times.
✓ Branch 1 taken 360 times.
13100 for (i = first; i < end; i++) {
5757
2/2
✓ Branch 0 taken 2030 times.
✓ Branch 1 taken 10710 times.
12740 if (flags & MOV_TRUN_SAMPLE_DURATION)
5758 2030 avio_wb32(pb, get_cluster_duration(track, i));
5759
2/2
✓ Branch 0 taken 3636 times.
✓ Branch 1 taken 9104 times.
12740 if (flags & MOV_TRUN_SAMPLE_SIZE)
5760 3636 avio_wb32(pb, track->cluster[i].size);
5761
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 12368 times.
12740 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5762 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5763
2/2
✓ Branch 0 taken 3162 times.
✓ Branch 1 taken 9578 times.
12740 if (flags & MOV_TRUN_SAMPLE_CTS)
5764 3162 avio_wb32(pb, track->cluster[i].cts);
5765 }
5766
5767 360 mov->first_trun = 0;
5768 360 return update_size(pb, pos);
5769 }
5770
5771 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5772 {
5773 82 int64_t pos = avio_tell(pb);
5774 static const uint8_t uuid[] = {
5775 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5776 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5777 };
5778
5779 82 avio_wb32(pb, 0); /* size placeholder */
5780 82 ffio_wfourcc(pb, "uuid");
5781 82 avio_write(pb, uuid, AV_UUID_LEN);
5782 82 avio_w8(pb, 1);
5783 82 avio_wb24(pb, 0);
5784 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5785 82 avio_wb64(pb, track->end_pts -
5786 82 (track->cluster[0].dts + track->cluster[0].cts));
5787
5788 82 return update_size(pb, pos);
5789 }
5790
5791 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5792 MOVTrack *track, int entry)
5793 {
5794 int n = track->nb_frag_info - 1 - entry, i;
5795 int size = 8 + 16 + 4 + 1 + 16*n;
5796 static const uint8_t uuid[] = {
5797 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5798 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5799 };
5800
5801 if (entry < 0)
5802 return 0;
5803
5804 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5805 avio_wb32(pb, size);
5806 ffio_wfourcc(pb, "uuid");
5807 avio_write(pb, uuid, AV_UUID_LEN);
5808 avio_w8(pb, 1);
5809 avio_wb24(pb, 0);
5810 avio_w8(pb, n);
5811 for (i = 0; i < n; i++) {
5812 int index = entry + 1 + i;
5813 avio_wb64(pb, track->frag_info[index].time);
5814 avio_wb64(pb, track->frag_info[index].duration);
5815 }
5816 if (n < mov->ism_lookahead) {
5817 int free_size = 16 * (mov->ism_lookahead - n);
5818 avio_wb32(pb, free_size);
5819 ffio_wfourcc(pb, "free");
5820 ffio_fill(pb, 0, free_size - 8);
5821 }
5822
5823 return 0;
5824 }
5825
5826 178 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5827 MOVTrack *track)
5828 {
5829 178 int64_t pos = avio_tell(pb);
5830 int i;
5831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 178 times.
178 for (i = 0; i < mov->ism_lookahead; i++) {
5832 /* Update the tfrf tag for the last ism_lookahead fragments,
5833 * nb_frag_info - 1 is the next fragment to be written. */
5834 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5835 }
5836 178 avio_seek(pb, pos, SEEK_SET);
5837 178 return 0;
5838 }
5839
5840 118 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5841 int size)
5842 {
5843 int i;
5844
2/2
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 118 times.
339 for (i = 0; i < mov->nb_tracks; i++) {
5845 221 MOVTrack *track = &mov->tracks[i];
5846 MOVFragmentInfo *info;
5847
6/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 178 times.
221 if ((tracks >= 0 && i != tracks) || !track->entry)
5848 43 continue;
5849 178 track->nb_frag_info++;
5850
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 106 times.
178 if (track->nb_frag_info >= track->frag_info_capacity) {
5851 72 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5852
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (av_reallocp_array(&track->frag_info,
5853 new_capacity,
5854 sizeof(*track->frag_info)))
5855 return AVERROR(ENOMEM);
5856 72 track->frag_info_capacity = new_capacity;
5857 }
5858 178 info = &track->frag_info[track->nb_frag_info - 1];
5859 178 info->offset = avio_tell(pb);
5860 178 info->size = size;
5861 // Try to recreate the original pts for the first packet
5862 // from the fields we have stored
5863 178 info->time = track->cluster[0].dts + track->cluster[0].cts;
5864 178 info->duration = track->end_pts -
5865 178 (track->cluster[0].dts + track->cluster[0].cts);
5866 // If the pts is less than zero, we will have trimmed
5867 // away parts of the media track using an edit list,
5868 // and the corresponding start presentation time is zero.
5869
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 170 times.
178 if (info->time < 0) {
5870 8 info->duration += info->time;
5871 8 info->time = 0;
5872 }
5873 178 info->tfrf_offset = 0;
5874 178 mov_write_tfrf_tags(pb, mov, track);
5875 }
5876 118 return 0;
5877 }
5878
5879 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5880 {
5881 int i;
5882 for (i = 0; i < mov->nb_tracks; i++) {
5883 MOVTrack *track = &mov->tracks[i];
5884 if ((tracks >= 0 && i != tracks) || !track->entry)
5885 continue;
5886 if (track->nb_frag_info > max) {
5887 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5888 track->nb_frag_info = max;
5889 }
5890 }
5891 }
5892
5893 276 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5894 {
5895 276 int64_t pos = avio_tell(pb);
5896
5897 276 avio_wb32(pb, 0); /* size */
5898 276 ffio_wfourcc(pb, "tfdt");
5899 276 avio_w8(pb, 1); /* version */
5900 276 avio_wb24(pb, 0);
5901 276 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5902 276 return update_size(pb, pos);
5903 }
5904
5905 358 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5906 MOVTrack *track, int64_t moof_offset,
5907 int moof_size)
5908 {
5909 358 int64_t pos = avio_tell(pb);
5910 358 int i, start = 0;
5911 358 avio_wb32(pb, 0); /* size placeholder */
5912 358 ffio_wfourcc(pb, "traf");
5913
5914 358 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5915
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 82 times.
358 if (mov->mode != MODE_ISM)
5916 276 mov_write_tfdt_tag(pb, track);
5917
2/2
✓ Branch 0 taken 12382 times.
✓ Branch 1 taken 358 times.
12740 for (i = 1; i < track->entry; i++) {
5918
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12380 times.
12382 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5919 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5920 2 start = i;
5921 }
5922 }
5923 358 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5924
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 276 times.
358 if (mov->mode == MODE_ISM) {
5925 82 mov_write_tfxd_tag(pb, track);
5926
5927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5928 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5929
5930 if (track->nb_frag_info > 0) {
5931 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5932 if (!info->tfrf_offset)
5933 info->tfrf_offset = avio_tell(pb);
5934 }
5935 avio_wb32(pb, 8 + size);
5936 ffio_wfourcc(pb, "free");
5937 ffio_fill(pb, 0, size);
5938 }
5939 }
5940
5941
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
358 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5942 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5943
5944 358 return update_size(pb, pos);
5945 }
5946
5947 238 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5948 int tracks, int moof_size)
5949 {
5950 238 int64_t pos = avio_tell(pb);
5951 int i;
5952
5953 238 avio_wb32(pb, 0); /* size placeholder */
5954 238 ffio_wfourcc(pb, "moof");
5955 238 mov->first_trun = 1;
5956
5957 238 mov_write_mfhd_tag(pb, mov);
5958
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 238 times.
682 for (i = 0; i < mov->nb_tracks; i++) {
5959 444 MOVTrack *track = &mov->tracks[i];
5960
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 286 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 82 times.
444 if (tracks >= 0 && i != tracks)
5961 76 continue;
5962
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 358 times.
368 if (!track->entry)
5963 10 continue;
5964
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
358 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5965 mov_write_pssh_tag(pb, track->st);
5966 358 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5967 }
5968
5969 238 return update_size(pb, pos);
5970 }
5971
5972 78 static int mov_write_sidx_tag(AVIOContext *pb,
5973 MOVTrack *track, int ref_size, int total_sidx_size)
5974 {
5975 78 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5976 int64_t presentation_time, duration, offset;
5977 unsigned starts_with_SAP;
5978 int i, entries;
5979
5980
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 if (track->entry) {
5981 78 entries = 1;
5982 78 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
5983 78 duration = track->end_pts -
5984 78 (track->cluster[0].dts + track->cluster[0].cts);
5985 78 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5986
5987 // pts<0 should be cut away using edts
5988
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 72 times.
78 if (presentation_time < 0) {
5989 6 duration += presentation_time;
5990 6 presentation_time = 0;
5991 }
5992 } else {
5993 entries = track->nb_frag_info;
5994 if (entries <= 0)
5995 return 0;
5996 presentation_time = track->frag_info[0].time;
5997 }
5998
5999 78 avio_wb32(pb, 0); /* size */
6000 78 ffio_wfourcc(pb, "sidx");
6001 78 avio_w8(pb, 1); /* version */
6002 78 avio_wb24(pb, 0);
6003 78 avio_wb32(pb, track->track_id); /* reference_ID */
6004 78 avio_wb32(pb, track->timescale); /* timescale */
6005 78 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
6006 78 offset_pos = avio_tell(pb);
6007 78 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
6008 78 avio_wb16(pb, 0); /* reserved */
6009
6010 78 avio_wb16(pb, entries); /* reference_count */
6011
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 78 times.
156 for (i = 0; i < entries; i++) {
6012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (!track->entry) {
6013 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
6014 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
6015 }
6016 duration = track->frag_info[i].duration;
6017 ref_size = track->frag_info[i].size;
6018 starts_with_SAP = 1;
6019 }
6020 78 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
6021 78 avio_wb32(pb, duration); /* subsegment_duration */
6022 78 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
6023 }
6024
6025 78 end_pos = avio_tell(pb);
6026 78 offset = pos + total_sidx_size - end_pos;
6027 78 avio_seek(pb, offset_pos, SEEK_SET);
6028 78 avio_wb64(pb, offset);
6029 78 avio_seek(pb, end_pos, SEEK_SET);
6030 78 return update_size(pb, pos);
6031 }
6032
6033 24 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
6034 int tracks, int ref_size)
6035 {
6036 int i, round, ret;
6037 AVIOContext *avio_buf;
6038 24 int total_size = 0;
6039
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 for (round = 0; round < 2; round++) {
6040 // First run one round to calculate the total size of all
6041 // sidx atoms.
6042 // This would be much simpler if we'd only write one sidx
6043 // atom, for the first track in the moof.
6044
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (round == 0) {
6045
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6046 return ret;
6047 } else {
6048 24 avio_buf = pb;
6049 }
6050
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 48 times.
126 for (i = 0; i < mov->nb_tracks; i++) {
6051 78 MOVTrack *track = &mov->tracks[i];
6052
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78 if (tracks >= 0 && i != tracks)
6053 continue;
6054 // When writing a sidx for the full file, entry is 0, but
6055 // we want to include all tracks. ref_size is 0 in this case,
6056 // since we read it from frag_info instead.
6057
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78 if (!track->entry && ref_size > 0)
6058 continue;
6059 78 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
6060 total_size);
6061 }
6062
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (round == 0) {
6063 24 total_size = ffio_close_null_buf(avio_buf);
6064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (total_size < 0)
6065 return total_size;
6066 }
6067 }
6068 24 return 0;
6069 }
6070
6071 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
6072 {
6073 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
6074 MOVTrack *first_track;
6075 int flags = 24;
6076
6077 /* PRFT should be associated with at most one track. So, choosing only the
6078 * first track. */
6079 if (tracks > 0)
6080 return 0;
6081 first_track = &(mov->tracks[0]);
6082
6083 if (!first_track->entry) {
6084 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
6085 return 0;
6086 }
6087
6088 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
6089 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
6090 return 0;
6091 }
6092
6093 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
6094 if (first_track->cluster[0].prft.wallclock) {
6095 /* Round the NTP time to whole milliseconds. */
6096 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
6097 NTP_OFFSET_US);
6098 flags = first_track->cluster[0].prft.flags;
6099 } else
6100 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
6101 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
6102 pts_us = av_rescale_q(first_track->cluster[0].pts,
6103 first_track->st->time_base, AV_TIME_BASE_Q);
6104 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
6105 } else {
6106 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
6107 mov->write_prft);
6108 return 0;
6109 }
6110
6111 avio_wb32(pb, 0); // Size place holder
6112 ffio_wfourcc(pb, "prft"); // Type
6113 avio_w8(pb, 1); // Version
6114 avio_wb24(pb, flags); // Flags
6115 avio_wb32(pb, first_track->track_id); // reference track ID
6116 avio_wb64(pb, ntp_ts); // NTP time stamp
6117 avio_wb64(pb, first_track->cluster[0].pts); //media time
6118 return update_size(pb, pos);
6119 }
6120
6121 119 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
6122 int64_t mdat_size)
6123 {
6124 AVIOContext *avio_buf;
6125 int ret, moof_size;
6126
6127
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
119 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6128 return ret;
6129 119 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
6130 119 moof_size = ffio_close_null_buf(avio_buf);
6131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (moof_size < 0)
6132 return moof_size;
6133
6134
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 94 times.
119 if (mov->flags & FF_MOV_FLAG_DASH &&
6135
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
25 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
6136 24 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
6137
6138
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
119 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
6139 mov_write_prft_tag(pb, mov, tracks);
6140
6141
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
6142
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 118 times.
119 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
6143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->ism_lookahead) {
6144
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
118 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
6145 return ret;
6146
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
6147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
6148 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
6149 }
6150 }
6151
6152 119 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
6153 }
6154
6155 68 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
6156 {
6157 68 int64_t pos = avio_tell(pb);
6158 int i;
6159
6160 68 avio_wb32(pb, 0); /* size placeholder */
6161 68 ffio_wfourcc(pb, "tfra");
6162 68 avio_w8(pb, 1); /* version */
6163 68 avio_wb24(pb, 0);
6164
6165 68 avio_wb32(pb, track->track_id);
6166 68 avio_wb32(pb, 0); /* length of traf/trun/sample num */
6167 68 avio_wb32(pb, track->nb_frag_info);
6168
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 68 times.
240 for (i = 0; i < track->nb_frag_info; i++) {
6169 172 avio_wb64(pb, track->frag_info[i].time);
6170 172 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
6171 172 avio_w8(pb, 1); /* traf number */
6172 172 avio_w8(pb, 1); /* trun number */
6173 172 avio_w8(pb, 1); /* sample number */
6174 }
6175
6176 68 return update_size(pb, pos);
6177 }
6178
6179 39 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
6180 {
6181 AVIOContext *mfra_pb;
6182 int i, ret, sz;
6183 uint8_t *buf;
6184
6185 39 ret = avio_open_dyn_buf(&mfra_pb);
6186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0)
6187 return ret;
6188
6189 39 avio_wb32(mfra_pb, 0); /* size placeholder */
6190 39 ffio_wfourcc(mfra_pb, "mfra");
6191 /* An empty mfra atom is enough to indicate to the publishing point that
6192 * the stream has ended. */
6193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (mov->flags & FF_MOV_FLAG_ISML)
6194 goto done_mfra;
6195
6196
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 39 times.
111 for (i = 0; i < mov->nb_tracks; i++) {
6197 72 MOVTrack *track = &mov->tracks[i];
6198
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (track->nb_frag_info)
6199 68 mov_write_tfra_tag(mfra_pb, track);
6200 }
6201
6202 39 avio_wb32(mfra_pb, 16);
6203 39 ffio_wfourcc(mfra_pb, "mfro");
6204 39 avio_wb32(mfra_pb, 0); /* version + flags */
6205 39 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
6206
6207 39 done_mfra:
6208
6209 39 sz = update_size(mfra_pb, 0);
6210 39 ret = avio_get_dyn_buf(mfra_pb, &buf);
6211 39 avio_write(pb, buf, ret);
6212 39 ffio_free_dyn_buf(&mfra_pb);
6213
6214 39 return sz;
6215 }
6216
6217 205 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
6218 {
6219 205 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
6220
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 55 times.
205 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
6221
6222 205 mov->mdat_pos = avio_tell(pb);
6223 205 avio_wb32(pb, 0); /* size placeholder*/
6224 205 ffio_wfourcc(pb, "mdat");
6225 205 return 0;
6226 }
6227
6228 498 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
6229 int has_h264, int has_video, int write_minor)
6230 {
6231 498 MOVMuxContext *mov = s->priv_data;
6232 498 int minor = 0x200;
6233
6234
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (mov->major_brand && strlen(mov->major_brand) >= 4)
6235 ffio_wfourcc(pb, mov->major_brand);
6236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 else if (mov->mode == MODE_3GP) {
6237 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
6238 minor = has_h264 ? 0x100 : 0x200;
6239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 } else if (mov->mode == MODE_AVIF) {
6240 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
6241 minor = 0;
6242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 } else if (mov->mode & MODE_3G2) {
6243 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
6244 minor = has_h264 ? 0x20000 : 0x10000;
6245
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 496 times.
498 } else if (mov->mode == MODE_PSP)
6246 2 ffio_wfourcc(pb, "MSNV");
6247
4/4
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 106 times.
496 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
6248
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 66 times.
74 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6249 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
6250
4/4
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 142 times.
488 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6251 30 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
6252
3/4
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 142 times.
458 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6253 ffio_wfourcc(pb, "iso4");
6254
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 316 times.
458 else if (mov->mode == MODE_MP4)
6255 142 ffio_wfourcc(pb, "isom");
6256
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 314 times.
316 else if (mov->mode == MODE_IPOD)
6257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6258
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 304 times.
314 else if (mov->mode == MODE_ISM)
6259 10 ffio_wfourcc(pb, "isml");
6260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 304 times.
304 else if (mov->mode == MODE_F4V)
6261 ffio_wfourcc(pb, "f4v ");
6262 else
6263 304 ffio_wfourcc(pb, "qt ");
6264
6265
2/2
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 249 times.
498 if (write_minor)
6266 249 avio_wb32(pb, minor);
6267 498 }
6268
6269 249 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6270 {
6271 249 MOVMuxContext *mov = s->priv_data;
6272 249 int64_t pos = avio_tell(pb);
6273 249 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6274 249 int has_iamf = 0;
6275
6276 #if CONFIG_IAMFENC
6277
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 244 times.
249 for (int i = 0; i < s->nb_stream_groups; i++) {
6278 5 const AVStreamGroup *stg = s->stream_groups[i];
6279
6280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6281 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6282 5 has_iamf = 1;
6283 5 break;
6284 }
6285 }
6286 #endif
6287
2/2
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 249 times.
562 for (int i = 0; i < mov->nb_streams; i++) {
6288 313 AVStream *st = mov->tracks[i].st;
6289
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 311 times.
313 if (is_cover_image(st))
6290 2 continue;
6291
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 108 times.
311 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6292 203 has_video = 1;
6293
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 273 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6294 38 has_h264 = 1;
6295
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 309 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6296 2 has_av1 = 1;
6297
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 6 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6298
2/2
✓ Branch 0 taken 301 times.
✓ Branch 1 taken 4 times.
305 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6299
3/4
✓ Branch 0 taken 301 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 299 times.
602 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6300 301 av_packet_side_data_get(st->codecpar->coded_side_data,
6301 301 st->codecpar->nb_coded_side_data,
6302 AV_PKT_DATA_DOVI_CONF))
6303 12 has_dolby = 1;
6304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 311 times.
311 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6305 has_id3 = 1;
6306 }
6307
6308 249 avio_wb32(pb, 0); /* size */
6309 249 ffio_wfourcc(pb, "ftyp");
6310
6311 // Write major brand
6312 249 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6313 // Write the major brand as the first compatible brand as well
6314 249 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6315
6316 // Write compatible brands, ensuring that we don't write the major brand as a
6317 // compatible brand a second time.
6318
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 244 times.
249 if (mov->mode == MODE_ISM) {
6319 5 ffio_wfourcc(pb, "piff");
6320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 } else if (mov->mode == MODE_AVIF) {
6321 const AVPixFmtDescriptor *pix_fmt_desc =
6322 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6323 const int depth = pix_fmt_desc->comp[0].depth;
6324 if (mov->is_animated_avif) {
6325 // For animated AVIF, major brand is "avis". Add "avif" as a
6326 // compatible brand.
6327 ffio_wfourcc(pb, "avif");
6328 ffio_wfourcc(pb, "msf1");
6329 ffio_wfourcc(pb, "iso8");
6330 }
6331 ffio_wfourcc(pb, "mif1");
6332 ffio_wfourcc(pb, "miaf");
6333 if (depth == 8 || depth == 10) {
6334 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6335 // computing that is based on chroma subsampling type. 420 chroma
6336 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6337 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6338 // 444 chroma subsampling.
6339 ffio_wfourcc(pb, "MA1A");
6340 } else {
6341 // 420 chroma subsampling.
6342 ffio_wfourcc(pb, "MA1B");
6343 }
6344 }
6345
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 152 times.
244 } else if (mov->mode != MODE_MOV) {
6346 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6347 // brand, if not already the major brand. This is compatible with users that
6348 // don't understand tfdt.
6349
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 2 times.
92 if (mov->mode == MODE_MP4) {
6350
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 88 times.
90 if (mov->flags & FF_MOV_FLAG_CMAF)
6351 2 ffio_wfourcc(pb, "cmfc");
6352
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 4 times.
90 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6353 33 ffio_wfourcc(pb, "iso6");
6354
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 88 times.
90 if (has_av1)
6355 2 ffio_wfourcc(pb, "av01");
6356
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 79 times.
90 if (has_dolby)
6357 11 ffio_wfourcc(pb, "dby1");
6358
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 85 times.
90 if (has_iamf)
6359 5 ffio_wfourcc(pb, "iamf");
6360 } else {
6361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6362 ffio_wfourcc(pb, "iso6");
6363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6364 ffio_wfourcc(pb, "iso5");
6365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6366 ffio_wfourcc(pb, "iso4");
6367 }
6368 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6369
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 17 times.
92 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6370 // write isom for mp4 only if it it's not the major brand already.
6371
4/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 71 times.
75 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6372 4 ffio_wfourcc(pb, "isom");
6373 75 ffio_wfourcc(pb, "iso2");
6374
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 51 times.
75 if (has_h264)
6375 24 ffio_wfourcc(pb, "avc1");
6376 }
6377 }
6378
6379
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 159 times.
249 if (mov->mode == MODE_MP4)
6380 90 ffio_wfourcc(pb, "mp41");
6381
6382
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 235 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
249 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6383 ffio_wfourcc(pb, "dash");
6384
6385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (has_id3)
6386 ffio_wfourcc(pb, "aid3");
6387
6388 249 return update_size(pb, pos);
6389 }
6390
6391 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6392 {
6393 1 AVStream *video_st = s->streams[0];
6394 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6395 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6396 1 int audio_rate = audio_par->sample_rate;
6397 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6398
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 :
6399 0;
6400 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6401 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6402
6403
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) {
6404 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6405 return AVERROR(EINVAL);
6406 }
6407
6408 1 avio_wb32(pb, 0x94); /* size */
6409 1 ffio_wfourcc(pb, "uuid");
6410 1 ffio_wfourcc(pb, "PROF");
6411
6412 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6413 1 avio_wb32(pb, 0xbb88695c);
6414 1 avio_wb32(pb, 0xfac9c740);
6415
6416 1 avio_wb32(pb, 0x0); /* ? */
6417 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6418
6419 1 avio_wb32(pb, 0x14); /* size */
6420 1 ffio_wfourcc(pb, "FPRF");
6421 1 avio_wb32(pb, 0x0); /* ? */
6422 1 avio_wb32(pb, 0x0); /* ? */
6423 1 avio_wb32(pb, 0x0); /* ? */
6424
6425 1 avio_wb32(pb, 0x2c); /* size */
6426 1 ffio_wfourcc(pb, "APRF"); /* audio */
6427 1 avio_wb32(pb, 0x0);
6428 1 avio_wb32(pb, 0x2); /* TrackID */
6429 1 ffio_wfourcc(pb, "mp4a");
6430 1 avio_wb32(pb, 0x20f);
6431 1 avio_wb32(pb, 0x0);
6432 1 avio_wb32(pb, audio_kbitrate);
6433 1 avio_wb32(pb, audio_kbitrate);
6434 1 avio_wb32(pb, audio_rate);
6435 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6436
6437 1 avio_wb32(pb, 0x34); /* size */
6438 1 ffio_wfourcc(pb, "VPRF"); /* video */
6439 1 avio_wb32(pb, 0x0);
6440 1 avio_wb32(pb, 0x1); /* TrackID */
6441
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6442 1 ffio_wfourcc(pb, "avc1");
6443 1 avio_wb16(pb, 0x014D);
6444 1 avio_wb16(pb, 0x0015);
6445 } else {
6446 ffio_wfourcc(pb, "mp4v");
6447 avio_wb16(pb, 0x0000);
6448 avio_wb16(pb, 0x0103);
6449 }
6450 1 avio_wb32(pb, 0x0);
6451 1 avio_wb32(pb, video_kbitrate);
6452 1 avio_wb32(pb, video_kbitrate);
6453 1 avio_wb32(pb, frame_rate);
6454 1 avio_wb32(pb, frame_rate);
6455 1 avio_wb16(pb, video_par->width);
6456 1 avio_wb16(pb, video_par->height);
6457 1 avio_wb32(pb, 0x010001); /* ? */
6458
6459 1 return 0;
6460 }
6461
6462 249 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6463 {
6464 249 MOVMuxContext *mov = s->priv_data;
6465 int i;
6466
6467 249 mov_write_ftyp_tag(pb,s);
6468
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 248 times.
249 if (mov->mode == MODE_PSP) {
6469 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6470
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6471 2 AVStream *st = mov->tracks[i].st;
6472
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6473 continue;
6474
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6475 1 video_streams_nb++;
6476
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6477 1 audio_streams_nb++;
6478 else
6479 other_streams_nb++;
6480 }
6481
6482
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) {
6483 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6484 return AVERROR(EINVAL);
6485 }
6486 1 return mov_write_uuidprof_tag(pb, s);
6487 }
6488 248 return 0;
6489 }
6490
6491 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6492 {
6493 8 uint32_t c = -1;
6494 8 int i, closed_gop = 0;
6495
6496
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6497 368 c = (c << 8) + pkt->data[i];
6498
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6499 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6500
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6501 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6502
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
6503 8 *flags = MOV_SYNC_SAMPLE;
6504 else
6505 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6506 8 break;
6507 }
6508 }
6509 8 return 0;
6510 }
6511
6512 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6513 {
6514 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6515 int seq = 0, entry = 0;
6516 int key = pkt->flags & AV_PKT_FLAG_KEY;
6517 start = find_next_marker(pkt->data, end);
6518 for (next = start; next < end; start = next) {
6519 next = find_next_marker(start + 4, end);
6520 switch (AV_RB32(start)) {
6521 case VC1_CODE_SEQHDR:
6522 seq = 1;
6523 break;
6524 case VC1_CODE_ENTRYPOINT:
6525 entry = 1;
6526 break;
6527 case VC1_CODE_SLICE:
6528 trk->vc1_info.slices = 1;
6529 break;
6530 }
6531 }
6532 if (!trk->entry && trk->vc1_info.first_packet_seen)
6533 trk->vc1_info.first_frag_written = 1;
6534 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6535 /* First packet in first fragment */
6536 trk->vc1_info.first_packet_seq = seq;
6537 trk->vc1_info.first_packet_entry = entry;
6538 trk->vc1_info.first_packet_seen = 1;
6539 } else if ((seq && !trk->vc1_info.packet_seq) ||
6540 (entry && !trk->vc1_info.packet_entry)) {
6541 int i;
6542 for (i = 0; i < trk->entry; i++)
6543 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6544 trk->has_keyframes = 0;
6545 if (seq)
6546 trk->vc1_info.packet_seq = 1;
6547 if (entry)
6548 trk->vc1_info.packet_entry = 1;
6549 if (!trk->vc1_info.first_frag_written) {
6550 /* First fragment */
6551 if ((!seq || trk->vc1_info.first_packet_seq) &&
6552 (!entry || trk->vc1_info.first_packet_entry)) {
6553 /* First packet had the same headers as this one, readd the
6554 * sync sample flag. */
6555 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6556 trk->has_keyframes = 1;
6557 }
6558 }
6559 }
6560 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6561 key = seq && entry;
6562 else if (trk->vc1_info.packet_seq)
6563 key = seq;
6564 else if (trk->vc1_info.packet_entry)
6565 key = entry;
6566 if (key) {
6567 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6568 trk->has_keyframes++;
6569 }
6570 }
6571
6572 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6573 {
6574 int length;
6575
6576 if (pkt->size < 8)
6577 return;
6578
6579 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6580 if (length < 8 || length > pkt->size)
6581 return;
6582
6583 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6584 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6585 trk->has_keyframes++;
6586 }
6587
6588 return;
6589 }
6590
6591 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6592 {
6593 89 MOVMuxContext *mov = s->priv_data;
6594 int ret, buf_size;
6595 uint8_t *buf;
6596 int i, offset;
6597
6598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if (!track->mdat_buf)
6599 return 0;
6600
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!mov->mdat_buf) {
6601
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6602 return ret;
6603 }
6604 89 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6605
6606 89 offset = avio_tell(mov->mdat_buf);
6607 89 avio_write(mov->mdat_buf, buf, buf_size);
6608 89 ffio_reset_dyn_buf(track->mdat_buf);
6609
6610
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 89 times.
177 for (i = track->entries_flushed; i < track->entry; i++)
6611 88 track->cluster[i].pos += offset;
6612 89 track->entries_flushed = track->entry;
6613 89 return 0;
6614 }
6615
6616 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6617 {
6618 28 MOVMuxContext *mov = s->priv_data;
6619 28 AVPacket *squashed_packet = mov->pkt;
6620 28 int ret = AVERROR_BUG;
6621
6622
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6623 28 case AV_CODEC_ID_TTML: {
6624 28 int had_packets = !!track->squashed_packet_queue.head;
6625
6626
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = ff_mov_generate_squashed_ttml_packet(s, track, squashed_packet)) < 0) {
6627 goto finish_squash;
6628 }
6629
6630 // We have generated a padding packet (no actual input packets in
6631 // queue) and its duration is zero. Skipping writing it.
6632
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
28 if (!had_packets && squashed_packet->duration == 0) {
6633 goto finish_squash;
6634 }
6635
6636 28 track->end_reliable = 1;
6637 28 break;
6638 }
6639 default:
6640 ret = AVERROR(EINVAL);
6641 goto finish_squash;
6642 }
6643
6644 28 squashed_packet->stream_index = track->st->index;
6645
6646 28 ret = mov_write_single_packet(s, squashed_packet);
6647
6648 28 finish_squash:
6649 28 av_packet_unref(squashed_packet);
6650
6651 28 return ret;
6652 }
6653
6654 398 static int mov_write_squashed_packets(AVFormatContext *s)
6655 {
6656 398 MOVMuxContext *mov = s->priv_data;
6657
6658
2/2
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 398 times.
973 for (int i = 0; i < mov->nb_streams; i++) {
6659 575 MOVTrack *track = &mov->tracks[i];
6660 575 int ret = AVERROR_BUG;
6661
6662
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 545 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
575 if (track->squash_fragment_samples_to_one && !track->entry) {
6663
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6664 av_log(s, AV_LOG_ERROR,
6665 "Failed to write squashed packet for %s stream with "
6666 "index %d and track id %d. Error: %s\n",
6667 avcodec_get_name(track->st->codecpar->codec_id),
6668 track->st->index, track->track_id,
6669 av_err2str(ret));
6670 return ret;
6671 }
6672 }
6673 }
6674
6675 398 return 0;
6676 }
6677
6678 189 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6679 int64_t ref_pos)
6680 {
6681 int i;
6682
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 187 times.
189 if (!track->entry)
6683 2 return 0;
6684
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 179 times.
187 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6685
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6686 124 track->cluster[i].pos += ref_pos + track->data_offset;
6687
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6688 // First flush. Chunking for this fragment may already have been
6689 // done, either if we didn't use empty_moov, or if we did use
6690 // delay_moov. In either case, reset chunking here.
6691
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6692 63 track->cluster[i].chunkNum = 0;
6693 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6694 }
6695 }
6696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6697 8 track->entry_written + track->entry,
6698 sizeof(*track->cluster)))
6699 return AVERROR(ENOMEM);
6700 8 memcpy(&track->cluster_written[track->entry_written],
6701 8 track->cluster, track->entry * sizeof(*track->cluster));
6702 8 track->entry_written += track->entry;
6703 }
6704 187 track->entry = 0;
6705 187 track->entries_flushed = 0;
6706 187 track->end_reliable = 0;
6707 187 return 0;
6708 }
6709
6710 151 static int mov_flush_fragment(AVFormatContext *s, int force)
6711 {
6712 151 MOVMuxContext *mov = s->priv_data;
6713 151 int i, first_track = -1;
6714 151 int64_t mdat_size = 0, mdat_start = 0;
6715 int ret;
6716 151 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6717
6718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6719 return 0;
6720
6721 // Check if we have any tracks that require squashing.
6722 // In that case, we'll have to write the packet here.
6723
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 151 times.
151 if ((ret = mov_write_squashed_packets(s)) < 0)
6724 return ret;
6725
6726 // Try to fill in the duration of the last packet in each stream
6727 // from queued packets in the interleave queues. If the flushing
6728 // of fragments was triggered automatically by an AVPacket, we
6729 // already have reliable info for the end of that track, but other
6730 // tracks may need to be filled in.
6731
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 151 times.
417 for (i = 0; i < mov->nb_streams; i++) {
6732 266 MOVTrack *track = &mov->tracks[i];
6733
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 90 times.
266 if (!track->end_reliable) {
6734 176 const AVPacket *pkt = ff_interleaved_peek(s, i);
6735
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 170 times.
176 if (pkt) {
6736 int64_t offset, dts, pts;
6737 6 ff_get_muxer_ts_offset(s, i, &offset);
6738 6 pts = pkt->pts + offset;
6739 6 dts = pkt->dts + offset;
6740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6741 dts += track->dts_shift;
6742 6 track->track_duration = dts - track->start_dts;
6743
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6744 6 track->end_pts = pts;
6745 else
6746 track->end_pts = dts;
6747
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
6748 6 track->elst_end_pts = track->end_pts;
6749 }
6750 }
6751 }
6752
6753
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 151 times.
423 for (i = 0; i < mov->nb_tracks; i++) {
6754 272 MOVTrack *track = &mov->tracks[i];
6755
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 185 times.
272 if (track->entry <= 1)
6756 87 continue;
6757 // Sample durations are calculated as the diff of dts values,
6758 // but for the last sample in a fragment, we don't know the dts
6759 // of the first sample in the next fragment, so we have to rely
6760 // on what was set as duration in the AVPacket. Not all callers
6761 // set this though, so we might want to replace it with an
6762 // estimate if it currently is zero.
6763
2/2
✓ Branch 1 taken 183 times.
✓ Branch 2 taken 2 times.
185 if (get_cluster_duration(track, track->entry - 1) != 0)
6764 183 continue;
6765 // Use the duration (i.e. dts diff) of the second last sample for
6766 // the last one. This is a wild guess (and fatal if it turns out
6767 // to be too long), but probably the best we can do - having a zero
6768 // duration is bad as well.
6769 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6770 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6771
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6772 2 av_log(s, AV_LOG_WARNING,
6773 "Estimating the duration of the last packet in a "
6774 "fragment, consider setting the duration field in "
6775 "AVPacket instead.\n");
6776 2 mov->missing_duration_warned = 1;
6777 }
6778 }
6779
6780
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 122 times.
151 if (!mov->moov_written) {
6781 29 int64_t pos = avio_tell(s->pb);
6782 uint8_t *buf;
6783 int buf_size, moov_size;
6784
6785
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 22 times.
73 for (i = 0; i < mov->nb_tracks; i++)
6786
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 44 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
51 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6787 7 break;
6788 /* Don't write the initial moov unless all tracks have data */
6789
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
29 if (i < mov->nb_tracks && !force)
6790 4 return 0;
6791
6792 25 moov_size = get_moov_size(s);
6793
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 25 times.
71 for (i = 0; i < mov->nb_tracks; i++)
6794 46 mov->tracks[i].data_offset = pos + moov_size + 8;
6795
6796 25 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6797
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6798
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6799 20 mov_write_identification(s->pb, s);
6800
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6801 return ret;
6802
6803
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6805 mov->reserved_header_pos = avio_tell(s->pb);
6806 20 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6807 20 mov->moov_written = 1;
6808 20 return 0;
6809 }
6810
6811
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (mov->mdat_buf) {
6812 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6813 4 avio_wb32(s->pb, buf_size + 8);
6814 4 ffio_wfourcc(s->pb, "mdat");
6815 4 avio_write(s->pb, buf, buf_size);
6816 4 ffio_reset_dyn_buf(mov->mdat_buf);
6817 }
6818
6819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6820 mov->reserved_header_pos = avio_tell(s->pb);
6821
6822 5 mov->moov_written = 1;
6823 5 mov->mdat_size = 0;
6824
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (i = 0; i < mov->nb_tracks; i++)
6825 10 mov_finish_fragment(mov, &mov->tracks[i], 0);
6826 5 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6827 5 return 0;
6828 }
6829
6830
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 120 times.
122 if (mov->frag_interleave) {
6831
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6832 4 MOVTrack *track = &mov->tracks[i];
6833 int ret;
6834
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6835 return ret;
6836 }
6837
6838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6839 return 0;
6840 2 mdat_size = avio_tell(mov->mdat_buf);
6841 }
6842
6843
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 122 times.
342 for (i = 0; i < mov->nb_tracks; i++) {
6844 220 MOVTrack *track = &mov->tracks[i];
6845
4/4
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 171 times.
220 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6846 49 track->data_offset = 0;
6847 else
6848 171 track->data_offset = mdat_size;
6849
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 110 times.
220 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6850 110 has_video = 1;
6851
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 if (first_video_track) {
6852
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 16 times.
110 if (track->entry)
6853 94 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6854 110 first_video_track = 0;
6855 }
6856 }
6857
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 179 times.
220 if (!track->entry)
6858 41 continue;
6859
1/2
✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
179 if (track->mdat_buf)
6860 179 mdat_size += avio_tell(track->mdat_buf);
6861
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 77 times.
179 if (first_track < 0)
6862 102 first_track = i;
6863 }
6864
6865
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 102 times.
122 if (!mdat_size)
6866 20 return 0;
6867
6868
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 4 times.
102 avio_write_marker(s->pb,
6869 102 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6870
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 7 times.
102 (has_video ? starts_with_key : mov->tracks[first_track].cluster[0].flags & MOV_SYNC_SAMPLE) ? AVIO_DATA_MARKER_SYNC_POINT : AVIO_DATA_MARKER_BOUNDARY_POINT);
6871
6872
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 102 times.
289 for (i = first_track; i < mov->nb_tracks; i++) {
6873 187 MOVTrack *track = &mov->tracks[i];
6874 187 int buf_size, write_moof = 1, moof_tracks = -1;
6875 uint8_t *buf;
6876
6877
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 179 times.
187 if (!track->entry)
6878 8 continue;
6879
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 138 times.
179 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6880 41 mdat_size = avio_tell(track->mdat_buf);
6881 41 moof_tracks = i;
6882 } else {
6883 138 write_moof = i == first_track;
6884 }
6885
6886
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 60 times.
179 if (write_moof) {
6887 119 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6888
6889 119 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6890 119 mov->fragments++;
6891
6892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (track->cenc.aes_ctr)
6893 ff_mov_cenc_flush(&track->cenc);
6894
6895 119 avio_wb32(s->pb, mdat_size + 8);
6896 119 ffio_wfourcc(s->pb, "mdat");
6897 119 mdat_start = avio_tell(s->pb);
6898 }
6899
6900 179 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6901
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 3 times.
179 if (!mov->frag_interleave) {
6902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176 times.
176 if (!track->mdat_buf)
6903 continue;
6904 176 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6905 176 avio_write(s->pb, buf, buf_size);
6906 176 ffio_reset_dyn_buf(track->mdat_buf);
6907 } else {
6908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!mov->mdat_buf)
6909 continue;
6910 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6911 3 avio_write(s->pb, buf, buf_size);
6912 3 ffio_reset_dyn_buf(mov->mdat_buf);
6913 }
6914 }
6915
6916 102 mov->mdat_size = 0;
6917
6918 102 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6919 102 return 0;
6920 }
6921
6922 97 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6923 {
6924 97 MOVMuxContext *mov = s->priv_data;
6925 97 int had_moov = mov->moov_written;
6926 97 int ret = mov_flush_fragment(s, force);
6927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (ret < 0)
6928 return ret;
6929 // If using delay_moov, the first flush only wrote the moov,
6930 // not the actual moof+mdat pair, thus flush once again.
6931
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
97 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6932 10 ret = mov_flush_fragment(s, force);
6933 97 return ret;
6934 }
6935
6936 46163 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6937 {
6938 int64_t ref;
6939 uint64_t duration;
6940
6941
2/2
✓ Branch 0 taken 45367 times.
✓ Branch 1 taken 796 times.
46163 if (trk->entry) {
6942 45367 ref = trk->cluster[trk->entry - 1].dts;
6943
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 604 times.
796 } else if ( trk->start_dts != AV_NOPTS_VALUE
6944
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 8 times.
192 && !trk->frag_discont) {
6945 184 ref = trk->start_dts + trk->track_duration;
6946 } else
6947 612 ref = pkt->dts; // Skip tests for the first packet
6948
6949
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 42108 times.
46163 if (trk->dts_shift != AV_NOPTS_VALUE) {
6950 /* With negative CTS offsets we have set an offset to the DTS,
6951 * reverse this for the check. */
6952 4055 ref -= trk->dts_shift;
6953 }
6954
6955 46163 duration = pkt->dts - ref;
6956
2/4
✓ Branch 0 taken 46163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46163 times.
46163 if (pkt->dts < ref || duration >= INT_MAX) {
6957 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6958 duration, pkt->dts, pkt->stream_index);
6959
6960 pkt->dts = ref + 1;
6961 pkt->pts = AV_NOPTS_VALUE;
6962 }
6963
6964
2/4
✓ Branch 0 taken 46163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46163 times.
46163 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6965 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6966 return AVERROR(EINVAL);
6967 }
6968 46163 return 0;
6969 }
6970
6971 6 int ff_mov_set_fragment_end_hint(AVFormatContext *s, int stream_index,
6972 const AVPacket *pkt, AVRational src_time_base)
6973 {
6974 6 MOVMuxContext *mov = s->priv_data;
6975 AVStream *st;
6976 MOVTrack *track;
6977 int64_t offset, dts, pts, candidate_duration;
6978
6979
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
6980
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 stream_index < 0 || stream_index >= s->nb_streams ||
6981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 pkt->dts == AV_NOPTS_VALUE)
6982 return 0;
6983
6984 6 st = s->streams[stream_index];
6985 6 track = st->priv_data;
6986
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!track->entry || track->start_dts == AV_NOPTS_VALUE)
6987 return 0;
6988
6989
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (ff_get_muxer_ts_offset(s, stream_index, &offset) < 0)
6990 return 0;
6991
6992 6 dts = av_rescale_q(pkt->dts, src_time_base, st->time_base) + offset;
6993 12 pts = pkt->pts == AV_NOPTS_VALUE
6994 ? AV_NOPTS_VALUE
6995
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 : av_rescale_q(pkt->pts, src_time_base, st->time_base) + offset;
6996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6997 dts += track->dts_shift;
6998
6999 6 candidate_duration = dts - track->start_dts;
7000
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (dts <= track->cluster[track->entry - 1].dts ||
7001
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 candidate_duration < 0 || candidate_duration >= track->track_duration)
7002 6 return 0;
7003
7004 track->track_duration = candidate_duration;
7005 track->end_pts = pts != AV_NOPTS_VALUE ? pts : dts;
7006 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7007 track->elst_end_pts = track->end_pts;
7008 track->end_reliable = 1;
7009
7010 return 1;
7011 }
7012
7013 23100 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7014 {
7015 23100 MOVMuxContext *mov = s->priv_data;
7016 23100 AVIOContext *pb = s->pb;
7017 MOVTrack *trk;
7018 AVCodecParameters *par;
7019 AVProducerReferenceTime *prft;
7020 23100 unsigned int samples_in_chunk = 0;
7021 int64_t duration;
7022 23100 int size = pkt->size, ret = 0, offset = 0;
7023 size_t prft_size;
7024 23100 uint8_t *reformatted_data = NULL;
7025
7026
2/2
✓ Branch 0 taken 23054 times.
✓ Branch 1 taken 46 times.
23100 if (pkt->stream_index < s->nb_streams)
7027 23054 trk = s->streams[pkt->stream_index]->priv_data;
7028 else // Timecode or chapter
7029 46 trk = &mov->tracks[pkt->stream_index];
7030 23100 par = trk->par;
7031
7032 23100 ret = check_pkt(s, trk, pkt);
7033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 if (ret < 0)
7034 return ret;
7035
7036
2/2
✓ Branch 0 taken 22479 times.
✓ Branch 1 taken 621 times.
23100 if (pkt->pts != AV_NOPTS_VALUE &&
7037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22479 times.
22479 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
7038 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
7039 return AVERROR_PATCHWELCOME;
7040 }
7041
7042
3/4
✓ Branch 0 taken 16492 times.
✓ Branch 1 taken 6608 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16492 times.
23100 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
7043 int ret;
7044
4/4
✓ Branch 0 taken 2176 times.
✓ Branch 1 taken 4432 times.
✓ Branch 2 taken 1938 times.
✓ Branch 3 taken 238 times.
6608 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
7045
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 6282 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
6370 if (mov->frag_interleave && mov->fragments > 0) {
7046
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
7047
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
7048 return ret;
7049 }
7050 }
7051
7052
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 6297 times.
6370 if (!trk->mdat_buf) {
7053
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
73 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
7054 return ret;
7055 }
7056 6370 pb = trk->mdat_buf;
7057 } else {
7058
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
7059
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
7060 return ret;
7061 }
7062 238 pb = mov->mdat_buf;
7063 }
7064 }
7065
7066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
7067 /* We must find out how many AMR blocks there are in one packet */
7068 static const uint16_t packed_size[16] =
7069 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
7070 int len = 0;
7071
7072 while (len < size && samples_in_chunk < 100) {
7073 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
7074 samples_in_chunk++;
7075 }
7076 if (samples_in_chunk > 1) {
7077 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
7078 return -1;
7079 }
7080
1/2
✓ Branch 0 taken 23100 times.
✗ Branch 1 not taken.
23100 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
7081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
7082 samples_in_chunk = trk->par->frame_size;
7083
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 21686 times.
23100 } else if (trk->sample_size)
7084 1414 samples_in_chunk = size / trk->sample_size;
7085 else
7086 21686 samples_in_chunk = 1;
7087
7088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23100 times.
23100 if (samples_in_chunk < 1) {
7089 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
7090 return AVERROR_PATCHWELCOME;
7091 }
7092
7093 /* copy extradata if it exists */
7094
3/4
✓ Branch 0 taken 7413 times.
✓ Branch 1 taken 15687 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7413 times.
23100 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
7095 !TAG_IS_AVCI(trk->tag) &&
7096 (par->codec_id != AV_CODEC_ID_DNXHD)) {
7097 trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
7098 if (!trk->extradata[0]) {
7099 ret = AVERROR(ENOMEM);
7100 goto err;
7101 }
7102 trk->extradata_size[0] = par->extradata_size;
7103 }
7104
7105
2/2
✓ Branch 0 taken 22985 times.
✓ Branch 1 taken 115 times.
23100 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
7106
2/2
✓ Branch 0 taken 20371 times.
✓ Branch 1 taken 2614 times.
22985 par->codec_id == AV_CODEC_ID_H264 ||
7107
2/2
✓ Branch 0 taken 19999 times.
✓ Branch 1 taken 372 times.
20371 par->codec_id == AV_CODEC_ID_HEVC ||
7108
2/2
✓ Branch 0 taken 19989 times.
✓ Branch 1 taken 10 times.
19999 par->codec_id == AV_CODEC_ID_VVC ||
7109
1/2
✓ Branch 0 taken 19989 times.
✗ Branch 1 not taken.
19989 par->codec_id == AV_CODEC_ID_VP9 ||
7110
2/2
✓ Branch 0 taken 19689 times.
✓ Branch 1 taken 300 times.
19989 par->codec_id == AV_CODEC_ID_EVC ||
7111
1/2
✓ Branch 0 taken 19689 times.
✗ Branch 1 not taken.
19689 par->codec_id == AV_CODEC_ID_LCEVC ||
7112
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19689 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3387 times.
23100 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
7113
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)) {
7114 /* copy frame to create needed atoms */
7115 24 trk->extradata_size[0] = size;
7116 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
7117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
7118 ret = AVERROR(ENOMEM);
7119 goto err;
7120 }
7121 24 memcpy(trk->extradata[0], pkt->data, size);
7122 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7123 }
7124
7125 23100 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
7126
4/6
✓ Branch 0 taken 23100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 23097 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
23100 if (pkt->size && sd && sd->size > 0) {
7127 int i;
7128
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < trk->stsd_count; i++) {
7129
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
7130 1 break;
7131 }
7132
7133
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (i < trk->stsd_count)
7134 1 trk->last_stsd_index = i;
7135
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (trk->stsd_count <= INT_MAX - 1) {
7136 2 int new_count = trk->stsd_count + 1;
7137 2 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
7138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata)
7139 return AVERROR(ENOMEM);
7140 2 trk->extradata = extradata;
7141
7142 2 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
7143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata_size)
7144 return AVERROR(ENOMEM);
7145 2 trk->extradata_size = extradata_size;
7146
7147 2 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
7148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->extradata[trk->stsd_count])
7149 return AVERROR(ENOMEM);
7150
7151 2 trk->extradata_size[trk->stsd_count] = sd->size;
7152 2 trk->last_stsd_index = trk->stsd_count;
7153 2 trk->stsd_count = new_count;
7154 } else
7155 return AVERROR(ENOMEM);
7156 }
7157
7158
3/4
✓ Branch 0 taken 8186 times.
✓ Branch 1 taken 14914 times.
✓ Branch 2 taken 8186 times.
✗ Branch 3 not taken.
23100 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
7159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8186 times.
8186 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
7160 if (!trk->st->nb_frames) {
7161 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
7162 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
7163 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
7164 return -1;
7165 }
7166 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
7167 }
7168
3/4
✓ Branch 0 taken 2614 times.
✓ Branch 1 taken 20486 times.
✓ Branch 2 taken 2614 times.
✗ Branch 3 not taken.
23100 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
7169
16/30
✓ Branch 0 taken 515 times.
✓ Branch 1 taken 2099 times.
✓ Branch 2 taken 515 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 515 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 515 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 515 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 515 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 515 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 515 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 515 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 515 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 515 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 515 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 515 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 515 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 515 times.
✗ Branch 29 not taken.
2614 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
7170 /* from x264 or from bytestream H.264 */
7171 /* NAL reformatting needed */
7172
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 515 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
515 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7173 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
7174 &size);
7175 if (ret < 0)
7176 return ret;
7177 avio_write(pb, reformatted_data, size);
7178 } else {
7179
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 498 times.
515 if (trk->cenc.aes_ctr) {
7180 17 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (size < 0) {
7182 ret = size;
7183 goto err;
7184 }
7185 } else {
7186 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7187 }
7188 }
7189
3/4
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 22213 times.
✓ Branch 2 taken 372 times.
✗ Branch 3 not taken.
22585 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7190
3/4
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 355 times.
✓ Branch 3 taken 17 times.
727 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7191 /* extradata is Annex B, assume the bitstream is too and convert it */
7192 355 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
7193
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
355 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7194 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
7195 &size, filter_ps, NULL);
7196 if (ret < 0)
7197 return ret;
7198 avio_write(pb, reformatted_data, size);
7199 } else {
7200
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 354 times.
355 if (trk->cenc.aes_ctr) {
7201 1 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (size < 0) {
7203 ret = size;
7204 goto err;
7205 }
7206 } else {
7207 354 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
7208 }
7209 }
7210
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 22220 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
22230 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7211
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7212 /* extradata is Annex B, assume the bitstream is too and convert it */
7213
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) {
7214 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
7215 &size, 0, NULL);
7216 if (ret < 0)
7217 return ret;
7218 avio_write(pb, reformatted_data, size);
7219 } else {
7220 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
7221 }
7222
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22220 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22220 } else if (par->codec_id == AV_CODEC_ID_LCEVC && trk->extradata_size[trk->last_stsd_index] > 0 &&
7223 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1) {
7224 /* extradata is Annex B, assume the bitstream is too and convert it */
7225 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7226 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size);
7227 if (ret < 0)
7228 return ret;
7229 avio_write(pb, reformatted_data, size);
7230 } else {
7231 if (trk->cenc.aes_ctr) {
7232 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7233 if (size < 0) {
7234 ret = size;
7235 goto err;
7236 }
7237 } else {
7238 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7239 }
7240 }
7241
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 22192 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 24 times.
22220 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
7242
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) {
7243 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
7244 &size, &offset);
7245 if (ret < 0)
7246 return ret;
7247 avio_write(pb, reformatted_data, size);
7248 } else {
7249 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
7250
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]) {
7251 mov->avif_extent_length[pkt->stream_index] = size;
7252 }
7253 }
7254
7255
2/2
✓ Branch 0 taken 21593 times.
✓ Branch 1 taken 623 times.
22216 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
7256
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 20479 times.
21593 par->codec_id == AV_CODEC_ID_EAC3) {
7257 1737 size = handle_eac3(mov, pkt, trk);
7258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (size < 0)
7259 return size;
7260
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1736 times.
1737 else if (!size)
7261 1 goto end;
7262 1736 avio_write(pb, pkt->data, size);
7263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20479 times.
20479 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
7264 size = 8;
7265
7266 for (int i = 0; i < pkt->size; i += 3) {
7267 if (pkt->data[i] == 0xFC) {
7268 size += 2;
7269 }
7270 }
7271 avio_wb32(pb, size);
7272 ffio_wfourcc(pb, "cdat");
7273 for (int i = 0; i < pkt->size; i += 3) {
7274 if (pkt->data[i] == 0xFC) {
7275 avio_w8(pb, pkt->data[i + 1]);
7276 avio_w8(pb, pkt->data[i + 2]);
7277 }
7278 }
7279
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20476 times.
20479 } else if (par->codec_id == AV_CODEC_ID_APV) {
7280 3 ff_isom_parse_apvc(trk->apv, pkt, s);
7281 3 avio_wb32(s->pb, pkt->size);
7282 3 size += 4;
7283
7284 3 avio_write(s->pb, pkt->data, pkt->size);
7285 } else {
7286
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 20443 times.
20476 if (trk->cenc.aes_ctr) {
7287 33 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
7288 33 int extradata_size = trk->extradata_size[trk->last_stsd_index];
7289
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
38 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
7290 5 int nal_size_length = (extradata[4] & 0x3) + 1;
7291 5 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7292
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
32 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
7293 4 int nal_size_length = (extradata[21] & 0x3) + 1;
7294 4 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 } else if(par->codec_id == AV_CODEC_ID_VVC) {
7296 ret = AVERROR_PATCHWELCOME;
7297
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if(par->codec_id == AV_CODEC_ID_AV1) {
7298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 av_assert0(size == pkt->size);
7299 24 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
7300
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (ret > 0) {
7301 24 size = ret;
7302 24 ret = 0;
7303 }
7304 } else {
7305 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
7306 }
7307
7308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
7309 goto err;
7310 }
7311 } else {
7312 20443 avio_write(pb, pkt->data, size);
7313 }
7314 }
7315
7316
2/2
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 22786 times.
23099 if (trk->entry >= trk->cluster_capacity) {
7317 313 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
7318 313 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
7319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (!cluster) {
7320 ret = AVERROR(ENOMEM);
7321 goto err;
7322 }
7323 313 trk->cluster = cluster;
7324 313 trk->cluster_capacity = new_capacity;
7325 }
7326
7327 23099 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7328 23099 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7329 23099 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7330 23099 trk->cluster[trk->entry].chunkNum = 0;
7331 23099 trk->cluster[trk->entry].size = size;
7332 23099 trk->cluster[trk->entry].entries = samples_in_chunk;
7333 23099 trk->cluster[trk->entry].dts = pkt->dts;
7334 23099 trk->cluster[trk->entry].pts = pkt->pts;
7335
2/2
✓ Branch 0 taken 23071 times.
✓ Branch 1 taken 28 times.
23099 if (!trk->squash_fragment_samples_to_one &&
7336
4/4
✓ Branch 0 taken 398 times.
✓ Branch 1 taken 22673 times.
✓ Branch 2 taken 103 times.
✓ Branch 3 taken 295 times.
23071 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7337
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 4 times.
103 if (!trk->frag_discont) {
7338 /* First packet of a new fragment. We already wrote the duration
7339 * of the last packet of the previous fragment based on track_duration,
7340 * which might not exactly match our dts. Therefore adjust the dts
7341 * of this packet to be what the previous packets duration implies. */
7342 99 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7343 /* We also may have written the pts and the corresponding duration
7344 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7345 * the next fragment. This means the cts of the first sample must
7346 * be the same in all fragments, unless end_pts was updated by
7347 * the packet causing the fragment to be written. */
7348
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 83 times.
99 if ((mov->flags & FF_MOV_FLAG_DASH &&
7349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7350
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 61 times.
83 mov->mode == MODE_ISM)
7351 38 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7352 } else {
7353 /* New fragment, but discontinuous from previous fragments.
7354 * Pretend the duration sum of the earlier fragments is
7355 * pkt->dts - trk->start_dts. */
7356 4 trk->end_pts = trk->elst_end_pts = AV_NOPTS_VALUE;
7357 4 trk->frag_discont = 0;
7358 }
7359 }
7360
7361
6/6
✓ Branch 0 taken 426 times.
✓ Branch 1 taken 22673 times.
✓ Branch 2 taken 299 times.
✓ Branch 3 taken 127 times.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 262 times.
23099 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7362
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 15 times.
37 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7363 /* Not using edit lists and shifting the first track to start from zero.
7364 * If the other streams start from a later timestamp, we won't be able
7365 * to signal the difference in starting time without an edit list.
7366 * Thus move the timestamp for this first sample to 0, increasing
7367 * its duration instead. */
7368 22 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7369 }
7370
2/2
✓ Branch 0 taken 277 times.
✓ Branch 1 taken 22822 times.
23099 if (trk->start_dts == AV_NOPTS_VALUE) {
7371 277 trk->start_dts = pkt->dts;
7372
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 271 times.
277 if (trk->frag_discont) {
7373
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7374 /* Pretend the whole stream started at pts=0, with earlier fragments
7375 * already written. If the stream started at pts=0, the duration sum
7376 * of earlier fragments would have been pkt->pts. */
7377 4 trk->start_dts = pkt->dts - pkt->pts;
7378 } else {
7379 /* Pretend the whole stream started at dts=0, with earlier fragments
7380 * already written, with a duration summing up to pkt->dts. */
7381 2 trk->start_dts = 0;
7382 }
7383 6 trk->frag_discont = 0;
7384
4/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 219 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 50 times.
271 } else if (pkt->dts && mov->moov_written)
7385 2 av_log(s, AV_LOG_WARNING,
7386 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7387 "already has been written. Set the delay_moov flag to handle "
7388 "this case.\n",
7389 pkt->stream_index, pkt->dts);
7390 }
7391
7392 23099 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
7393
5/6
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 23059 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 1 times.
23138 if (sd && sd->size >= 10 && trk->par->frame_size) {
7394
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
39 duration = FFMAX(av_rescale_q(trk->par->frame_size, (AVRational){ 1, trk->par->sample_rate },
7395 trk->st->time_base), pkt->duration);
7396
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (mov->use_editlist)
7397 39 pkt->duration = duration;
7398 39 duration -= av_rescale_q(AV_RL32(sd->data + 4), (AVRational){ 1, trk->par->sample_rate },
7399 39 trk->st->time_base);
7400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (duration < 0)
7401 return AVERROR_INVALIDDATA;
7402 } else
7403 23060 duration = pkt->duration;
7404
7405 23099 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7406 23099 trk->last_sample_is_subtitle_end = 0;
7407
7408
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 22478 times.
23099 if (pkt->pts == AV_NOPTS_VALUE) {
7409 621 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7410 621 pkt->pts = pkt->dts;
7411 }
7412
2/2
✓ Branch 0 taken 1401 times.
✓ Branch 1 taken 21698 times.
23099 if (pkt->dts != pkt->pts)
7413 1401 trk->flags |= MOV_TRACK_CTTS;
7414 23099 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7415 23099 trk->cluster[trk->entry].flags = 0;
7416
6/6
✓ Branch 0 taken 22800 times.
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 68 times.
✓ Branch 3 taken 22732 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 63 times.
23099 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7417 304 trk->start_cts = pkt->pts - pkt->dts;
7418
2/2
✓ Branch 0 taken 303 times.
✓ Branch 1 taken 22796 times.
23099 if (trk->end_pts == AV_NOPTS_VALUE)
7419 303 trk->end_pts = trk->cluster[trk->entry].dts +
7420 303 trk->cluster[trk->entry].cts + duration;
7421 else
7422 22796 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7423 trk->cluster[trk->entry].cts +
7424 duration);
7425
2/2
✓ Branch 0 taken 23096 times.
✓ Branch 1 taken 3 times.
23099 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7426 23096 trk->elst_end_pts = trk->end_pts;
7427
7428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23099 times.
23099 if (par->codec_id == AV_CODEC_ID_VC1) {
7429 mov_parse_vc1_frame(pkt, trk);
7430
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23099 times.
23099 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7431 mov_parse_truehd_frame(pkt, trk);
7432
2/2
✓ Branch 0 taken 17050 times.
✓ Branch 1 taken 6049 times.
23099 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7433
4/4
✓ Branch 0 taken 6267 times.
✓ Branch 1 taken 10783 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6258 times.
17050 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7434
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7435 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7437 trk->flags |= MOV_TRACK_STPS;
7438 } else {
7439 17042 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7440 }
7441
1/2
✓ Branch 0 taken 17050 times.
✗ Branch 1 not taken.
17050 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7442 17050 trk->has_keyframes++;
7443 }
7444
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 23092 times.
23099 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7445 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7446 7 trk->has_disposable++;
7447 }
7448
7449 23099 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7450
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23099 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23099 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7451 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7452 else
7453 23099 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7454
7455 23099 trk->entry++;
7456 23099 trk->sample_count += samples_in_chunk;
7457 23099 mov->mdat_size += size;
7458
7459
3/4
✓ Branch 0 taken 23017 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
23099 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7460 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7462 : NULL, size);
7463
7464 23100 end:
7465 23100 err:
7466
7467
1/2
✓ Branch 0 taken 23100 times.
✗ Branch 1 not taken.
23100 if (pkt->data != reformatted_data)
7468 23100 av_free(reformatted_data);
7469 23100 return ret;
7470 }
7471
7472 23063 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7473 {
7474 23063 MOVMuxContext *mov = s->priv_data;
7475 23063 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7476 23063 AVCodecParameters *par = trk->par;
7477 23063 int64_t frag_duration = 0;
7478 23063 int size = pkt->size;
7479
7480 23063 int ret = check_pkt(s, trk, pkt);
7481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23063 times.
23063 if (ret < 0)
7482 return ret;
7483
7484
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 23058 times.
23063 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7485
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7486 10 mov->tracks[i].frag_discont = 1;
7487 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7488 }
7489
7490
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 21051 times.
23063 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7491
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7492 15 trk->dts_shift = pkt->pts - pkt->dts;
7493 2012 pkt->dts += trk->dts_shift;
7494 }
7495
7496
1/2
✓ Branch 0 taken 23063 times.
✗ Branch 1 not taken.
23063 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7497
2/2
✓ Branch 0 taken 14875 times.
✓ Branch 1 taken 8188 times.
23063 trk->par->codec_id == AV_CODEC_ID_AAC ||
7498
2/2
✓ Branch 0 taken 14847 times.
✓ Branch 1 taken 28 times.
14875 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7499
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 14787 times.
14847 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7500 size_t side_size;
7501 8276 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7502 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7503
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8270 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
8276 if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
7504 6 void *newextra = av_malloc(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7506 return AVERROR(ENOMEM);
7507 6 memset((uint8_t*)newextra + side_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7508 6 memcpy(newextra, side, side_size);
7509 6 av_free(trk->extradata[trk->last_stsd_index]);
7510 6 trk->extradata[trk->last_stsd_index] = newextra;
7511 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7512 }
7513 }
7514
7515
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23054 times.
23063 if (!pkt->size) {
7516
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) {
7517 4 trk->start_dts = pkt->dts;
7518
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7519 4 trk->start_cts = pkt->pts - pkt->dts;
7520 else
7521 trk->start_cts = 0;
7522 }
7523
7524 9 return 0; /* Discard 0 sized packets */
7525 }
7526
7527
4/4
✓ Branch 0 taken 22689 times.
✓ Branch 1 taken 365 times.
✓ Branch 2 taken 22665 times.
✓ Branch 3 taken 24 times.
23054 if (trk->entry && pkt->stream_index < mov->nb_streams)
7528 22665 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7529 22665 s->streams[pkt->stream_index]->time_base,
7530 22665 AV_TIME_BASE_Q);
7531
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 22793 times.
23054 if ((mov->max_fragment_duration &&
7532
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7533
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23050 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23050 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7534
2/2
✓ Branch 0 taken 4885 times.
✓ Branch 1 taken 18165 times.
23050 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7535
2/2
✓ Branch 0 taken 2311 times.
✓ Branch 1 taken 2574 times.
4885 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7536
4/4
✓ Branch 0 taken 2284 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 2234 times.
✓ Branch 3 taken 50 times.
2311 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7537
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22999 times.
23000 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7538
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (frag_duration >= mov->min_fragment_duration) {
7539
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1 times.
55 if (trk->entry) {
7540 // Set the duration of this track to line up with the next
7541 // sample in this track. This avoids relying on AVPacket
7542 // duration, but only helps for this particular track, not
7543 // for the other ones that are flushed at the same time.
7544 //
7545 // If we have trk->entry == 0, no fragment will be written
7546 // for this track, and we can't adjust the track end here.
7547 54 trk->track_duration = pkt->dts - trk->start_dts;
7548
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (pkt->pts != AV_NOPTS_VALUE)
7549 54 trk->end_pts = pkt->pts;
7550 else
7551 trk->end_pts = pkt->dts;
7552
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7553 54 trk->elst_end_pts = trk->end_pts;
7554 54 trk->end_reliable = 1;
7555 }
7556 55 mov_auto_flush_fragment(s, 0);
7557 }
7558 }
7559
7560 23054 return ff_mov_write_packet(s, pkt);
7561 }
7562
7563 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7564 int stream_index,
7565 int64_t dts) {
7566 3 MOVMuxContext *mov = s->priv_data;
7567 3 AVPacket *end = mov->pkt;
7568 3 uint8_t data[2] = {0};
7569 int ret;
7570
7571 3 end->size = sizeof(data);
7572 3 end->data = data;
7573 3 end->pts = dts;
7574 3 end->dts = dts;
7575 3 end->duration = 0;
7576 3 end->stream_index = stream_index;
7577
7578 3 ret = mov_write_single_packet(s, end);
7579 3 av_packet_unref(end);
7580
7581 3 return ret;
7582 }
7583
7584 #if CONFIG_IAMFENC
7585 300 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7586 {
7587 uint8_t *data;
7588 int ret;
7589
7590
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 240 times.
300 if (pkt->stream_index == trk->first_iamf_idx) {
7591 60 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (ret < 0)
7593 return ret;
7594 }
7595
7596 300 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7597 300 s->streams[pkt->stream_index]->id, pkt);
7598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (ret < 0)
7599 return ret;
7600
7601
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (pkt->stream_index != trk->last_iamf_idx)
7602 240 return AVERROR(EAGAIN);
7603
7604 60 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7605 60 trk->iamf_buf = NULL;
7606
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
60 if (!ret) {
7607
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7608 // Either all or none of the packets for a single
7609 // IA Sample may be empty.
7610 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7611 "stream #%d\n", pkt->stream_index);
7612 ret = AVERROR_INVALIDDATA;
7613 }
7614 5 av_free(data);
7615 5 return ret;
7616 }
7617
7618 55 av_buffer_unref(&pkt->buf);
7619 55 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (!pkt->buf) {
7621 av_free(data);
7622 return AVERROR(ENOMEM);
7623 }
7624 55 pkt->data = data;
7625 55 pkt->size = ret;
7626 55 pkt->stream_index = trk->first_iamf_idx;
7627
7628 55 return avio_open_dyn_buf(&trk->iamf_buf);
7629 }
7630 #endif
7631
7632 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7633 {
7634 2 int64_t pos = avio_tell(pb);
7635 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7636 2 const char *value = "";
7637
7638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7639
7640 2 avio_write_marker(pb,
7641 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7642 AVIO_DATA_MARKER_BOUNDARY_POINT);
7643
7644 2 avio_wb32(pb, 0); /* size */
7645 2 ffio_wfourcc(pb, "emsg");
7646 2 avio_w8(pb, 1); /* version */
7647 2 avio_wb24(pb, 0);
7648 2 avio_wb32(pb, st->time_base.den); /* timescale */
7649 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7650 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7651 2 avio_wb32(pb, 0); /* id */
7652 /* null terminated UTF8 strings */
7653 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7654 2 avio_write(pb, value, strlen(value) + 1);
7655 2 avio_write(pb, pkt->data, pkt->size);
7656
7657 2 return update_size(pb, pos);
7658 }
7659
7660 23468 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7661 {
7662 23468 MOVMuxContext *mov = s->priv_data;
7663 MOVTrack *trk;
7664
7665
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 23424 times.
23468 if (!pkt) {
7666 44 mov_flush_fragment(s, 1);
7667 44 return 1;
7668 }
7669
7670
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23422 times.
23424 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7671 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7672 2 return 0;
7673 }
7674
7675 23422 trk = s->streams[pkt->stream_index]->priv_data;
7676
7677 #if CONFIG_IAMFENC
7678
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 23122 times.
23422 if (trk->iamf) {
7679 300 int ret = mov_build_iamf_packet(s, trk, pkt);
7680
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (ret < 0) {
7681
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if (ret == AVERROR(EAGAIN))
7682 240 return 0;
7683 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7684 "for stream #%d\n", trk->st->index);
7685 return ret;
7686 }
7687 }
7688 #endif
7689
7690
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 23180 times.
23182 if (is_cover_image(trk->st)) {
7691 int ret;
7692
7693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7694 if (trk->st->nb_frames == 1)
7695 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7696 " ignoring.\n", pkt->stream_index);
7697 return 0;
7698 }
7699
7700
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7701 return ret;
7702
7703 2 return 0;
7704 } else {
7705 int i;
7706
7707
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23171 times.
23180 if (!pkt->size)
7708 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7709
7710 /*
7711 * Subtitles require special handling.
7712 *
7713 * 1) For full compliance, every track must have a sample at
7714 * dts == 0, which is rarely true for subtitles. So, as soon
7715 * as we see any packet with dts > 0, write an empty subtitle
7716 * at dts == 0 for any subtitle track with no samples in it.
7717 *
7718 * 2) For each subtitle track, check if the current packet's
7719 * dts is past the duration of the last subtitle sample. If
7720 * so, we now need to write an end sample for that subtitle.
7721 *
7722 * This must be done conditionally to allow for subtitles that
7723 * immediately replace each other, in which case an end sample
7724 * is not needed, and is, in fact, actively harmful.
7725 *
7726 * 3) See mov_write_trailer for how the final end sample is
7727 * handled.
7728 */
7729
2/2
✓ Branch 0 taken 39165 times.
✓ Branch 1 taken 23171 times.
62336 for (i = 0; i < mov->nb_tracks; i++) {
7730 39165 MOVTrack *trk = &mov->tracks[i];
7731 int ret;
7732
7733
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39162 times.
39165 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7734
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7735
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)) {
7736 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7738 2 trk->last_sample_is_subtitle_end = 1;
7739 }
7740 }
7741
7742
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 23023 times.
23171 if (trk->squash_fragment_samples_to_one) {
7743 /*
7744 * If the track has to have its samples squashed into one sample,
7745 * we just take it into the track's queue.
7746 * This will then be utilized as the samples get written in either
7747 * mov_flush_fragment or when the mux is finalized in
7748 * mov_write_trailer.
7749 */
7750 148 int ret = AVERROR_BUG;
7751
7752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7753 av_log(s, AV_LOG_ERROR,
7754 "Packets without a valid presentation timestamp are "
7755 "not supported with packet squashing!\n");
7756 return AVERROR(EINVAL);
7757 }
7758
7759 /* The following will reset pkt and is only allowed to be used
7760 * because we return immediately. afterwards. */
7761
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = ff_packet_list_put(&trk->squashed_packet_queue,
7762 pkt, NULL, 0)) < 0) {
7763 return ret;
7764 }
7765
7766 148 return 0;
7767 }
7768
7769
7770
4/4
✓ Branch 0 taken 7939 times.
✓ Branch 1 taken 15084 times.
✓ Branch 2 taken 3917 times.
✓ Branch 3 taken 4022 times.
23023 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7771 3917 AVPacket *opkt = pkt;
7772 int reshuffle_ret, ret;
7773
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3892 times.
3917 if (trk->is_unaligned_qt_rgb) {
7774
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;
7775 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7776 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7777
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7778 return reshuffle_ret;
7779 } else
7780 3892 reshuffle_ret = 0;
7781
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3679 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3917 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7782 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7784 goto fail;
7785
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7786 5 trk->pal_done++;
7787
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 3087 times.
3912 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7788
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7790 ret = av_packet_make_writable(pkt);
7791 if (ret < 0)
7792 goto fail;
7793 for (i = 0; i < pkt->size; i++)
7794 pkt->data[i] = ~pkt->data[i];
7795 }
7796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3917 times.
3917 if (reshuffle_ret) {
7797 ret = mov_write_single_packet(s, pkt);
7798 fail:
7799 if (reshuffle_ret)
7800 av_packet_free(&pkt);
7801 return ret;
7802 }
7803 }
7804
7805 23023 return mov_write_single_packet(s, pkt);
7806 }
7807 }
7808
7809 // QuickTime chapters involve an additional text track with the chapter names
7810 // as samples, and a tref pointing from the other tracks to the chapter one.
7811 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7812 {
7813 static const uint8_t stub_header[] = {
7814 // TextSampleEntry
7815 0x00, 0x00, 0x00, 0x01, // displayFlags
7816 0x00, 0x00, // horizontal + vertical justification
7817 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7818 // BoxRecord
7819 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7820 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7821 // StyleRecord
7822 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7823 0x00, 0x01, // fontID
7824 0x00, 0x00, // fontStyleFlags + fontSize
7825 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7826 // FontTableBox
7827 0x00, 0x00, 0x00, 0x0D, // box size
7828 'f', 't', 'a', 'b', // box atom name
7829 0x00, 0x01, // entry count
7830 // FontRecord
7831 0x00, 0x01, // font ID
7832 0x00, // font name length
7833 };
7834 1 MOVMuxContext *mov = s->priv_data;
7835 1 MOVTrack *track = &mov->tracks[tracknum];
7836 1 AVPacket *pkt = mov->pkt;
7837 int i, len;
7838 int ret;
7839
7840 1 track->mode = mov->mode;
7841 1 track->tag = MKTAG('t','e','x','t');
7842 1 track->timescale = mov->movie_timescale;
7843 1 track->par = avcodec_parameters_alloc();
7844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7845 return AVERROR(ENOMEM);
7846 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7847 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7849 return ret;
7850 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7851
7852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7853 track->stsd_count = 1;
7854 track->extradata = av_calloc(1, sizeof(*track->extradata));
7855 track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7856 if (!track->extradata || !track->extradata_size)
7857 return AVERROR(ENOMEM);
7858 }
7859
7860 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7862 return AVERROR(ENOMEM);
7863 1 track->extradata_size[0] = sizeof(stub_header);
7864
7865 1 pkt->stream_index = tracknum;
7866 1 pkt->flags = AV_PKT_FLAG_KEY;
7867
7868
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7869 4 AVChapter *c = s->chapters[i];
7870 AVDictionaryEntry *t;
7871
7872 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7873 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7874 4 pkt->duration = end - pkt->dts;
7875
7876
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7877 static const char encd[12] = {
7878 0x00, 0x00, 0x00, 0x0C,
7879 'e', 'n', 'c', 'd',
7880 0x00, 0x00, 0x01, 0x00 };
7881 4 len = strlen(t->value);
7882 4 pkt->size = len + 2 + 12;
7883 4 pkt->data = av_malloc(pkt->size);
7884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7885 av_packet_unref(pkt);
7886 return AVERROR(ENOMEM);
7887 }
7888 4 AV_WB16(pkt->data, len);
7889 4 memcpy(pkt->data + 2, t->value, len);
7890 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7891 4 ff_mov_write_packet(s, pkt);
7892 4 av_freep(&pkt->data);
7893 }
7894 }
7895
7896 1 av_packet_unref(mov->pkt);
7897
7898 1 return 0;
7899 }
7900
7901
7902 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7903 {
7904 int ret;
7905
7906 /* compute the frame number */
7907 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7908 13 return ret;
7909 }
7910
7911 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7912 {
7913 6 MOVMuxContext *mov = s->priv_data;
7914 6 MOVTrack *track = &mov->tracks[index];
7915 6 AVStream *src_st = mov->tracks[src_index].st;
7916 uint8_t data[4];
7917 6 AVPacket *pkt = mov->pkt;
7918 6 AVRational rate = src_st->avg_frame_rate;
7919 int ret;
7920
7921 /* tmcd track based on video stream */
7922 6 track->mode = mov->mode;
7923 6 track->tag = MKTAG('t','m','c','d');
7924 6 track->src_track = av_malloc(sizeof(*track->src_track));
7925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->src_track)
7926 return AVERROR(ENOMEM);
7927 6 *track->src_track = src_index;
7928 6 track->nb_src_track = 1;
7929
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7930 3 track->timescale = tc.fps * 1000;
7931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (tc.rate.den == 1001)
7932 track->timescale = tc.rate.num;
7933 else
7934 3 track->timescale = tc.fps;
7935
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7936 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7937
7938 /* set st to src_st for metadata access*/
7939 6 track->st = src_st;
7940
7941 /* encode context: tmcd data stream */
7942 6 track->par = avcodec_parameters_alloc();
7943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7944 return AVERROR(ENOMEM);
7945 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7946 6 track->par->codec_tag = track->tag;
7947 6 track->st->avg_frame_rate = rate;
7948
7949 /* the tmcd track just contains one packet with the frame number */
7950 6 pkt->data = data;
7951 6 pkt->stream_index = index;
7952 6 pkt->flags = AV_PKT_FLAG_KEY;
7953 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){ 1, track->timescale });
7954 6 pkt->size = 4;
7955 6 AV_WB32(pkt->data, tc.start);
7956 6 ret = ff_mov_write_packet(s, pkt);
7957 6 av_packet_unref(pkt);
7958 6 return ret;
7959 }
7960
7961 /*
7962 * st->disposition controls the "enabled" flag in the tkhd tag.
7963 * QuickTime will not play a track if it is not enabled. So make sure
7964 * that one track of each type (audio, video, subtitle) is enabled.
7965 *
7966 * Subtitles are special. For audio and video, setting "enabled" also
7967 * makes the track "default" (i.e. it is rendered when played). For
7968 * subtitles, an "enabled" subtitle is not rendered by default, but
7969 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7970 * empty!
7971 */
7972 247 static void enable_tracks(AVFormatContext *s)
7973 {
7974 247 MOVMuxContext *mov = s->priv_data;
7975 int i;
7976 int enabled[AVMEDIA_TYPE_NB];
7977 int first[AVMEDIA_TYPE_NB];
7978
7979
2/2
✓ Branch 0 taken 1235 times.
✓ Branch 1 taken 247 times.
1482 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7980 1235 enabled[i] = 0;
7981 1235 first[i] = -1;
7982 }
7983
7984
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 247 times.
556 for (i = 0; i < mov->nb_streams; i++) {
7985 309 AVStream *st = mov->tracks[i].st;
7986
7987
1/2
✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
309 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7988
3/4
✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 307 times.
618 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7989 309 is_cover_image(st))
7990 2 continue;
7991
7992
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 15 times.
307 if (first[st->codecpar->codec_type] < 0)
7993 292 first[st->codecpar->codec_type] = i;
7994
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 271 times.
307 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7995 36 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7996 36 enabled[st->codecpar->codec_type]++;
7997 }
7998 }
7999
8000
2/2
✓ Branch 0 taken 1235 times.
✓ Branch 1 taken 247 times.
1482 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8001
2/2
✓ Branch 0 taken 741 times.
✓ Branch 1 taken 494 times.
1235 switch (i) {
8002 741 case AVMEDIA_TYPE_VIDEO:
8003 case AVMEDIA_TYPE_AUDIO:
8004 case AVMEDIA_TYPE_SUBTITLE:
8005
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 740 times.
741 if (enabled[i] > 1)
8006 1 mov->per_stream_grouping = 1;
8007
4/4
✓ Branch 0 taken 710 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 259 times.
✓ Branch 3 taken 451 times.
741 if (!enabled[i] && first[i] >= 0)
8008 259 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
8009 741 break;
8010 }
8011 }
8012 247 }
8013
8014 247 static void mov_free(AVFormatContext *s)
8015 {
8016 247 MOVMuxContext *mov = s->priv_data;
8017
8018
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (int i = 0; i < s->nb_streams; i++)
8019 330 s->streams[i]->priv_data = NULL;
8020
8021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (!mov->tracks)
8022 return;
8023
8024
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->chapter_track) {
8025 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
8026 }
8027
8028
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (int i = 0; i < mov->nb_tracks; i++) {
8029 318 MOVTrack *const track = &mov->tracks[i];
8030
8031
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 316 times.
318 if (track->tag == MKTAG('r','t','p',' '))
8032 2 ff_mov_close_hinting(track);
8033
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
316 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
8034 6 av_freep(&track->par);
8035 318 av_freep(&track->cluster);
8036 318 av_freep(&track->cluster_written);
8037 318 av_freep(&track->frag_info);
8038 318 av_packet_free(&track->cover_image);
8039
8040
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 308 times.
318 if (track->eac3_priv) {
8041 10 struct eac3_info *info = track->eac3_priv;
8042 10 av_packet_free(&info->pkt);
8043 10 av_freep(&track->eac3_priv);
8044 }
8045
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 318 times.
638 for (int j = 0; j < track->stsd_count; j++)
8046 320 av_freep(&track->extradata[j]);
8047 318 av_freep(&track->extradata);
8048 318 av_freep(&track->extradata_size);
8049
8050
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 318 times.
328 for (int i = 0; i < track->nb_tref_tags; i++)
8051 10 av_freep(&track->tref_tags[i].id);
8052 318 av_freep(&track->tref_tags);
8053 318 av_freep(&track->src_track);
8054
8055 318 ff_mov_cenc_free(&track->cenc);
8056 318 ffio_free_dyn_buf(&track->mdat_buf);
8057
8058 #if CONFIG_IAMFENC
8059 318 ffio_free_dyn_buf(&track->iamf_buf);
8060
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 313 times.
318 if (track->iamf)
8061 5 ff_iamf_uninit_context(track->iamf);
8062 318 av_freep(&track->iamf);
8063 #endif
8064 318 ff_isom_close_apvc(&track->apv);
8065
8066 318 ff_packet_list_free(&track->squashed_packet_queue);
8067 }
8068
8069 247 av_freep(&mov->tracks);
8070 247 ffio_free_dyn_buf(&mov->mdat_buf);
8071 }
8072
8073 static uint32_t rgb_to_yuv(uint32_t rgb)
8074 {
8075 uint8_t r, g, b;
8076 int y, cb, cr;
8077
8078 r = (rgb >> 16) & 0xFF;
8079 g = (rgb >> 8) & 0xFF;
8080 b = (rgb ) & 0xFF;
8081
8082 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
8083 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
8084 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
8085
8086 return (y << 16) | (cr << 8) | cb;
8087 }
8088
8089 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
8090 AVStream *st)
8091 {
8092 int i, width = 720, height = 480;
8093 int have_palette = 0, have_size = 0;
8094 uint32_t palette[16];
8095 char *cur = st->codecpar->extradata;
8096
8097 while (cur && *cur) {
8098 if (strncmp("palette:", cur, 8) == 0) {
8099 int i, count;
8100 count = sscanf(cur + 8,
8101 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8102 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8103 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8104 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
8105 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
8106 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
8107 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
8108 &palette[12], &palette[13], &palette[14], &palette[15]);
8109
8110 for (i = 0; i < count; i++) {
8111 palette[i] = rgb_to_yuv(palette[i]);
8112 }
8113 have_palette = 1;
8114 } else if (!strncmp("size:", cur, 5)) {
8115 sscanf(cur + 5, "%dx%d", &width, &height);
8116 have_size = 1;
8117 }
8118 if (have_palette && have_size)
8119 break;
8120 cur += strcspn(cur, "\n\r");
8121 cur += strspn(cur, "\n\r");
8122 }
8123 if (have_palette) {
8124 track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
8125 if (!track->extradata[track->last_stsd_index])
8126 return AVERROR(ENOMEM);
8127 for (i = 0; i < 16; i++) {
8128 AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
8129 }
8130 memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8131 track->extradata_size[track->last_stsd_index] = 16 * 4;
8132 }
8133 st->codecpar->width = width;
8134 st->codecpar->height = track->height = height;
8135
8136 return 0;
8137 }
8138
8139 #if CONFIG_IAMFENC
8140 247 static int mov_init_iamf_track(AVFormatContext *s)
8141 {
8142 247 MOVMuxContext *mov = s->priv_data;
8143 MOVTrack *track;
8144 IAMFContext *iamf;
8145 247 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
8146 247 int nb_audio_elements = 0, nb_mix_presentations = 0;
8147 int ret;
8148
8149
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 247 times.
257 for (int i = 0; i < s->nb_stream_groups; i++) {
8150 10 const AVStreamGroup *stg = s->stream_groups[i];
8151
8152
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8153 5 nb_audio_elements++;
8154
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
8155 5 nb_mix_presentations++;
8156 }
8157
8158
3/4
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 242 times.
✗ Branch 3 not taken.
247 if (!nb_audio_elements && !nb_mix_presentations)
8159 242 return 0;
8160
8161
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) {
8162 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
8163 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
8164 return AVERROR(EINVAL);
8165 }
8166
8167 5 iamf = av_mallocz(sizeof(*iamf));
8168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
8169 return AVERROR(ENOMEM);
8170
8171
8172
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8173 10 const AVStreamGroup *stg = s->stream_groups[i];
8174
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
8175 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
8176
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8177 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
8178 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
8179 }
8180
8181 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
8182 5 break;
8183 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
8184 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
8185 5 break;
8186 default:
8187 av_assert0(0);
8188 }
8189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
8190 ff_iamf_uninit_context(iamf);
8191 av_free(iamf);
8192 return ret;
8193 }
8194 }
8195
8196 5 track = &mov->tracks[first_iamf_idx];
8197 5 track->iamf = iamf;
8198 5 track->first_iamf_idx = first_iamf_idx;
8199 5 track->last_iamf_idx = last_iamf_idx;
8200 5 track->tag = MKTAG('i','a','m','f');
8201
8202
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8203 10 AVStreamGroup *stg = s->stream_groups[i];
8204
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8205 5 continue;
8206
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
8207 25 stg->streams[j]->priv_data = track;
8208 }
8209
8210 5 ret = avio_open_dyn_buf(&track->iamf_buf);
8211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
8212 return ret;
8213
8214 5 return 0;
8215 }
8216 #endif
8217
8218 247 static int mov_init(AVFormatContext *s)
8219 {
8220 247 MOVMuxContext *mov = s->priv_data;
8221 247 int has_iamf = 0;
8222 int i, ret;
8223
8224 247 mov->fc = s;
8225 247 mov->pkt = ffformatcontext(s)->pkt;
8226
8227 /* Default mode == MP4 */
8228 247 mov->mode = MODE_MP4;
8229
8230 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
8231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
8232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
8233
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 96 times.
247 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
8234
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
8235
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 94 times.
95 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
8236
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 89 times.
94 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
8237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
8238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
8239 #undef IS_MODE
8240
8241
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 227 times.
247 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
8242 20 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
8243
8244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->mode == MODE_AVIF)
8245 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
8246
8247 /* Set the FRAGMENT flag if any of the fragmentation methods are
8248 * enabled. */
8249
3/4
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 245 times.
✗ Branch 3 not taken.
247 if (mov->max_fragment_duration || mov->max_fragment_size ||
8250
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 211 times.
245 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
8251 FF_MOV_FLAG_FRAG_KEYFRAME |
8252 FF_MOV_FLAG_FRAG_CUSTOM |
8253 FF_MOV_FLAG_FRAG_EVERY_FRAME))
8254 36 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8255
8256
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
247 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
8257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
8258 av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
8259 return AVERROR(EINVAL);
8260 }
8261
8262 /* Set other implicit flags immediately */
8263
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
247 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8264 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8265
8266
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 242 times.
247 if (mov->mode == MODE_ISM)
8267 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
8268 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8269
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 233 times.
247 if (mov->flags & FF_MOV_FLAG_DASH)
8270 14 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8271 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
8272
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
247 if (mov->flags & FF_MOV_FLAG_CMAF)
8273 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8274 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8275
8276
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 3 times.
247 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
8277 34 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
8278 34 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
8279 }
8280
8281
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
247 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
8282 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
8283 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
8284 }
8285
8286
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 244 times.
247 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8287 3 mov->reserved_moov_size = -1;
8288 }
8289
8290
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 7 times.
247 if (mov->use_editlist < 0) {
8291 240 mov->use_editlist = 1;
8292
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 205 times.
240 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8293
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 18 times.
35 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8294 // If we can avoid needing an edit list by shifting the
8295 // tracks, prefer that over (trying to) write edit lists
8296 // in fragmented output.
8297
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
8298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
8299 16 mov->use_editlist = 0;
8300 }
8301 }
8302
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 210 times.
247 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8303
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
8304 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
8305
8306
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
247 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist)
8307 mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8308
8309
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 1 times.
247 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
8310
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
21 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
8311 13 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
8312
8313 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
8314 * if the latter is set that's enough and omit_tfhd_offset doesn't
8315 * add anything extra on top of that. */
8316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
8317 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
8318 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
8319
8320
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->frag_interleave &&
8321
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)) {
8322 av_log(s, AV_LOG_ERROR,
8323 "Sample interleaving in fragments is mutually exclusive with "
8324 "omit_tfhd_offset and separate_moof\n");
8325 return AVERROR(EINVAL);
8326 }
8327
8328 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8329 * is enabled, we don't support non-seekable output at all. */
8330
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 218 times.
247 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
8331
2/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
8332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 mov->mode == MODE_AVIF)) {
8333 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
8334 return AVERROR(EINVAL);
8335 }
8336
8337 /* AVIF output must have at most two video streams (one for YUV and one for
8338 * alpha). */
8339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->mode == MODE_AVIF) {
8340 if (s->nb_streams > 2) {
8341 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
8342 return AVERROR(EINVAL);
8343 }
8344 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
8345 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
8346 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
8347 return AVERROR(EINVAL);
8348 }
8349 if (s->nb_streams > 1) {
8350 const AVPixFmtDescriptor *pixdesc =
8351 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
8352 if (pixdesc->nb_components != 1) {
8353 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8354 return AVERROR(EINVAL);
8355 }
8356 }
8357 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
8358 }
8359
8360
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 247 times.
257 for (i = 0; i < s->nb_stream_groups; i++) {
8361 10 AVStreamGroup *stg = s->stream_groups[i];
8362
8363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_LCEVC) {
8364 if (stg->nb_streams != 2) {
8365 av_log(s, AV_LOG_ERROR, "Exactly two Streams are supported for Stream Groups of type LCEVC\n");
8366 return AVERROR(EINVAL);
8367 }
8368 AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8369 if (lcevc->el_index > 1)
8370 return AVERROR(EINVAL);
8371 AVStream *st = stg->streams[lcevc->el_index];
8372 if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) {
8373 av_log(s, AV_LOG_ERROR, "Stream #%u is not an LCEVC stream\n", lcevc->el_index);
8374 return AVERROR(EINVAL);
8375 }
8376 }
8377
8378 #if CONFIG_IAMFENC
8379
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8380 5 continue;
8381
8382
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
8383 25 AVStream *st = stg->streams[j];
8384
8385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8386 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8387 "IAMF Audio Element\n", j);
8388 return AVERROR(EINVAL);
8389 }
8390 25 st->priv_data = st;
8391 }
8392 5 has_iamf = 1;
8393
8394
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
8395 5 mov->nb_tracks++;
8396 #endif
8397 }
8398
8399
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8400 330 AVStream *st = s->streams[i];
8401
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 305 times.
330 if (st->priv_data)
8402 25 continue;
8403 // Don't produce a track in the output file for timed ID3 streams.
8404
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 304 times.
305 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8405 // Leave priv_data set to NULL for these AVStreams that don't
8406 // have a corresponding track.
8407 1 continue;
8408 }
8409 304 st->priv_data = st;
8410 304 mov->nb_tracks++;
8411 }
8412
8413 247 mov->nb_streams = mov->nb_tracks;
8414
8415
4/4
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 240 times.
247 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8416 1 mov->chapter_track = mov->nb_tracks++;
8417
8418
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8419
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8420
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8421 2 mov->nb_tracks++;
8422 }
8423
8424
1/2
✓ Branch 0 taken 247 times.
✗ Branch 1 not taken.
247 if (mov->write_btrt < 0) {
8425 247 mov->write_btrt = mov->mode == MODE_MP4;
8426 }
8427
8428
6/6
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 151 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 89 times.
247 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8429
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8430 243 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8431 NULL, 0);
8432
8433 /* +1 tmcd track for each video stream with a timecode */
8434
2/2
✓ Branch 0 taken 323 times.
✓ Branch 1 taken 243 times.
566 for (i = 0; i < s->nb_streams; i++) {
8435 323 AVStream *st = s->streams[i];
8436 323 AVDictionaryEntry *t = global_tcr;
8437
4/4
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 6 times.
323 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8438
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 193 times.
194 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8439 AVTimecode tc;
8440 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8441
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8442 7 mov->nb_meta_tmcd++;
8443 }
8444 }
8445
8446 /* check if there is already a tmcd track to remux */
8447
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 236 times.
243 if (mov->nb_meta_tmcd) {
8448
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8449 13 AVStream *st = s->streams[i];
8450
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8451 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8452 "so timecode metadata are now ignored\n");
8453 3 mov->nb_meta_tmcd = 0;
8454 }
8455 }
8456 }
8457
8458 243 mov->nb_tracks += mov->nb_meta_tmcd;
8459 }
8460
8461 // Reserve an extra stream for chapters for the case where chapters
8462 // are written in the trailer
8463 247 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (!mov->tracks)
8465 return AVERROR(ENOMEM);
8466
8467
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (i = 0; i < mov->nb_tracks; i++) {
8468 318 MOVTrack *track = &mov->tracks[i];
8469
8470 318 track->stsd_count = 1;
8471 318 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8472 318 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8473
2/4
✓ Branch 0 taken 318 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 318 times.
318 if (!track->extradata || !track->extradata_size)
8474 return AVERROR(ENOMEM);
8475 }
8476
8477
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 242 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
247 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8478
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8479 5 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8480
8481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8482 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8483 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8484 return AVERROR(EINVAL);
8485 }
8486
8487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8488 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8489 mov->encryption_kid_len, CENC_KID_SIZE);
8490 return AVERROR(EINVAL);
8491 }
8492 } else {
8493 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8494 mov->encryption_scheme_str);
8495 return AVERROR(EINVAL);
8496 }
8497 }
8498
8499 #if CONFIG_IAMFENC
8500 247 ret = mov_init_iamf_track(s);
8501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (ret < 0)
8502 return ret;
8503 #endif
8504
8505
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8506 330 AVStream *st = s->streams[j];
8507
8508
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 304 times.
330 if (st != st->priv_data) {
8509
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8510 5 i += has_iamf--;
8511 26 continue;
8512 }
8513 304 st->priv_data = &mov->tracks[i++];
8514 }
8515
8516 247 AVRational movie_timescale = (AVRational) { 0, 1 };
8517
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8518 330 AVStream *st= s->streams[i];
8519 330 MOVTrack *track = st->priv_data;
8520
8521
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 329 times.
330 if (!track)
8522 1 continue;
8523
8524
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 20 times.
329 if (!track->st) {
8525 309 track->st = st;
8526 309 track->par = st->codecpar;
8527 }
8528
8529 329 movie_timescale = av_gcd_q(movie_timescale, st->time_base, INT_MAX, (AVRational){1,0});
8530 }
8531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (!movie_timescale.den)
8532 movie_timescale = MOV_TIMESCALE_Q;
8533
8534
1/2
✓ Branch 0 taken 247 times.
✗ Branch 1 not taken.
247 if (!mov->movie_timescale)
8535 247 mov->movie_timescale = FFMAX(movie_timescale.den, MOV_TIMESCALE);
8536
8537
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8538 330 AVStream *st= s->streams[i];
8539 330 MOVTrack *track = st->priv_data;
8540 330 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8541
8542
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 329 times.
330 if (!track)
8543 1 continue;
8544
8545
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 299 times.
329 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8546
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 171 times.
329 if (track->language < 0)
8547 158 track->language = 32767; // Unspecified Macintosh language code
8548 329 track->mode = mov->mode;
8549
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 25 times.
329 if (!track->tag)
8550 304 track->tag = mov_find_codec_tag(s, track);
8551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 329 times.
329 if (!track->tag) {
8552 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8553 "codec not currently supported in container\n",
8554 avcodec_get_name(st->codecpar->codec_id), i);
8555 return AVERROR(EINVAL);
8556 }
8557 /* If hinting of this track is enabled by a later hint track,
8558 * this is updated. */
8559 329 track->hint_track = -1;
8560 329 track->start_dts = AV_NOPTS_VALUE;
8561 329 track->start_cts = AV_NOPTS_VALUE;
8562 329 track->end_pts = AV_NOPTS_VALUE;
8563 329 track->dts_shift = AV_NOPTS_VALUE;
8564
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 126 times.
329 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8565
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
203 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8566
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
203 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8567
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
203 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8568 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8569 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8570 return AVERROR(EINVAL);
8571 }
8572 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8573 }
8574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 if (mov->video_track_timescale) {
8575 track->timescale = mov->video_track_timescale;
8576 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8577 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8578 } else {
8579 203 track->timescale = st->time_base.den;
8580
2/2
✓ Branch 0 taken 1594 times.
✓ Branch 1 taken 203 times.
1797 while(track->timescale < 10000)
8581 1594 track->timescale *= 2;
8582 }
8583
2/4
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
203 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8584 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8585 return AVERROR(EINVAL);
8586 }
8587
4/4
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 131 times.
203 if (track->mode == MODE_MOV && track->timescale > 100000)
8588 5 av_log(s, AV_LOG_WARNING,
8589 "WARNING codec timebase is very high. If duration is too long,\n"
8590 "file may not be playable by quicktime. Specify a shorter timebase\n"
8591 "or choose different container.\n");
8592
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 67 times.
203 if (track->mode == MODE_MOV &&
8593
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 119 times.
136 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8594
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8595 1 enum AVPixelFormat pix_fmt = track->par->format;
8596
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)
8597 pix_fmt = AV_PIX_FMT_MONOWHITE;
8598 1 track->is_unaligned_qt_rgb =
8599 pix_fmt == AV_PIX_FMT_RGB24 ||
8600 pix_fmt == AV_PIX_FMT_BGR24 ||
8601 pix_fmt == AV_PIX_FMT_PAL8 ||
8602 pix_fmt == AV_PIX_FMT_GRAY8 ||
8603
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 ||
8604 pix_fmt == AV_PIX_FMT_MONOBLACK;
8605 }
8606
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
203 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8607 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8608 return AVERROR(EINVAL);
8609
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 201 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8610
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8611 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8612 return AVERROR(EINVAL);
8613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8614 /* altref frames handling is not defined in the spec as of version v1.0,
8615 * so just forbid muxing VP8 streams altogether until a new version does */
8616 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8617 return AVERROR_PATCHWELCOME;
8618
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 202 times.
203 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8619 1 ret = ff_isom_init_apvc(&track->apv, s);
8620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8621 return ret;
8622 }
8623
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 201 times.
203 if (is_cover_image(st)) {
8624 2 track->cover_image = av_packet_alloc();
8625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8626 return AVERROR(ENOMEM);
8627 }
8628
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 9 times.
126 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8629 117 track->timescale = st->codecpar->sample_rate;
8630
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 84 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 26 times.
117 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8631 7 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8632 7 track->audio_vbr = 1;
8633
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8634
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8636 if (!st->codecpar->block_align) {
8637 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8638 return AVERROR(EINVAL);
8639 }
8640 track->sample_size = st->codecpar->block_align;
8641
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 26 times.
110 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8642 84 track->audio_vbr = 1;
8643 }else{
8644 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8645 26 st->codecpar->ch_layout.nb_channels;
8646 }
8647
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8649 track->audio_vbr = 1;
8650 }
8651
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 31 times.
117 if (track->mode != MODE_MOV &&
8652
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
86 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8653 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8654 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8655 i, track->par->sample_rate);
8656 return AVERROR(EINVAL);
8657 } else {
8658 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8659 i, track->par->sample_rate);
8660 }
8661 }
8662
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 25 times.
117 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8663
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 track->par->codec_id == AV_CODEC_ID_OPUS) {
8665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8666 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8667 return AVERROR(EINVAL);
8668 }
8669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8670 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8671 av_log(s, AV_LOG_ERROR,
8672 "%s in MP4 support is experimental, add "
8673 "'-strict %d' if you want to use it.\n",
8674 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8675 return AVERROR_EXPERIMENTAL;
8676 }
8677 }
8678
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8679 5 track->timescale = st->time_base.den;
8680
8681
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8682 /* 14496-30 requires us to use a single sample per fragment
8683 for TTML, for which we define a per-track flag.
8684
8685 We set the flag in case we are receiving TTML paragraphs
8686 from the input, in other words in case we are not doing
8687 stream copy. */
8688 4 track->squash_fragment_samples_to_one =
8689 4 ff_is_ttml_stream_paragraph_based(track->par);
8690
8691
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8692
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8694 av_log(s, AV_LOG_ERROR,
8695 "ISMV style TTML support with the 'dfxp' tag in "
8696 "non-ISMV formats is not officially supported. Add "
8697 "'-strict unofficial' if you want to use it.\n");
8698 return AVERROR_EXPERIMENTAL;
8699 }
8700 }
8701
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8702 4 track->timescale = st->time_base.den;
8703
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->tag == MKTAG('t','m','c','d') &&
8704
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->extradata_size >= 8)
8705 3 track->timecode_flags = AV_RB32(st->codecpar->extradata + 4);
8706 } else {
8707 track->timescale = mov->movie_timescale;
8708 }
8709
1/2
✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
329 if (!track->height)
8710 329 track->height = st->codecpar->height;
8711 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8712 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8713 for video tracks, so if user-set, it isn't overwritten */
8714
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 322 times.
329 if (mov->mode == MODE_ISM &&
8715
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8716
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !mov->video_track_timescale))) {
8717 7 track->timescale = 10000000;
8718 }
8719
8720 329 avpriv_set_pts_info(st, 64, 1, track->timescale);
8721
8722
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 324 times.
329 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8723 5 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8724
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8725
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8726
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret)
8728 return ret;
8729 }
8730 }
8731
8732
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 247 times.
257 for (i = 0; i < s->nb_stream_groups; i++) {
8733 10 AVStreamGroup *stg = s->stream_groups[i];
8734
8735
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 switch (stg->type) {
8736 case AV_STREAM_GROUP_PARAMS_LCEVC: {
8737 AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8738 AVStream *st = stg->streams[lcevc->el_index];
8739 MOVTrack *track = st->priv_data;
8740
8741 for (int j = 0; j < mov->nb_tracks; j++) {
8742 MOVTrack *trk = &mov->tracks[j];
8743
8744 if (trk->st == stg->streams[!lcevc->el_index]) {
8745 track->src_track = av_malloc(sizeof(*track->src_track));
8746 if (!track->src_track)
8747 return AVERROR(ENOMEM);
8748 *track->src_track = j;
8749 track->nb_src_track = 1;
8750 break;
8751 }
8752 }
8753
8754 track->par->width = lcevc->width;
8755 track->par->height = track->height = lcevc->height;
8756 break;
8757 }
8758 case AV_STREAM_GROUP_PARAMS_TREF: {
8759 const AVStreamGroupTREF *tref = stg->params.tref;
8760 MOVTrack *track;
8761
8762 if (tref->metadata_index >= stg->nb_streams)
8763 return AVERROR(EINVAL);
8764
8765 track = stg->streams[tref->metadata_index]->priv_data;
8766 for (int j = 0; j < stg->nb_streams; j++) {
8767 const AVStream *st2 = stg->streams[j];
8768 int index = -1;
8769
8770 if (j == tref->metadata_index)
8771 continue;
8772
8773 for (int k = 0; k < mov->nb_tracks; k++) {
8774 if (mov->tracks[k].st != st2)
8775 continue;
8776 index = k;
8777 break;
8778 }
8779 if (index < 0)
8780 return AVERROR(EINVAL);
8781
8782 int *tmp = av_realloc(track->src_track,
8783 (track->nb_src_track + 1) * sizeof(*track->src_track));
8784 if (!tmp)
8785 return AVERROR(ENOMEM);
8786 track->src_track = tmp;
8787 track->src_track[track->nb_src_track++] = index;
8788 }
8789 break;
8790 }
8791 10 default:
8792 10 break;
8793 }
8794 }
8795
8796 /* fill src_track for tmcd tracks not covered by stream groups or
8797 * created by this muxer, retaining the old behavior of src_track
8798 * being arbitrarily 0. */
8799
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 247 times.
577 for (i = 0; i < s->nb_streams; i++) {
8800 330 AVStream *st = s->streams[i];
8801 330 MOVTrack *track = st->priv_data;
8802
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 327 times.
330 if (st->codecpar->codec_tag != MKTAG('t','m','c','d') ||
8803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 track->nb_src_track)
8804 327 continue;
8805
8806 3 track->src_track = av_malloc(sizeof(*track->src_track));
8807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!track->src_track)
8808 return AVERROR(ENOMEM);
8809 3 *track->src_track = 0;
8810 3 track->nb_src_track = 1;
8811 }
8812
8813 247 enable_tracks(s);
8814 247 return 0;
8815 }
8816
8817 247 static int mov_write_header(AVFormatContext *s)
8818 {
8819 247 AVIOContext *pb = s->pb;
8820 247 MOVMuxContext *mov = s->priv_data;
8821 247 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8822
8823
4/4
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 240 times.
247 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8824 1 nb_tracks++;
8825
8826
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8827 1 hint_track = nb_tracks;
8828
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8829
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8830 2 nb_tracks++;
8831 }
8832 }
8833
8834
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 241 times.
247 if (mov->nb_meta_tmcd)
8835 6 tmcd_track = nb_tracks;
8836
8837
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 247 times.
556 for (int i = 0; i < mov->nb_streams; i++) {
8838 309 MOVTrack *track = &mov->tracks[i];
8839 309 AVStream *st = track->st;
8840
8841 /* copy extradata if it exists */
8842
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 164 times.
309 if (st->codecpar->extradata_size) {
8843
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
145 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8844 mov_create_dvd_sub_decoder_specific_info(track, st);
8845
15/30
✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 145 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 145 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 145 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 145 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 145 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 145 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 145 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 145 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 145 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 145 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 145 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 145 times.
✗ Branch 29 not taken.
145 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8846 145 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8847 290 track->extradata[track->last_stsd_index] =
8848 145 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
145 if (!track->extradata[track->last_stsd_index]) {
8850 return AVERROR(ENOMEM);
8851 }
8852 145 memcpy(track->extradata[track->last_stsd_index],
8853 145 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8854 145 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8855 0, AV_INPUT_BUFFER_PADDING_SIZE);
8856 }
8857 }
8858
8859
4/4
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 14 times.
406 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8860 97 av_channel_layout_compare(&track->par->ch_layout,
8861 97 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8862 295 continue;
8863
8864
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
46 for (int j = 0; j < mov->nb_streams; j++) {
8865 32 AVStream *stj= mov->tracks[j].st;
8866 32 MOVTrack *trackj= &mov->tracks[j];
8867
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 18 times.
32 if (j == i)
8868 14 continue;
8869
8870
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
18 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8871
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 ||
8872 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8873 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8874 )
8875 4 track->mono_as_fc = -1;
8876
8877
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
29 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8878 11 av_channel_layout_compare(&trackj->par->ch_layout,
8879 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8880
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
8881 )
8882 7 track->mono_as_fc++;
8883
8884
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
29 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8885 11 av_channel_layout_compare(&trackj->par->ch_layout,
8886 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8887 trackj->language != track->language ||
8888 trackj->tag != track->tag
8889 )
8890 18 continue;
8891 track->multichannel_as_mono++;
8892 }
8893 }
8894
8895
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 227 times.
247 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8897
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 227 times.
227 if ((ret = mov_write_identification(pb, s)) < 0)
8898 return ret;
8899 }
8900
8901
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 244 times.
247 if (mov->reserved_moov_size){
8902 3 mov->reserved_header_pos = avio_tell(pb);
8903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8904 avio_skip(pb, mov->reserved_moov_size);
8905 }
8906
8907
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 205 times.
247 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8908 /* If no fragmentation options have been set, set a default. */
8909
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 35 times.
42 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8910 FF_MOV_FLAG_FRAG_CUSTOM |
8911 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8912
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
7 !mov->max_fragment_duration && !mov->max_fragment_size)
8913 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8914
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8915 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8916
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8917 2 mov->mdat_pos = avio_tell(pb);
8918 // The free/wide header that later will be converted into an
8919 // mdat, covering the initial moov and all the fragments.
8920 2 avio_wb32(pb, 0);
8921
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8922 // Write an ftyp atom, hidden in a free/wide. This is neither
8923 // exposed while the file is written, as fragmented, nor when the
8924 // file is finalized into non-fragmented form. However, this allows
8925 // accessing a pristine, sequential ftyp+moov init segment, even
8926 // after the file is finalized. It also allows dumping the whole
8927 // contents of the mdat box, to get the fragmented form of the
8928 // file.
8929
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_identification(pb, s)) < 0)
8930 return ret;
8931 2 update_size(pb, mov->mdat_pos);
8932 }
8933
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 } else if (mov->mode != MODE_AVIF) {
8934
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 202 times.
205 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8935 3 mov->reserved_header_pos = avio_tell(pb);
8936 205 mov_write_mdat_tag(pb, mov);
8937 }
8938
8939 247 ff_parse_creation_time_metadata(s, &mov->time, 1);
8940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->time)
8941 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8942
8943
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->chapter_track)
8944
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8945 return ret;
8946
8947
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
247 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8948
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8949
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8950
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8951 return ret;
8952 2 hint_track++;
8953 }
8954 }
8955 }
8956
8957
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 241 times.
247 if (mov->nb_meta_tmcd) {
8958 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8959 "timecode", NULL, 0);
8960 /* Initialize the tmcd tracks */
8961
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8962 8 AVStream *st = mov->tracks[i].st;
8963 8 t = global_tcr;
8964
8965
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8966 AVTimecode tc;
8967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8968 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8970 continue;
8971
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8972 continue;
8973
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8974 return ret;
8975 6 tmcd_track++;
8976 }
8977 }
8978 }
8979
8980 247 avio_flush(pb);
8981
8982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 247 times.
247 if (mov->flags & FF_MOV_FLAG_ISML)
8983 mov_write_isml_manifest(pb, mov, s);
8984
8985
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 210 times.
247 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8986
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 20 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8987
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8988 return ret;
8989 17 mov->moov_written = 1;
8990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8991 mov->reserved_header_pos = avio_tell(pb);
8992 }
8993
8994 247 return 0;
8995 }
8996
8997 31 static int get_moov_size(AVFormatContext *s)
8998 {
8999 int ret;
9000 AVIOContext *moov_buf;
9001 31 MOVMuxContext *mov = s->priv_data;
9002
9003
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
9004 return ret;
9005
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
9006 return ret;
9007 31 return ffio_close_null_buf(moov_buf);
9008 }
9009
9010 static int get_sidx_size(AVFormatContext *s)
9011 {
9012 int ret;
9013 AVIOContext *buf;
9014 MOVMuxContext *mov = s->priv_data;
9015
9016 if ((ret = ffio_open_null_buf(&buf)) < 0)
9017 return ret;
9018 mov_write_sidx_tags(buf, mov, -1, 0);
9019 return ffio_close_null_buf(buf);
9020 }
9021
9022 /*
9023 * This function gets the moov size if moved to the top of the file: the chunk
9024 * offset table can switch between stco (32-bit entries) to co64 (64-bit
9025 * entries) when the moov is moved to the beginning, so the size of the moov
9026 * would change. It also updates the chunk offset tables.
9027 */
9028 3 static int compute_moov_size(AVFormatContext *s)
9029 {
9030 int i, moov_size, moov_size2;
9031 3 MOVMuxContext *mov = s->priv_data;
9032
9033 3 moov_size = get_moov_size(s);
9034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9035 return moov_size;
9036
9037
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
9038 8 mov->tracks[i].data_offset += moov_size;
9039
9040 3 moov_size2 = get_moov_size(s);
9041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
9042 return moov_size2;
9043
9044 /* if the size changed, we just switched from stco to co64 and need to
9045 * update the offsets */
9046
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
9047 for (i = 0; i < mov->nb_tracks; i++)
9048 mov->tracks[i].data_offset += moov_size2 - moov_size;
9049
9050 3 return moov_size2;
9051 }
9052
9053 static int compute_sidx_size(AVFormatContext *s)
9054 {
9055 int i, sidx_size;
9056 MOVMuxContext *mov = s->priv_data;
9057
9058 sidx_size = get_sidx_size(s);
9059 if (sidx_size < 0)
9060 return sidx_size;
9061
9062 for (i = 0; i < mov->nb_tracks; i++)
9063 mov->tracks[i].data_offset += sidx_size;
9064
9065 return sidx_size;
9066 }
9067
9068 3 static int shift_data(AVFormatContext *s)
9069 {
9070 int moov_size;
9071 3 MOVMuxContext *mov = s->priv_data;
9072
9073
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
9074 moov_size = compute_sidx_size(s);
9075 else
9076 3 moov_size = compute_moov_size(s);
9077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9078 return moov_size;
9079
9080 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
9081 }
9082
9083 207 static void mov_write_mdat_size(AVFormatContext *s)
9084 {
9085 207 MOVMuxContext *mov = s->priv_data;
9086 207 AVIOContext *pb = s->pb;
9087
9088 /* Write size of mdat tag */
9089
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 if (mov->mdat_size + 8 <= UINT32_MAX) {
9090 207 avio_seek(pb, mov->mdat_pos, SEEK_SET);
9091 207 avio_wb32(pb, mov->mdat_size + 8);
9092
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 205 times.
207 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
9093 2 ffio_wfourcc(pb, "mdat"); // overwrite the original free/wide into a mdat
9094 } else {
9095 /* overwrite 'wide' placeholder atom */
9096 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
9097 /* special value: real atom size will be 64 bit value after
9098 * tag field */
9099 avio_wb32(pb, 1);
9100 ffio_wfourcc(pb, "mdat");
9101 avio_wb64(pb, mov->mdat_size + 16);
9102 }
9103 207 }
9104
9105 247 static int mov_write_trailer(AVFormatContext *s)
9106 {
9107 247 MOVMuxContext *mov = s->priv_data;
9108 247 AVIOContext *pb = s->pb;
9109 247 int res = 0;
9110 int i;
9111 int64_t moov_pos;
9112
9113 /*
9114 * Before actually writing the trailer, make sure that there are no
9115 * dangling subtitles, that need a terminating sample.
9116 */
9117
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (i = 0; i < mov->nb_tracks; i++) {
9118 318 MOVTrack *trk = &mov->tracks[i];
9119
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 317 times.
318 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
9120
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
9121 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
9122 1 trk->last_sample_is_subtitle_end = 1;
9123 }
9124 }
9125
9126 //Also check for a buffered EAC3 packet
9127
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 247 times.
565 for (i = 0; i < mov->nb_tracks; i++) {
9128 318 MOVTrack *trk = &mov->tracks[i];
9129
2/2
✓ Branch 0 taken 314 times.
✓ Branch 1 taken 4 times.
318 if (trk->par->codec_id != AV_CODEC_ID_EAC3)
9130 314 continue;
9131 4 struct eac3_info *info = trk->eac3_priv;
9132
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 if (!info || !info->pkt || !info->pkt->size)
9133 4 continue;
9134
9135 av_packet_move_ref(mov->pkt, info->pkt);
9136 info->eof = 1;
9137 res = mov_write_single_packet(s, mov->pkt);
9138 if (res < 0)
9139 return res;
9140
9141 av_packet_unref(mov->pkt);
9142 }
9143
9144 // Check if we have any tracks that require squashing.
9145 // In that case, we'll have to write the packet here.
9146
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 247 times.
247 if ((res = mov_write_squashed_packets(s)) < 0)
9147 return res;
9148
9149 // If there were no chapters when the header was written, but there
9150 // are chapters now, write them in the trailer. This only works
9151 // when we are not doing fragments.
9152
4/4
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 204 times.
✓ Branch 3 taken 42 times.
247 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
9153
3/4
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
204 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
9154 mov->chapter_track = mov->nb_tracks++;
9155 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9156 return res;
9157 }
9158 }
9159
9160
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 205 times.
247 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
9161
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9162
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 205 times.
207 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9163 2 mov_auto_flush_fragment(s, 1);
9164 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
9165
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
9166 4 MOVTrack *track = &mov->tracks[i];
9167 4 track->data_offset = 0;
9168 4 av_free(track->cluster);
9169 4 track->cluster = track->cluster_written;
9170 4 track->entry = track->entry_written;
9171 4 track->cluster_written = NULL;
9172 4 track->entry_written = 0;
9173 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
9174 }
9175 // Clear the empty_moov flag, as we do want the moov to include
9176 // all the samples at this point.
9177 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
9178 }
9179
9180 207 moov_pos = avio_tell(pb);
9181
9182
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 2 times.
207 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
9183 205 mov_write_mdat_size(s);
9184
9185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
9186
9187
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 204 times.
207 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
9188 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
9189 3 res = shift_data(s);
9190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
9191 return res;
9192 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9193
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9194 return res;
9195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 } else if (mov->reserved_moov_size > 0) {
9196 int64_t size;
9197 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9198 return res;
9199 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
9200 if (size < 8){
9201 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
9202 return AVERROR(EINVAL);
9203 }
9204 avio_wb32(pb, size);
9205 ffio_wfourcc(pb, "free");
9206 ffio_fill(pb, 0, size - 8);
9207 avio_seek(pb, moov_pos, SEEK_SET);
9208 } else {
9209
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
204 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9210 return res;
9211 }
9212
9213
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 205 times.
207 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9214 // With hybrid fragmentation, only write the mdat size (hiding
9215 // the original moov and all the fragments within the mdat)
9216 // after we've successfully written the complete moov, to avoid
9217 // risk for an unreadable file if writing the final moov fails.
9218 2 mov_write_mdat_size(s);
9219 }
9220
9221 207 res = 0;
9222 } else {
9223 40 mov_auto_flush_fragment(s, 1);
9224
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 40 times.
113 for (i = 0; i < mov->nb_tracks; i++)
9225 73 mov->tracks[i].data_offset = 0;
9226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
9227 int64_t end;
9228 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
9229 res = shift_data(s);
9230 if (res < 0)
9231 return res;
9232 end = avio_tell(pb);
9233 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9234 mov_write_sidx_tags(pb, mov, -1, 0);
9235 avio_seek(pb, end, SEEK_SET);
9236 }
9237
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1 times.
40 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
9238 39 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
9239 39 res = mov_write_mfra_tag(pb, mov);
9240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (res < 0)
9241 return res;
9242 }
9243 }
9244
9245 247 return res;
9246 }
9247
9248 263 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
9249 const AVPacket *pkt)
9250 {
9251 263 int ret = 1;
9252
9253
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 246 times.
263 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
9254
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
9255 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
9256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
9257 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
9258 }
9259
9260 263 return ret;
9261 }
9262
9263 #if CONFIG_AVIF_MUXER
9264 static int avif_write_trailer(AVFormatContext *s)
9265 {
9266 AVIOContext *pb = s->pb;
9267 MOVMuxContext *mov = s->priv_data;
9268 int64_t pos_backup, extent_offsets[2];
9269 uint8_t *buf;
9270 int buf_size, moov_size;
9271
9272 if (mov->moov_written) return 0;
9273
9274 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
9275 if (mov->is_animated_avif && mov->nb_streams > 1) {
9276 // For animated avif with alpha channel, we need to write a tref tag
9277 // with type "auxl".
9278 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[1], MKTAG('a', 'u', 'x', 'l'));
9279 if (!tag)
9280 return AVERROR(ENOMEM);
9281
9282 int ret = mov_add_tref_id(mov, tag, 1);
9283 if (ret < 0)
9284 return ret;
9285 }
9286 mov_write_identification(pb, s);
9287 mov_write_meta_tag(pb, mov, s);
9288
9289 moov_size = get_moov_size(s);
9290 for (int i = 0; i < mov->nb_tracks; i++)
9291 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
9292
9293 if (mov->is_animated_avif) {
9294 int ret;
9295 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9296 return ret;
9297 }
9298
9299 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
9300 avio_wb32(pb, buf_size + 8);
9301 ffio_wfourcc(pb, "mdat");
9302
9303 // The offset for the YUV planes is the starting position of mdat.
9304 extent_offsets[0] = avio_tell(pb);
9305 // The offset for alpha plane is YUV offset + YUV size.
9306 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
9307
9308 avio_write(pb, buf, buf_size);
9309
9310 // write extent offsets.
9311 pos_backup = avio_tell(pb);
9312 for (int i = 0; i < mov->nb_streams; i++) {
9313 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
9314 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
9315 return AVERROR_INVALIDDATA;
9316 }
9317 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
9318 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
9319 }
9320 avio_seek(pb, pos_backup, SEEK_SET);
9321
9322 return 0;
9323 }
9324 #endif
9325
9326 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
9327 static const AVCodecTag codec_3gp_tags[] = {
9328 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
9329 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9330 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9331 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9332 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
9333 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
9334 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9335 { AV_CODEC_ID_NONE, 0 },
9336 };
9337 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
9338 #endif
9339
9340 static const AVCodecTag codec_mp4_tags[] = {
9341 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
9342 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
9343 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
9344 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
9345 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
9346 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
9347 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
9348 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
9349 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
9350 { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') },
9351 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
9352 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
9353 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
9354 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
9355 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
9356 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
9357 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
9358 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
9359 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
9360 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
9361 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
9362 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
9363 { AV_CODEC_ID_APPLE_APAC, MKTAG('a', 'p', 'a', 'c') },
9364 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
9365 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
9366 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
9367 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
9368 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
9369 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
9370 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
9371 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
9372 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
9373 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
9374 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
9375 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
9376 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
9377 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
9378 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
9379 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
9380 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
9381 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
9382 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
9383 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
9384
9385 /* ISO/IEC 23003-5 integer formats */
9386 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
9387 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
9388 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
9389 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
9390 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
9391 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
9392 /* ISO/IEC 23003-5 floating-point formats */
9393 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
9394 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
9395 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
9396 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
9397
9398 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
9399
9400 { AV_CODEC_ID_NONE, 0 },
9401 };
9402 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
9403 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
9404 #endif
9405
9406 static const AVCodecTag codec_ism_tags[] = {
9407 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
9408 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
9409 { AV_CODEC_ID_NONE , 0 },
9410 };
9411
9412 static const AVCodecTag codec_ipod_tags[] = {
9413 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9414 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9415 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9416 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
9417 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
9418 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9419 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
9420 { AV_CODEC_ID_NONE, 0 },
9421 };
9422
9423 static const AVCodecTag codec_f4v_tags[] = {
9424 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
9425 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9426 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9427 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
9428 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
9429 { AV_CODEC_ID_NONE, 0 },
9430 };
9431
9432 #if CONFIG_AVIF_MUXER
9433
9434 static const AVOption avif_options[] = {
9435 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
9436 { "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 },
9437 { NULL },
9438 };
9439 static const AVCodecTag codec_avif_tags[] = {
9440 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
9441 { AV_CODEC_ID_NONE, 0 },
9442 };
9443 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
9444
9445 static const AVClass mov_avif_muxer_class = {
9446 .class_name = "avif muxer",
9447 .item_name = av_default_item_name,
9448 .option = avif_options,
9449 .version = LIBAVUTIL_VERSION_INT,
9450 };
9451 #endif
9452
9453 #if CONFIG_MOV_MUXER
9454 const FFOutputFormat ff_mov_muxer = {
9455 .p.name = "mov",
9456 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
9457 .p.extensions = "mov",
9458 .priv_data_size = sizeof(MOVMuxContext),
9459 .p.audio_codec = AV_CODEC_ID_AAC,
9460 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9461 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9462 .init = mov_init,
9463 .write_header = mov_write_header,
9464 .write_packet = mov_write_packet,
9465 .write_trailer = mov_write_trailer,
9466 .deinit = mov_free,
9467 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9468 .p.codec_tag = (const AVCodecTag* const []){
9469 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
9470 },
9471 .check_bitstream = mov_check_bitstream,
9472 .p.priv_class = &mov_isobmff_muxer_class,
9473 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9474 };
9475 #endif
9476 #if CONFIG_TGP_MUXER
9477 const FFOutputFormat ff_tgp_muxer = {
9478 .p.name = "3gp",
9479 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9480 .p.extensions = "3gp",
9481 .priv_data_size = sizeof(MOVMuxContext),
9482 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9483 .p.video_codec = AV_CODEC_ID_H263,
9484 .init = mov_init,
9485 .write_header = mov_write_header,
9486 .write_packet = mov_write_packet,
9487 .write_trailer = mov_write_trailer,
9488 .deinit = mov_free,
9489 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9490 .p.codec_tag = codec_3gp_tags_list,
9491 .check_bitstream = mov_check_bitstream,
9492 .p.priv_class = &mov_isobmff_muxer_class,
9493 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9494 };
9495 #endif
9496 #if CONFIG_MP4_MUXER
9497 const FFOutputFormat ff_mp4_muxer = {
9498 .p.name = "mp4",
9499 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9500 .p.mime_type = "video/mp4",
9501 .p.extensions = "mp4",
9502 .priv_data_size = sizeof(MOVMuxContext),
9503 .p.audio_codec = AV_CODEC_ID_AAC,
9504 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9505 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9506 .init = mov_init,
9507 .write_header = mov_write_header,
9508 .write_packet = mov_write_packet,
9509 .write_trailer = mov_write_trailer,
9510 .deinit = mov_free,
9511 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9512 .p.codec_tag = mp4_codec_tags_list,
9513 .check_bitstream = mov_check_bitstream,
9514 .p.priv_class = &mov_isobmff_muxer_class,
9515 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9516 };
9517 #endif
9518 #if CONFIG_PSP_MUXER
9519 const FFOutputFormat ff_psp_muxer = {
9520 .p.name = "psp",
9521 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9522 .p.extensions = "mp4,psp",
9523 .priv_data_size = sizeof(MOVMuxContext),
9524 .p.audio_codec = AV_CODEC_ID_AAC,
9525 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9526 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9527 .init = mov_init,
9528 .write_header = mov_write_header,
9529 .write_packet = mov_write_packet,
9530 .write_trailer = mov_write_trailer,
9531 .deinit = mov_free,
9532 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9533 .p.codec_tag = mp4_codec_tags_list,
9534 .check_bitstream = mov_check_bitstream,
9535 .p.priv_class = &mov_isobmff_muxer_class,
9536 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9537 };
9538 #endif
9539 #if CONFIG_TG2_MUXER
9540 const FFOutputFormat ff_tg2_muxer = {
9541 .p.name = "3g2",
9542 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9543 .p.extensions = "3g2",
9544 .priv_data_size = sizeof(MOVMuxContext),
9545 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9546 .p.video_codec = AV_CODEC_ID_H263,
9547 .init = mov_init,
9548 .write_header = mov_write_header,
9549 .write_packet = mov_write_packet,
9550 .write_trailer = mov_write_trailer,
9551 .deinit = mov_free,
9552 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9553 .p.codec_tag = codec_3gp_tags_list,
9554 .check_bitstream = mov_check_bitstream,
9555 .p.priv_class = &mov_isobmff_muxer_class,
9556 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9557 };
9558 #endif
9559 #if CONFIG_IPOD_MUXER
9560 const FFOutputFormat ff_ipod_muxer = {
9561 .p.name = "ipod",
9562 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9563 .p.mime_type = "video/mp4",
9564 .p.extensions = "m4v,m4a,m4b",
9565 .priv_data_size = sizeof(MOVMuxContext),
9566 .p.audio_codec = AV_CODEC_ID_AAC,
9567 .p.video_codec = AV_CODEC_ID_H264,
9568 .init = mov_init,
9569 .write_header = mov_write_header,
9570 .write_packet = mov_write_packet,
9571 .write_trailer = mov_write_trailer,
9572 .deinit = mov_free,
9573 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9574 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9575 .check_bitstream = mov_check_bitstream,
9576 .p.priv_class = &mov_isobmff_muxer_class,
9577 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9578 };
9579 #endif
9580 #if CONFIG_ISMV_MUXER
9581 const FFOutputFormat ff_ismv_muxer = {
9582 .p.name = "ismv",
9583 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9584 .p.mime_type = "video/mp4",
9585 .p.extensions = "ismv,isma",
9586 .priv_data_size = sizeof(MOVMuxContext),
9587 .p.audio_codec = AV_CODEC_ID_AAC,
9588 .p.video_codec = AV_CODEC_ID_H264,
9589 .init = mov_init,
9590 .write_header = mov_write_header,
9591 .write_packet = mov_write_packet,
9592 .write_trailer = mov_write_trailer,
9593 .deinit = mov_free,
9594 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9595 .p.codec_tag = (const AVCodecTag* const []){
9596 codec_mp4_tags, codec_ism_tags, 0 },
9597 .check_bitstream = mov_check_bitstream,
9598 .p.priv_class = &mov_isobmff_muxer_class,
9599 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9600 };
9601 #endif
9602 #if CONFIG_F4V_MUXER
9603 const FFOutputFormat ff_f4v_muxer = {
9604 .p.name = "f4v",
9605 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9606 .p.mime_type = "application/f4v",
9607 .p.extensions = "f4v",
9608 .priv_data_size = sizeof(MOVMuxContext),
9609 .p.audio_codec = AV_CODEC_ID_AAC,
9610 .p.video_codec = AV_CODEC_ID_H264,
9611 .init = mov_init,
9612 .write_header = mov_write_header,
9613 .write_packet = mov_write_packet,
9614 .write_trailer = mov_write_trailer,
9615 .deinit = mov_free,
9616 .p.flags = AVFMT_GLOBALHEADER,
9617 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9618 .check_bitstream = mov_check_bitstream,
9619 .p.priv_class = &mov_isobmff_muxer_class,
9620 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9621 };
9622 #endif
9623 #if CONFIG_AVIF_MUXER
9624 const FFOutputFormat ff_avif_muxer = {
9625 .p.name = "avif",
9626 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9627 .p.mime_type = "image/avif",
9628 .p.extensions = "avif",
9629 .priv_data_size = sizeof(MOVMuxContext),
9630 .p.video_codec = AV_CODEC_ID_AV1,
9631 .init = mov_init,
9632 .write_header = mov_write_header,
9633 .write_packet = mov_write_packet,
9634 .write_trailer = avif_write_trailer,
9635 .deinit = mov_free,
9636 .p.flags = AVFMT_GLOBALHEADER,
9637 .p.codec_tag = codec_avif_tags_list,
9638 .p.priv_class = &mov_avif_muxer_class,
9639 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9640 };
9641 #endif
9642