FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2026-10-17 12:12:06
Exec Total Coverage
Lines: 4047 5882 68.8%
Functions: 191 243 78.6%
Branches: 2426 4065 59.7%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <math.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29
30 #include "movenc.h"
31 #include "avformat.h"
32 #include "avio_internal.h"
33 #include "dovi_isom.h"
34 #include "riff.h"
35 #include "avio.h"
36 #include "iamf_writer.h"
37 #include "isom.h"
38 #include "av1.h"
39 #include "avc.h"
40 #include "evc.h"
41 #include "apv.h"
42 #include "lcevc.h"
43 #include "libavcodec/ac3_parser_internal.h"
44 #include "libavcodec/dnxhddata.h"
45 #include "libavcodec/flac.h"
46 #include "libavcodec/mpegaudiodata.h"
47 #include "libavcodec/get_bits.h"
48
49 #include "libavcodec/internal.h"
50 #include "libavcodec/put_bits.h"
51 #include "libavcodec/vc1_common.h"
52 #include "libavcodec/raw.h"
53 #include "internal.h"
54 #include "libavutil/avstring.h"
55 #include "libavutil/channel_layout.h"
56 #include "libavutil/csp.h"
57 #include "libavutil/intfloat.h"
58 #include "libavutil/mathematics.h"
59 #include "libavutil/mem.h"
60 #include "libavutil/opt.h"
61 #include "libavutil/dict.h"
62 #include "libavutil/pixdesc.h"
63 #include "libavutil/stereo3d.h"
64 #include "libavutil/timecode.h"
65 #include "libavutil/dovi_meta.h"
66 #include "libavutil/uuid.h"
67 #include "hevc.h"
68 #include "rtpenc.h"
69 #include "nal.h"
70 #include "mov_chan.h"
71 #include "movenc_ttml.h"
72 #include "mux.h"
73 #include "rawutils.h"
74 #include "ttmlenc.h"
75 #include "version.h"
76 #include "vpcc.h"
77 #include "vvc.h"
78
79 static const AVOption options[] = {
80 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
82 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
83 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
84 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
85 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
87 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
88 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
89 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
90 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
91 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
92 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
104 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
105 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
106 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
107 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
116 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
117 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
118 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
119 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
120 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
121 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
122 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
125 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
126 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
127 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
128 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
129 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
130 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
131 { NULL },
132 };
133
134 static const AVClass mov_isobmff_muxer_class = {
135 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
136 .item_name = av_default_item_name,
137 .option = options,
138 .version = LIBAVUTIL_VERSION_INT,
139 };
140
141 static int get_moov_size(AVFormatContext *s);
142 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
143
144 31 static int utf8len(const uint8_t *b)
145 {
146 31 int len = 0;
147 int val;
148
2/2
✓ Branch 0 taken 581 times.
✓ Branch 1 taken 31 times.
612 while (*b) {
149
3/8
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 581 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 581 times.
581 GET_UTF8(val, *b++, return -1;)
150 581 len++;
151 }
152 31 return len;
153 }
154
155 //FIXME support 64 bit variant with wide placeholders
156 11906 static int64_t update_size(AVIOContext *pb, int64_t pos)
157 {
158 11906 int64_t curpos = avio_tell(pb);
159 11906 avio_seek(pb, pos, SEEK_SET);
160 11906 avio_wb32(pb, curpos - pos); /* rewrite size */
161 11906 avio_seek(pb, curpos, SEEK_SET);
162
163 11906 return curpos - pos;
164 }
165
166 588 static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version)
167 {
168 588 int64_t curpos = avio_tell(pb);
169 588 avio_seek(pb, pos, SEEK_SET);
170 588 avio_wb32(pb, curpos - pos); /* rewrite size */
171 588 avio_skip(pb, 4);
172 588 avio_w8(pb, version); /* rewrite version */
173 588 avio_seek(pb, curpos, SEEK_SET);
174
175 588 return curpos - pos;
176 }
177
178 588 static int co64_required(const MOVTrack *track)
179 {
180
3/4
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 308 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 280 times.
588 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
181 ✗ return 1;
182 588 return 0;
183 }
184
185 28732 static int is_cover_image(const AVStream *st)
186 {
187 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
188 * is encoded as sparse video track */
189
3/4
✓ Branch 0 taken 28732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 28720 times.
28732 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
190 }
191
192 6 static int rtp_hinting_needed(const AVStream *st)
193 {
194 /* Add hint tracks for each real audio and video stream */
195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
196 ✗ return 0;
197
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
198
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
199 }
200
201 /* Chunk offset atom */
202 588 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
203 {
204 int i;
205 588 int mode64 = co64_required(track); // use 32 bit size variant if possible
206 588 int64_t pos = avio_tell(pb);
207 588 avio_wb32(pb, 0); /* size */
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (mode64)
209 ✗ ffio_wfourcc(pb, "co64");
210 else
211 588 ffio_wfourcc(pb, "stco");
212 588 avio_wb32(pb, 0); /* version & flags */
213 588 avio_wb32(pb, track->chunkCount); /* entry count */
214
2/2
✓ Branch 0 taken 18207 times.
✓ Branch 1 taken 588 times.
18795 for (i = 0; i < track->entry; i++) {
215
2/2
✓ Branch 0 taken 15174 times.
✓ Branch 1 taken 3033 times.
18207 if (!track->cluster[i].chunkNum)
216 15174 continue;
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3033 times.
3033 if (mode64 == 1)
218 ✗ avio_wb64(pb, track->cluster[i].pos + track->data_offset);
219 else
220 3033 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
221 }
222 588 return update_size(pb, pos);
223 }
224
225 /* Sample size atom */
226 588 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
227 {
228 588 int equalChunks = 1;
229 588 int i, j, entries = 0, tst = -1, oldtst = -1;
230
231 588 int64_t pos = avio_tell(pb);
232 588 avio_wb32(pb, 0); /* size */
233 588 ffio_wfourcc(pb, "stsz");
234 588 avio_wb32(pb, 0); /* version & flags */
235
236
2/2
✓ Branch 0 taken 18207 times.
✓ Branch 1 taken 588 times.
18795 for (i = 0; i < track->entry; i++) {
237 18207 tst = track->cluster[i].size / track->cluster[i].entries;
238
4/4
✓ Branch 0 taken 17927 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 12786 times.
✓ Branch 3 taken 5141 times.
18207 if (oldtst != -1 && tst != oldtst)
239 12786 equalChunks = 0;
240 18207 oldtst = tst;
241 18207 entries += track->cluster[i].entries;
242 }
243
4/4
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 160 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 308 times.
708 if (equalChunks && track->entry) {
244
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
245 120 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
246 120 avio_wb32(pb, sSize); // sample size
247 120 avio_wb32(pb, entries); // sample count
248 } else {
249 468 avio_wb32(pb, 0); // sample size
250 468 avio_wb32(pb, entries); // sample count
251
2/2
✓ Branch 0 taken 14142 times.
✓ Branch 1 taken 468 times.
14610 for (i = 0; i < track->entry; i++) {
252
2/2
✓ Branch 0 taken 14142 times.
✓ Branch 1 taken 14142 times.
28284 for (j = 0; j < track->cluster[i].entries; j++) {
253 14142 avio_wb32(pb, track->cluster[i].size /
254 14142 track->cluster[i].entries);
255 }
256 }
257 }
258 588 return update_size(pb, pos);
259 }
260
261 /* Sample to chunk atom */
262 588 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
263 {
264 588 int index = 0, oldidx = -1, oldval = -1, i;
265 int64_t entryPos, curpos;
266
267 588 int64_t pos = avio_tell(pb);
268 588 avio_wb32(pb, 0); /* size */
269 588 ffio_wfourcc(pb, "stsc");
270 588 avio_wb32(pb, 0); // version & flags
271 588 entryPos = avio_tell(pb);
272 588 avio_wb32(pb, track->chunkCount); // entry count
273
2/2
✓ Branch 0 taken 18207 times.
✓ Branch 1 taken 588 times.
18795 for (i = 0; i < track->entry; i++) {
274
2/2
✓ Branch 0 taken 2191 times.
✓ Branch 1 taken 16016 times.
18207 if ((oldval != track->cluster[i].samples_in_chunk ||
275
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2189 times.
✓ Branch 2 taken 844 times.
✓ Branch 3 taken 15174 times.
18207 oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
276 844 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
277 844 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
278 844 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
279 844 oldval = track->cluster[i].samples_in_chunk;
280 844 oldidx = track->cluster[i].stsd_index;
281 844 index++;
282 }
283 }
284 588 curpos = avio_tell(pb);
285 588 avio_seek(pb, entryPos, SEEK_SET);
286 588 avio_wb32(pb, index); // rewrite size
287 588 avio_seek(pb, curpos, SEEK_SET);
288
289 588 return update_size(pb, pos);
290 }
291
292 /* Sync sample atom */
293 71 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
294 {
295 int64_t curpos, entryPos;
296 71 int i, index = 0;
297 71 int64_t pos = avio_tell(pb);
298 71 avio_wb32(pb, 0); // size
299
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
300 71 avio_wb32(pb, 0); // version & flags
301 71 entryPos = avio_tell(pb);
302 71 avio_wb32(pb, track->entry); // entry count
303
2/2
✓ Branch 0 taken 3542 times.
✓ Branch 1 taken 71 times.
3613 for (i = 0; i < track->entry; i++) {
304
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 3314 times.
3542 if (track->cluster[i].flags & flag) {
305 228 avio_wb32(pb, i + 1);
306 228 index++;
307 }
308 }
309 71 curpos = avio_tell(pb);
310 71 avio_seek(pb, entryPos, SEEK_SET);
311 71 avio_wb32(pb, index); // rewrite size
312 71 avio_seek(pb, curpos, SEEK_SET);
313 71 return update_size(pb, pos);
314 }
315
316 /* Sample dependency atom */
317 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
318 {
319 int i;
320 uint8_t leading, dependent, reference, redundancy;
321 3 int64_t pos = avio_tell(pb);
322 3 avio_wb32(pb, 0); // size
323 3 ffio_wfourcc(pb, "sdtp");
324 3 avio_wb32(pb, 0); // version & flags
325
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
326 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
327 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
328
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
329 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
330 }
331
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
332 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
333 }
334 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
335 13 (reference << 2) | redundancy);
336 }
337 3 return update_size(pb, pos);
338 }
339
340 #if CONFIG_IAMFENC
341 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
342 {
343 AVIOContext *dyn_bc;
344 5 int64_t pos = avio_tell(pb);
345 5 uint8_t *dyn_buf = NULL;
346 int dyn_size;
347 5 int ret = avio_open_dyn_buf(&dyn_bc);
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
349 ✗ return ret;
350
351 5 avio_wb32(pb, 0);
352 5 ffio_wfourcc(pb, "iacb");
353 5 avio_w8(pb, 1); // configurationVersion
354
355 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0) {
357 ✗ ffio_free_dyn_buf(&dyn_bc);
358 ✗ return ret;
359 }
360
361 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
362 5 ffio_write_leb(pb, dyn_size);
363 5 avio_write(pb, dyn_buf, dyn_size);
364 5 av_free(dyn_buf);
365
366 5 return update_size(pb, pos);
367 }
368 #endif
369
370 ✗ static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
371 {
372 ✗ avio_wb32(pb, 0x11); /* size */
373 ✗ if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
374 ✗ else ffio_wfourcc(pb, "damr");
375 ✗ ffio_wfourcc(pb, "FFMP");
376 ✗ avio_w8(pb, 0); /* decoder version */
377
378 ✗ avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
379 ✗ avio_w8(pb, 0x00); /* Mode change period (no restriction) */
380 ✗ avio_w8(pb, 0x01); /* Frames per sample */
381 ✗ return 0x11;
382 }
383
384 struct eac3_info {
385 AVPacket *pkt;
386 uint8_t eof;
387 uint8_t ec3_done;
388 uint8_t num_blocks;
389
390 /* Layout of the EC3SpecificBox */
391 /* maximum bitrate */
392 uint16_t data_rate;
393 int8_t ac3_bit_rate_code;
394 /* number of independent substreams */
395 uint8_t num_ind_sub;
396 struct {
397 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
398 uint8_t fscod;
399 /* bit stream identification 5 bits */
400 uint8_t bsid;
401 /* one bit reserved */
402 /* audio service mixing (not supported yet) 1 bit */
403 /* bit stream mode 3 bits */
404 uint8_t bsmod;
405 /* audio coding mode 3 bits */
406 uint8_t acmod;
407 /* sub woofer on 1 bit */
408 uint8_t lfeon;
409 /* 3 bits reserved */
410 /* number of dependent substreams associated with this substream 4 bits */
411 uint8_t num_dep_sub;
412 /* channel locations of the dependent substream(s), if any, 9 bits */
413 uint16_t chan_loc;
414 /* if there is no dependent substream, then one bit reserved instead */
415 } substream[1]; /* TODO: support 8 independent substreams */
416 /* indicates the decoding complexity, 8 bits */
417 uint8_t complexity_index_type_a;
418 };
419
420 7 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
421 {
422 7 struct eac3_info *info = track->eac3_priv;
423 PutBitContext pbc;
424 uint8_t buf[3];
425
426
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!info || !info->ec3_done) {
427 ✗ av_log(s, AV_LOG_ERROR,
428 "Cannot write moov atom before AC3 packets."
429 " Set the delay_moov flag to fix this.\n");
430 ✗ return AVERROR(EINVAL);
431 }
432
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->substream[0].bsid > 8) {
434 ✗ av_log(s, AV_LOG_ERROR,
435 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
436 "ISOBMFF specification in ETSI TS 102 366!\n",
437 ✗ info->substream[0].bsid);
438 ✗ return AVERROR(EINVAL);
439 }
440
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (info->ac3_bit_rate_code < 0) {
442 ✗ av_log(s, AV_LOG_ERROR,
443 "No valid AC3 bit rate code for data rate of %d!\n",
444 ✗ info->data_rate);
445 ✗ return AVERROR(EINVAL);
446 }
447
448 7 avio_wb32(pb, 11);
449 7 ffio_wfourcc(pb, "dac3");
450
451 7 init_put_bits(&pbc, buf, sizeof(buf));
452 7 put_bits(&pbc, 2, info->substream[0].fscod);
453 7 put_bits(&pbc, 5, info->substream[0].bsid);
454 7 put_bits(&pbc, 3, info->substream[0].bsmod);
455 7 put_bits(&pbc, 3, info->substream[0].acmod);
456 7 put_bits(&pbc, 1, info->substream[0].lfeon);
457 7 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
458 7 put_bits(&pbc, 5, 0); // reserved
459
460 7 flush_put_bits(&pbc);
461 7 avio_write(pb, buf, sizeof(buf));
462
463 7 return 11;
464 }
465
466 1737 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
467 {
468 1737 AC3HeaderInfo *hdr = NULL;
469 struct eac3_info *info;
470 int num_blocks, ret;
471
472
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
1737 if (!track->eac3_priv) {
473
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
474 ✗ return AVERROR(ENOMEM);
475
476 10 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
477 }
478 1737 info = track->eac3_priv;
479
480
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1727 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
1737 if (!info->pkt && !(info->pkt = av_packet_alloc()))
481 ✗ return AVERROR(ENOMEM);
482
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (info->eof) {
484 av_assert1(!info->pkt->size);
485 ✗ ret = pkt->size;
486 ✗ goto end;
487 }
488
489
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1736 times.
1737 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
491 ✗ goto end;
492
493 /* drop the packets until we see a good one */
494
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
495 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
496 1 ret = 0;
497 } else
498 ✗ ret = AVERROR_INVALIDDATA;
499 1 goto end;
500 }
501
502 1736 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
503 1736 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
504 hdr->ac3_bit_rate_code);
505 1736 info->complexity_index_type_a = hdr->complexity_index_type_a;
506
507 1736 num_blocks = hdr->num_blocks;
508
509
2/2
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 14 times.
1736 if (!info->ec3_done) {
510 /* AC-3 substream must be the first one */
511
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
14 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
512 ✗ ret = AVERROR(EINVAL);
513 ✗ goto end;
514 }
515
516 /* this should always be the case, given that our AC-3 parser
517 * concatenates dependent frames to their independent parent */
518
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
519
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
520 /* substream ids must be incremental */
521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid > info->num_ind_sub + 1) {
522 ✗ ret = AVERROR(EINVAL);
523 ✗ goto end;
524 }
525
526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (hdr->substreamid == info->num_ind_sub + 1) {
527 //info->num_ind_sub++;
528 ✗ avpriv_request_sample(mov->fc, "Multiple independent substreams");
529 ✗ ret = AVERROR_PATCHWELCOME;
530 ✗ goto end;
531
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 } else if (hdr->substreamid < info->num_ind_sub ||
532
3/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 10 times.
14 hdr->substreamid == 0 && info->substream[0].bsid) {
533 4 info->ec3_done = 1;
534 4 goto concatenate;
535 }
536 } else {
537 ✗ if (hdr->substreamid != 0) {
538 ✗ avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
539 ✗ ret = AVERROR_PATCHWELCOME;
540 ✗ goto end;
541 }
542 }
543
544 /* fill the info needed for the "dec3" atom */
545 10 info->substream[hdr->substreamid].fscod = hdr->sr_code;
546 10 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
547 10 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
548 10 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
549 10 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
550
551
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (track->par->codec_id == AV_CODEC_ID_AC3) {
552 // with AC-3 we only require the information of a single packet,
553 // so we can finish as soon as the basic values of the bit stream
554 // have been set to the track's informational structure.
555 6 info->ec3_done = 1;
556 6 goto concatenate;
557 }
558
559 /* Parse dependent substream(s), if any */
560
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (pkt->size != hdr->frame_size) {
561 1 int cumul_size = hdr->frame_size;
562 1 int parent = hdr->substreamid;
563
564
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (cumul_size != pkt->size) {
565 1 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
567 ✗ goto end;
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
569 ✗ ret = AVERROR(EINVAL);
570 ✗ goto end;
571 }
572 1 info->substream[parent].num_dep_sub++;
573 1 ret /= 8;
574
575 /* get the dependent stream channel map, if exists */
576
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (hdr->channel_map_present) {
577 /* chanmap is a 16-bit field read MSB-first, so flag index
578 * i sits at bit (15 - i), matching the indexing of
579 * ff_eac3_custom_channel_map_locations. chan_loc bits 0-7
580 * carry flag indices 5-12, i.e. chanmap bit (10 - j).
581 * The mapping is not contiguous at the top: index 13
582 * (Lts/Rts) has no chan_loc bit and is skipped, and
583 * chan_loc bit 8 carries LFE2, which is index 14 and so
584 * chanmap bit 1. */
585
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for (int j = 0; j < 8; j++) {
586
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if ((hdr->channel_map >> (10 - j)) & 1)
587 1 info->substream[parent].chan_loc |= 1 << j;
588 }
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((hdr->channel_map >> 1) & 1)
590 ✗ info->substream[parent].chan_loc |= 1 << 8;
591 } else {
592 ✗ info->substream[parent].chan_loc |= hdr->channel_mode;
593 }
594 1 cumul_size += hdr->frame_size;
595 }
596 }
597 }
598
599 1726 concatenate:
600
2/4
✓ Branch 0 taken 1736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1736 times.
✗ Branch 3 not taken.
1736 if (!info->num_blocks && num_blocks == 6) {
601 1736 ret = pkt->size;
602 1736 goto end;
603 }
604 ✗ else if (info->num_blocks + num_blocks > 6) {
605 ✗ ret = AVERROR_INVALIDDATA;
606 ✗ goto end;
607 }
608
609 ✗ if (!info->num_blocks) {
610 ✗ ret = av_packet_ref(info->pkt, pkt);
611 ✗ if (!ret)
612 ✗ info->num_blocks = num_blocks;
613 ✗ goto end;
614 } else {
615 const AVPacketSideData *sd;
616 ✗ int64_t duration = pkt->duration;
617 ✗ if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
618 ✗ goto end;
619 ✗ sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
620 ✗ if (sd && sd->size >= 10) {
621 ✗ uint8_t *buf = av_packet_new_side_data(info->pkt, AV_PKT_DATA_SKIP_SAMPLES, sd->size);
622 ✗ if (buf)
623 ✗ memcpy(buf, sd->data, sd->size);
624 ✗ if (track->par->frame_size)
625 ✗ duration = FFMAX(av_rescale_q(track->par->frame_size, (AVRational){ 1, track->par->sample_rate },
626 track->st->time_base), duration);
627 }
628 ✗ memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
629 ✗ info->num_blocks += num_blocks;
630 ✗ info->pkt->duration += duration;
631 ✗ if (info->num_blocks != 6)
632 ✗ goto end;
633 ✗ av_packet_unref(pkt);
634 ✗ av_packet_move_ref(pkt, info->pkt);
635 ✗ info->num_blocks = 0;
636 }
637 ✗ ret = pkt->size;
638
639 1737 end:
640 1737 av_free(hdr);
641
642 1737 return ret;
643 }
644
645 4 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
646 {
647 PutBitContext pbc;
648 uint8_t *buf;
649 struct eac3_info *info;
650 int size, i;
651
652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->eac3_priv) {
653 ✗ av_log(s, AV_LOG_ERROR,
654 "Cannot write moov atom before EAC3 packets parsed.\n");
655 ✗ return AVERROR(EINVAL);
656 }
657
658 4 info = track->eac3_priv;
659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 size = 2 + (4 * (info->num_ind_sub + 1)) + (2 * !!info->complexity_index_type_a);
660 4 buf = av_malloc(size);
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!buf) {
662 ✗ return AVERROR(ENOMEM);
663 }
664
665 4 init_put_bits(&pbc, buf, size);
666 4 put_bits(&pbc, 13, info->data_rate);
667 4 put_bits(&pbc, 3, info->num_ind_sub);
668
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i <= info->num_ind_sub; i++) {
669 4 put_bits(&pbc, 2, info->substream[i].fscod);
670 4 put_bits(&pbc, 5, info->substream[i].bsid);
671 4 put_bits(&pbc, 1, 0); /* reserved */
672 4 put_bits(&pbc, 1, 0); /* asvc */
673 4 put_bits(&pbc, 3, info->substream[i].bsmod);
674 4 put_bits(&pbc, 3, info->substream[i].acmod);
675 4 put_bits(&pbc, 1, info->substream[i].lfeon);
676 4 put_bits(&pbc, 3, 0); /* reserved */
677 4 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
678
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (!info->substream[i].num_dep_sub) {
679 3 put_bits(&pbc, 1, 0); /* reserved */
680 } else {
681 1 put_bits(&pbc, 9, info->substream[i].chan_loc);
682 }
683 }
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (info->complexity_index_type_a) {
685 ✗ put_bits(&pbc, 7, 0); /* reserved */
686 ✗ put_bits(&pbc, 1, 1); // flag_eac3_extension_type_a
687 ✗ put_bits(&pbc, 8, info->complexity_index_type_a);
688 }
689 4 flush_put_bits(&pbc);
690 4 size = put_bytes_output(&pbc);
691
692 4 avio_wb32(pb, size + 8);
693 4 ffio_wfourcc(pb, "dec3");
694 4 avio_write(pb, buf, size);
695
696 4 av_free(buf);
697
698 4 return size;
699 }
700
701 /**
702 * This function writes extradata "as is".
703 * Extradata must be formatted like a valid atom (with size and tag).
704 */
705 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
706 {
707 12 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
708 12 return track->extradata_size[track->last_stsd_index];
709 }
710
711 ✗ static int mov_write_enda_tag(AVIOContext *pb)
712 {
713 ✗ avio_wb32(pb, 10);
714 ✗ ffio_wfourcc(pb, "enda");
715 ✗ avio_wb16(pb, 1); /* little endian */
716 ✗ return 10;
717 }
718
719 2 static int mov_write_enda_tag_be(AVIOContext *pb)
720 {
721 2 avio_wb32(pb, 10);
722 2 ffio_wfourcc(pb, "enda");
723 2 avio_wb16(pb, 0); /* big endian */
724 2 return 10;
725 }
726
727 1017 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
728 {
729 1017 int i = 3;
730 1017 avio_w8(pb, tag);
731
2/2
✓ Branch 0 taken 3051 times.
✓ Branch 1 taken 1017 times.
4068 for (; i > 0; i--)
732 3051 avio_w8(pb, (size >> (7 * i)) | 0x80);
733 1017 avio_w8(pb, size & 0x7F);
734 1017 }
735
736 687 static unsigned compute_avg_bitrate(MOVTrack *track)
737 {
738 687 uint64_t size = 0;
739 int i;
740
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 633 times.
687 if (!track->track_duration)
741 54 return 0;
742
2/2
✓ Branch 0 taken 16965 times.
✓ Branch 1 taken 633 times.
17598 for (i = 0; i < track->entry; i++)
743 16965 size += track->cluster[i].size;
744 633 return size * 8 * track->timescale / track->track_duration;
745 }
746
747 struct mpeg4_bit_rate_values {
748 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
749 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
750 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
751 };
752
753 687 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
754 {
755 1374 const AVPacketSideData *sd = track->st ?
756 686 av_packet_side_data_get(track->st->codecpar->coded_side_data,
757 686 track->st->codecpar->nb_coded_side_data,
758
2/2
✓ Branch 0 taken 686 times.
✓ Branch 1 taken 1 times.
687 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
759
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 635 times.
687 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
760 687 struct mpeg4_bit_rate_values bit_rates = { 0 };
761
762 687 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
763
2/2
✓ Branch 0 taken 556 times.
✓ Branch 1 taken 131 times.
687 if (!bit_rates.avg_bit_rate) {
764 // if the average bit rate cannot be calculated at this point, such as
765 // in the case of fragmented MP4, utilize the following values as
766 // fall-back in priority order:
767 //
768 // 1. average bit rate property
769 // 2. bit rate (usually average over the whole clip)
770 // 3. maximum bit rate property
771
772
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 538 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
556 if (props && props->avg_bitrate) {
773 18 bit_rates.avg_bit_rate = props->avg_bitrate;
774
2/2
✓ Branch 0 taken 409 times.
✓ Branch 1 taken 129 times.
538 } else if (track->par->bit_rate) {
775 409 bit_rates.avg_bit_rate = track->par->bit_rate;
776
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
129 } else if (props && props->max_bitrate) {
777 ✗ bit_rates.avg_bit_rate = props->max_bitrate;
778 }
779 }
780
781 // (FIXME should be max rate in any 1 sec window)
782 687 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
783 bit_rates.avg_bit_rate);
784
785 // utilize values from properties if we have them available
786
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 635 times.
687 if (props) {
787 // no avg_bitrate signals that the track is VBR
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (!props->avg_bitrate)
789 ✗ bit_rates.avg_bit_rate = props->avg_bitrate;
790 52 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
791 props->max_bitrate);
792 52 bit_rates.buffer_size = props->buffer_size / 8;
793 }
794
795 687 return bit_rates;
796 }
797
798 306 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
799 {
800 306 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
801 306 int64_t pos = avio_tell(pb);
802 612 int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
803
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 207 times.
306 5 + track->extradata_size[track->last_stsd_index] : 0;
804
805 306 avio_wb32(pb, 0); // size
806 306 ffio_wfourcc(pb, "esds");
807 306 avio_wb32(pb, 0); // Version
808
809 // ES descriptor
810 306 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
811 306 avio_wb16(pb, track->track_id);
812 306 avio_w8(pb, 0x00); // flags (= no flags)
813
814 // DecoderConfig descriptor
815 306 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
816
817 // Object type indication
818
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 200 times.
306 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
819
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 105 times.
106 track->par->codec_id == AV_CODEC_ID_MP3) &&
820
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 200 times.
201 track->par->sample_rate > 24000)
821 1 avio_w8(pb, 0x6B); // 11172-3
822 else
823 305 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
824
825 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
826 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306 times.
306 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
828 ✗ avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
829
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 37 times.
306 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
830 269 avio_w8(pb, 0x15); // flags (= Audiostream)
831 else
832 37 avio_w8(pb, 0x11); // flags (= Visualstream)
833
834 306 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
835 306 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
836 306 avio_wb32(pb, bit_rates.avg_bit_rate);
837
838
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 207 times.
306 if (track->extradata_size[track->last_stsd_index]) {
839 // DecoderSpecific info descriptor
840 99 put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
841 99 avio_write(pb, track->extradata[track->last_stsd_index],
842 99 track->extradata_size[track->last_stsd_index]);
843 }
844
845 // SL descriptor
846 306 put_descr(pb, 0x06, 1);
847 306 avio_w8(pb, 0x02);
848 306 return update_size(pb, pos);
849 }
850
851 75 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
852 {
853
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 return codec_id == AV_CODEC_ID_PCM_S24LE ||
854
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 codec_id == AV_CODEC_ID_PCM_S32LE ||
855
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
150 codec_id == AV_CODEC_ID_PCM_F32LE ||
856 codec_id == AV_CODEC_ID_PCM_F64LE;
857 }
858
859 75 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
860 {
861
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
71 return codec_id == AV_CODEC_ID_PCM_S24BE ||
862
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 codec_id == AV_CODEC_ID_PCM_S32BE ||
863
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
146 codec_id == AV_CODEC_ID_PCM_F32BE ||
864 codec_id == AV_CODEC_ID_PCM_F64BE;
865 }
866
867 ✗ static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
868 {
869 int ret;
870 ✗ int64_t pos = avio_tell(pb);
871 ✗ avio_wb32(pb, 0);
872 ✗ avio_wl32(pb, track->tag); // store it byteswapped
873 ✗ track->par->codec_tag = av_bswap16(track->tag >> 16);
874 ✗ if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
875 ✗ return ret;
876 ✗ return update_size(pb, pos);
877 }
878
879 ✗ static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
880 {
881 int ret;
882 ✗ int64_t pos = avio_tell(pb);
883 ✗ avio_wb32(pb, 0);
884 ✗ ffio_wfourcc(pb, "wfex");
885 ✗ if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
886 ✗ return ret;
887 ✗ return update_size(pb, pos);
888 }
889
890 ✗ static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
891 {
892 ✗ int64_t pos = avio_tell(pb);
893 ✗ avio_wb32(pb, 0);
894 ✗ ffio_wfourcc(pb, "dfLa");
895 ✗ avio_w8(pb, 0); /* version */
896 ✗ avio_wb24(pb, 0); /* flags */
897
898 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
899 ✗ if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
900 ✗ return AVERROR_INVALIDDATA;
901
902 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
903 ✗ avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
904 ✗ avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
905 ✗ avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
906
907 ✗ return update_size(pb, pos);
908 }
909
910 ✗ static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
911 {
912 ✗ int64_t pos = avio_tell(pb);
913 int channels, channel_map;
914 ✗ avio_wb32(pb, 0);
915 ✗ ffio_wfourcc(pb, "dOps");
916 ✗ avio_w8(pb, 0); /* Version */
917 ✗ if (track->extradata_size[track->last_stsd_index] < 19) {
918 ✗ av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
919 ✗ return AVERROR_INVALIDDATA;
920 }
921 /* extradata contains an Ogg OpusHead, other than byte-ordering and
922 OpusHead's preceding magic/version, OpusSpecificBox is currently
923 identical. */
924 ✗ channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
925 ✗ channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
926
927 ✗ avio_w8(pb, channels); /* OuputChannelCount */
928 ✗ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
929 ✗ avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
930 ✗ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
931 ✗ avio_w8(pb, channel_map); /* ChannelMappingFamily */
932 /* Write the rest of the header out without byte-swapping. */
933 ✗ if (channel_map) {
934 ✗ if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
935 ✗ av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
936 ✗ return AVERROR_INVALIDDATA;
937 }
938 ✗ avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
939 }
940
941 ✗ return update_size(pb, pos);
942 }
943
944 ✗ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
945 {
946 ✗ int64_t pos = avio_tell(pb);
947 int length;
948 ✗ avio_wb32(pb, 0);
949 ✗ ffio_wfourcc(pb, "dmlp");
950
951 ✗ if (track->extradata_size[track->last_stsd_index] < 20) {
952 ✗ av_log(s, AV_LOG_ERROR,
953 "Cannot write moov atom before TrueHD packets."
954 " Set the delay_moov flag to fix this.\n");
955 ✗ return AVERROR(EINVAL);
956 }
957
958 ✗ length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
959 ✗ if (length < 20 || length > track->extradata_size[track->last_stsd_index])
960 ✗ return AVERROR_INVALIDDATA;
961
962 // Only TrueHD is supported
963 ✗ if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
964 ✗ return AVERROR_INVALIDDATA;
965
966 ✗ avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
967 ✗ avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
968 ✗ avio_wb32(pb, 0); /* reserved */
969
970 ✗ return update_size(pb, pos);
971 }
972
973 1 static int mov_write_mhac_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
974 {
975 1 int64_t pos = avio_tell(pb);
976 1 int layout = 0;
977
978
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->extradata_size[track->last_stsd_index] ||
979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->extradata_size[track->last_stsd_index] > UINT16_MAX) {
980 ✗ av_log(s, AV_LOG_ERROR,
981 "Invalid extradata size %d for MPEGH-H stream.\n",
982 ✗ track->extradata_size[track->last_stsd_index]);
983 ✗ return AVERROR(EINVAL);
984 }
985
986 1 avio_wb32(pb, 0);
987 1 ffio_wfourcc(pb, "mhaC");
988
989 1 avio_w8(pb, 1); // ConfigurationVersion
990 1 avio_w8(pb, track->par->profile * 5 + track->par->level);
991
992
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 for (size_t i = 0; i < FF_ARRAY_ELEMS(ff_mpa_cicp_channel_layout_masks); i++) {
993
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
17 if (ff_mpa_cicp_channel_layout_masks[i]) {
994 AVChannelLayout ch_layout;
995 15 av_channel_layout_from_mask(&ch_layout, ff_mpa_cicp_channel_layout_masks[i]);
996
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 14 times.
15 if (!av_channel_layout_compare(&track->par->ch_layout, &ch_layout)) {
997 1 layout = i;
998 1 break;
999 }
1000 }
1001 }
1002
1003 1 avio_w8(pb, layout);
1004 1 avio_wb16(pb, track->extradata_size[track->last_stsd_index]);
1005 1 avio_write(pb, track->extradata[track->last_stsd_index],
1006 1 track->extradata_size[track->last_stsd_index]);
1007
1008 1 return update_size(pb, pos);
1009 }
1010
1011 289 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1012 {
1013 289 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
1014 289 AVChannelLayout ch_layout = { 0 };
1015 int64_t pos;
1016 int ambisonic_order, ambi_channels, non_diegetic_channels;
1017 int i, ret;
1018
1019
1/2
✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
289 if (!str)
1020 289 return 0;
1021
1022 ✗ ret = av_channel_layout_from_string(&ch_layout, str->value);
1023 ✗ if (ret < 0) {
1024 ✗ if (ret == AVERROR(EINVAL)) {
1025 ✗ invalid:
1026 ✗ av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
1027 ✗ ret = 0;
1028 }
1029 ✗ av_channel_layout_uninit(&ch_layout);
1030 ✗ return ret;
1031 }
1032
1033 ✗ if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
1034 ✗ goto invalid;
1035
1036 ✗ ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
1037 ✗ if (ambisonic_order < 0)
1038 ✗ goto invalid;
1039
1040 ✗ ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
1041 ✗ non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
1042 ✗ if (non_diegetic_channels &&
1043 ✗ (non_diegetic_channels != 2 ||
1044 ✗ av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
1045 ✗ goto invalid;
1046
1047 ✗ av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
1048
1049 ✗ pos = avio_tell(pb);
1050
1051 ✗ avio_wb32(pb, 0); // Size
1052 ✗ ffio_wfourcc(pb, "SA3D");
1053 ✗ avio_w8(pb, 0); // version
1054 ✗ avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
1055 ✗ avio_wb32(pb, ambisonic_order); // ambisonic_order
1056 ✗ avio_w8(pb, 0); // ambisonic_channel_ordering
1057 ✗ avio_w8(pb, 0); // ambisonic_normalization
1058 ✗ avio_wb32(pb, ch_layout.nb_channels); // num_channels
1059 ✗ for (i = 0; i < ambi_channels; i++)
1060 ✗ avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
1061 ✗ for (; i < ch_layout.nb_channels; i++)
1062 ✗ avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
1063
1064 ✗ av_channel_layout_uninit(&ch_layout);
1065
1066 ✗ return update_size(pb, pos);
1067 }
1068
1069 39 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1070 {
1071 uint32_t layout_tag, bitmap, *channel_desc;
1072 39 int64_t pos = avio_tell(pb);
1073 int num_desc, ret;
1074
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (track->multichannel_as_mono)
1076 ✗ return 0;
1077
1078 39 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
1079 &bitmap, &channel_desc);
1080
1081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0) {
1082 ✗ if (ret == AVERROR(ENOSYS)) {
1083 ✗ av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
1084 "lack of channel information\n");
1085 ✗ ret = 0;
1086 }
1087
1088 ✗ return ret;
1089 }
1090
1091 /* no predefined tag found + ch_layout in AV_CHANNEL_ORDER_NATIVE
1092 * but bitstream channels not actually in native order */
1093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (layout_tag == MOV_CH_LAYOUT_UNKNOWN)
1094 ✗ return 0;
1095
1096
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
39 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1098 1 channel_desc = av_malloc(sizeof(*channel_desc));
1099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1100 ✗ return AVERROR(ENOMEM);
1101
1102 1 layout_tag = 0;
1103 1 bitmap = 0;
1104 1 *channel_desc = 3; // channel label "Center"
1105 }
1106
1107
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 36 times.
39 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1108
1109 39 avio_wb32(pb, 0); // Size
1110 39 ffio_wfourcc(pb, "chan"); // Type
1111 39 avio_w8(pb, 0); // Version
1112 39 avio_wb24(pb, 0); // Flags
1113 39 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1114 39 avio_wb32(pb, bitmap); // mChannelBitmap
1115 39 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1116
1117
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39 times.
42 for (int i = 0; i < num_desc; i++) {
1118 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1119 3 avio_wb32(pb, 0); // mChannelFlags
1120 3 avio_wl32(pb, 0); // mCoordinates[0]
1121 3 avio_wl32(pb, 0); // mCoordinates[1]
1122 3 avio_wl32(pb, 0); // mCoordinates[2]
1123 }
1124
1125 39 av_free(channel_desc);
1126
1127 39 return update_size(pb, pos);
1128 }
1129
1130 14 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1131 {
1132 14 int64_t pos = avio_tell(pb);
1133
1134 14 avio_wb32(pb, 0); /* size */
1135 14 ffio_wfourcc(pb, "wave");
1136
1137
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1138 14 avio_wb32(pb, 12); /* size */
1139 14 ffio_wfourcc(pb, "frma");
1140 14 avio_wl32(pb, track->tag);
1141 }
1142
1143
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1144 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1145 3 avio_wb32(pb, 12); /* size */
1146 3 ffio_wfourcc(pb, "mp4a");
1147 3 avio_wb32(pb, 0);
1148 3 mov_write_esds_tag(pb, track);
1149
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1150 ✗ mov_write_enda_tag(pb);
1151
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
11 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1152 2 mov_write_enda_tag_be(pb);
1153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1154 ✗ mov_write_amr_tag(pb, track);
1155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1156 ✗ mov_write_ac3_tag(s, pb, track);
1157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1158 ✗ mov_write_eac3_tag(s, pb, track);
1159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1160 ✗ track->par->codec_id == AV_CODEC_ID_QDM2) {
1161 9 mov_write_extradata_tag(pb, track);
1162 ✗ } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1163 ✗ track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1164 ✗ mov_write_ms_tag(s, pb, track);
1165 }
1166
1167 14 avio_wb32(pb, 8); /* size */
1168 14 avio_wb32(pb, 0); /* null tag */
1169
1170 14 return update_size(pb, pos);
1171 }
1172
1173 ✗ static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1174 {
1175 uint8_t *unescaped;
1176 ✗ const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
1177 ✗ track->extradata_size[track->last_stsd_index];
1178 ✗ int unescaped_size, seq_found = 0;
1179 ✗ int level = 0, interlace = 0;
1180 ✗ int packet_seq = track->vc1_info.packet_seq;
1181 ✗ int packet_entry = track->vc1_info.packet_entry;
1182 ✗ int slices = track->vc1_info.slices;
1183 PutBitContext pbc;
1184
1185 ✗ if (track->start_dts == AV_NOPTS_VALUE) {
1186 /* No packets written yet, vc1_info isn't authoritative yet. */
1187 /* Assume inline sequence and entry headers. */
1188 ✗ packet_seq = packet_entry = 1;
1189 ✗ av_log(NULL, AV_LOG_WARNING,
1190 "moov atom written before any packets, unable to write correct "
1191 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1192 }
1193
1194 ✗ unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
1195 ✗ if (!unescaped)
1196 ✗ return AVERROR(ENOMEM);
1197 ✗ start = find_next_marker(track->extradata[track->last_stsd_index], end);
1198 ✗ for (next = start; next < end; start = next) {
1199 GetBitContext gb;
1200 int size;
1201 ✗ next = find_next_marker(start + 4, end);
1202 ✗ size = next - start - 4;
1203 ✗ if (size <= 0)
1204 ✗ continue;
1205 ✗ unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1206 ✗ init_get_bits(&gb, unescaped, 8 * unescaped_size);
1207 ✗ if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1208 ✗ int profile = get_bits(&gb, 2);
1209 ✗ if (profile != PROFILE_ADVANCED) {
1210 ✗ av_free(unescaped);
1211 ✗ return AVERROR(ENOSYS);
1212 }
1213 ✗ seq_found = 1;
1214 ✗ level = get_bits(&gb, 3);
1215 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1216 * width, height */
1217 ✗ skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1218 ✗ skip_bits(&gb, 1); /* broadcast */
1219 ✗ interlace = get_bits1(&gb);
1220 ✗ skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1221 }
1222 }
1223 ✗ if (!seq_found) {
1224 ✗ av_free(unescaped);
1225 ✗ return AVERROR(ENOSYS);
1226 }
1227
1228 ✗ init_put_bits(&pbc, buf, 7);
1229 /* VC1DecSpecStruc */
1230 ✗ put_bits(&pbc, 4, 12); /* profile - advanced */
1231 ✗ put_bits(&pbc, 3, level);
1232 ✗ put_bits(&pbc, 1, 0); /* reserved */
1233 /* VC1AdvDecSpecStruc */
1234 ✗ put_bits(&pbc, 3, level);
1235 ✗ put_bits(&pbc, 1, 0); /* cbr */
1236 ✗ put_bits(&pbc, 6, 0); /* reserved */
1237 ✗ put_bits(&pbc, 1, !interlace); /* no interlace */
1238 ✗ put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1239 ✗ put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1240 ✗ put_bits(&pbc, 1, !slices); /* no slice code */
1241 ✗ put_bits(&pbc, 1, 0); /* no bframe */
1242 ✗ put_bits(&pbc, 1, 0); /* reserved */
1243
1244 /* framerate */
1245 ✗ if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1246 ✗ put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1247 else
1248 ✗ put_bits32(&pbc, 0xffffffff);
1249
1250 ✗ flush_put_bits(&pbc);
1251
1252 ✗ av_free(unescaped);
1253
1254 ✗ return 0;
1255 }
1256
1257 ✗ static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1258 {
1259 ✗ uint8_t buf[7] = { 0 };
1260 int ret;
1261
1262 ✗ if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1263 ✗ return ret;
1264
1265 ✗ avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
1266 ✗ ffio_wfourcc(pb, "dvc1");
1267 ✗ avio_write(pb, buf, sizeof(buf));
1268 ✗ avio_write(pb, track->extradata[track->last_stsd_index],
1269 ✗ track->extradata_size[track->last_stsd_index]);
1270
1271 ✗ return 0;
1272 }
1273
1274 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1275 {
1276 4 avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
1277 4 ffio_wfourcc(pb, "glbl");
1278 4 avio_write(pb, track->extradata[track->last_stsd_index],
1279 4 track->extradata_size[track->last_stsd_index]);
1280 4 return 8 + track->extradata_size[track->last_stsd_index];
1281 }
1282
1283 /**
1284 * Compute flags for 'lpcm' tag.
1285 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1286 */
1287 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1288 {
1289
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 switch (codec_id) {
1290 ✗ case AV_CODEC_ID_PCM_F32BE:
1291 case AV_CODEC_ID_PCM_F64BE:
1292 ✗ return 11;
1293 ✗ case AV_CODEC_ID_PCM_F32LE:
1294 case AV_CODEC_ID_PCM_F64LE:
1295 ✗ return 9;
1296 ✗ case AV_CODEC_ID_PCM_U8:
1297 ✗ return 10;
1298 ✗ case AV_CODEC_ID_PCM_S16BE:
1299 case AV_CODEC_ID_PCM_S24BE:
1300 case AV_CODEC_ID_PCM_S32BE:
1301 ✗ return 14;
1302 ✗ case AV_CODEC_ID_PCM_S8:
1303 case AV_CODEC_ID_PCM_S16LE:
1304 case AV_CODEC_ID_PCM_S24LE:
1305 case AV_CODEC_ID_PCM_S32LE:
1306 ✗ return 12;
1307 8 default:
1308 8 return 0;
1309 }
1310 }
1311
1312 40172 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1313 {
1314 int64_t next_dts;
1315
1316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40172 times.
40172 if (cluster_idx >= track->entry)
1317 ✗ return 0;
1318
1319
2/2
✓ Branch 0 taken 1639 times.
✓ Branch 1 taken 38533 times.
40172 if (cluster_idx + 1 == track->entry)
1320 1639 next_dts = track->track_duration + track->start_dts;
1321 else
1322 38533 next_dts = track->cluster[cluster_idx + 1].dts;
1323
1324 40172 next_dts -= track->cluster[cluster_idx].dts;
1325
1326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40172 times.
40172 av_assert0(next_dts >= 0);
1327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40172 times.
40172 av_assert0(next_dts <= INT_MAX);
1328
1329 40172 return next_dts;
1330 }
1331
1332 4 static int get_samples_per_packet(MOVTrack *track)
1333 {
1334 int i, first_duration;
1335
1336 /* use 1 for raw PCM */
1337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1338 ✗ return 1;
1339
1340 /* check to see if duration is constant for all clusters */
1341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1342 ✗ return 0;
1343 4 first_duration = get_cluster_duration(track, 0);
1344
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1345
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1346 4 return 0;
1347 }
1348 ✗ return first_duration;
1349 }
1350
1351 381 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1352 {
1353 381 int64_t pos = avio_tell(pb);
1354 381 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1355
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 295 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
381 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1356
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 !bit_rates.buffer_size)
1357 // no useful data to be written, skip
1358 86 return 0;
1359
1360 295 avio_wb32(pb, 0); /* size */
1361 295 ffio_wfourcc(pb, "btrt");
1362
1363 295 avio_wb32(pb, bit_rates.buffer_size);
1364 295 avio_wb32(pb, bit_rates.max_bit_rate);
1365 295 avio_wb32(pb, bit_rates.avg_bit_rate);
1366
1367 295 return update_size(pb, pos);
1368 }
1369
1370 7 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1371 {
1372 7 int64_t pos = avio_tell(pb);
1373 7 int config = 0;
1374 int ret;
1375 7 uint8_t *speaker_pos = NULL;
1376 7 const AVChannelLayout *layout = &track->par->ch_layout;
1377
1378 7 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1379
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
7 if (ret || !config) {
1380 4 config = 0;
1381 4 speaker_pos = av_malloc(layout->nb_channels);
1382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1383 ✗ return AVERROR(ENOMEM);
1384 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1385 4 speaker_pos, layout->nb_channels);
1386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1387 ✗ char buf[128] = {0};
1388
1389 ✗ av_freep(&speaker_pos);
1390 ✗ av_channel_layout_describe(layout, buf, sizeof(buf));
1391 ✗ av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1392 ✗ return ret;
1393 }
1394 }
1395
1396 7 avio_wb32(pb, 0); /* size */
1397 7 ffio_wfourcc(pb, "chnl");
1398 7 avio_wb32(pb, 0); /* version & flags */
1399
1400 7 avio_w8(pb, 1); /* stream_structure */
1401 7 avio_w8(pb, config);
1402
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (config) {
1403 3 avio_wb64(pb, 0);
1404 } else {
1405 4 avio_write(pb, speaker_pos, layout->nb_channels);
1406 4 av_freep(&speaker_pos);
1407 }
1408
1409 7 return update_size(pb, pos);
1410 }
1411
1412 9 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1413 {
1414 9 int64_t pos = avio_tell(pb);
1415 int format_flags;
1416 int sample_size;
1417
1418 9 avio_wb32(pb, 0); /* size */
1419 9 ffio_wfourcc(pb, "pcmC");
1420 9 avio_wb32(pb, 0); /* version & flags */
1421
1422 /* 0x01: indicates little-endian format */
1423 26 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1424
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1426
2/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1427 ✗ track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1428 9 avio_w8(pb, format_flags);
1429 9 sample_size = track->par->bits_per_raw_sample;
1430
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!sample_size)
1431 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 av_assert0(sample_size);
1433 9 avio_w8(pb, sample_size);
1434
1435 9 return update_size(pb, pos);
1436 }
1437
1438 5 static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track)
1439 {
1440 5 int64_t pos = avio_tell(pb);
1441 5 avio_wb32(pb, 0); /* size */
1442 5 ffio_wfourcc(pb, "srat");
1443 5 avio_wb32(pb, 0); /* version & flags */
1444
1445 5 avio_wb32(pb, track->par->sample_rate);
1446
1447 5 return update_size(pb, pos);
1448 }
1449
1450 331 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1451 {
1452 331 int64_t pos = avio_tell(pb);
1453 331 int version = 0;
1454 331 uint32_t tag = track->tag;
1455 331 int ret = 0;
1456
1457
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
331 if (track->mode == MODE_MOV) {
1458
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
39 if (track->par->sample_rate > UINT16_MAX || !track->par->ch_layout.nb_channels ||
1459
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 track->par->ch_layout.nb_channels > 2) {
1461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1462 ✗ tag = AV_RL32("lpcm");
1463 4 version = 2;
1464
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
61 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1465 26 mov_pcm_be_gt16(track->par->codec_id) ||
1466
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1467
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1469 11 version = 1;
1470 }
1471
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 3 times.
292 } else if (track->mode == MODE_MP4) {
1472
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 284 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
289 if (track->par->sample_rate > UINT16_MAX &&
1473 ✗ (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG))
1474 5 version = 1;
1475 }
1476
1477 331 avio_wb32(pb, 0); /* size */
1478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (mov->encryption_scheme != MOV_ENC_NONE) {
1479 ✗ ffio_wfourcc(pb, "enca");
1480 } else {
1481 331 avio_wl32(pb, tag); // store it byteswapped
1482 }
1483 331 avio_wb32(pb, 0); /* Reserved */
1484 331 avio_wb16(pb, 0); /* Reserved */
1485 331 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1486
1487 /* SoundDescription */
1488 331 avio_wb16(pb, version); /* Version */
1489 331 avio_wb16(pb, 0); /* Revision level */
1490 331 avio_wb32(pb, 0); /* Reserved */
1491
1492
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 327 times.
331 if (version == 2) {
1493 4 avio_wb16(pb, 3);
1494 4 avio_wb16(pb, 16);
1495 4 avio_wb16(pb, 0xfffe);
1496 4 avio_wb16(pb, 0);
1497 4 avio_wb32(pb, 0x00010000);
1498 4 avio_wb32(pb, 72);
1499 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1500 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1501 4 avio_wb32(pb, 0x7F000000);
1502 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1503 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1504 4 avio_wb32(pb, track->sample_size);
1505 4 avio_wb32(pb, get_samples_per_packet(track));
1506 } else {
1507 327 unsigned sample_rate = track->par->sample_rate;
1508
1509
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 292 times.
327 if (track->mode == MODE_MOV) {
1510 35 avio_wb16(pb, track->par->ch_layout.nb_channels);
1511
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1512
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1513 1 avio_wb16(pb, 8); /* bits per sample */
1514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1515 ✗ avio_wb16(pb, track->par->bits_per_coded_sample);
1516 else
1517 34 avio_wb16(pb, 16);
1518
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26 times.
35 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1519 } else { /* reserved for mp4/3gp */
1520
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 5 times.
579 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1521 287 0 : track->par->ch_layout.nb_channels);
1522
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 5 times.
292 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 track->par->codec_id == AV_CODEC_ID_ALAC) {
1524 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1525 } else {
1526 287 avio_wb16(pb, 16);
1527 }
1528 292 avio_wb16(pb, 0);
1529
1530
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 292 times.
297 while (sample_rate > UINT16_MAX)
1531 5 sample_rate >>= 1;
1532 }
1533
1534 327 avio_wb16(pb, 0); /* packet size (= 0) */
1535
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 322 times.
327 if (track->tag == MKTAG('i','a','m','f'))
1536 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 322 times.
322 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1538 ✗ avio_wb16(pb, 48000);
1539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 322 times.
322 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1540 ✗ avio_wb32(pb, track->par->sample_rate);
1541 else
1542 322 avio_wb16(pb, sample_rate);
1543
1544
1/2
✓ Branch 0 taken 327 times.
✗ Branch 1 not taken.
327 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1545 327 avio_wb16(pb, 0); /* Reserved */
1546 }
1547
1548
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 28 times.
331 if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */
1549
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 9 times.
22 if (mov_pcm_le_gt16(track->par->codec_id) ||
1550 11 mov_pcm_be_gt16(track->par->codec_id))
1551 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1552 else
1553 9 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1554 11 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1555 11 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1556 11 avio_wb32(pb, 2); /* Bytes per sample */
1557 }
1558
1559
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
331 if (track->mode == MODE_MOV &&
1560
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
39 (track->par->codec_id == AV_CODEC_ID_AAC ||
1561
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AC3 ||
1562
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1563
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1564
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1565
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1566
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1567
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1568
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
54 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1569
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1570 14 ret = mov_write_wave_tag(s, pb, track);
1571
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 51 times.
317 else if (track->tag == MKTAG('m','p','4','a'))
1572 266 ret = mov_write_esds_tag(pb, track);
1573 #if CONFIG_IAMFENC
1574
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 46 times.
51 else if (track->tag == MKTAG('i','a','m','f'))
1575 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1576 #endif
1577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1578 ✗ ret = mov_write_amr_tag(pb, track);
1579
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
46 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1580 7 ret = mov_write_ac3_tag(s, pb, track);
1581
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 35 times.
39 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1582 4 ret = mov_write_eac3_tag(s, pb, track);
1583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1584 ✗ ret = mov_write_extradata_tag(pb, track);
1585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1586 ✗ ret = mov_write_wfex_tag(s, pb, track);
1587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1588 ✗ ret = mov_write_dfla_tag(pb, track);
1589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1590 ✗ ret = mov_write_dops_tag(s, pb, track);
1591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1592 ✗ ret = mov_write_dmlp_tag(s, pb, track);
1593
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 34 times.
35 else if (track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO)
1594 1 ret = mov_write_mhac_tag(s, pb, track);
1595
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
34 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1596
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (track->par->sample_rate > UINT16_MAX)
1597 5 mov_write_srat_tag(pb, track);
1598
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (track->par->ch_layout.nb_channels > 1)
1599 7 ret = mov_write_chnl_tag(s, pb, track);
1600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
1601 ✗ return ret;
1602 9 ret = mov_write_pcmc_tag(s, pb, track);
1603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->extradata_size[track->last_stsd_index] > 0)
1604 ✗ ret = mov_write_glbl_tag(pb, track);
1605
1606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (ret < 0)
1607 ✗ return ret;
1608
1609
3/4
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 289 times.
✗ Branch 3 not taken.
331 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1610
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 289 times.
289 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1611 ✗ return ret;
1612 }
1613
1614
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 292 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
331 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1615
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1616 ✗ return ret;
1617 }
1618
1619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (mov->encryption_scheme != MOV_ENC_NONE
1620 ✗ && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1621 ✗ return ret;
1622 }
1623
1624
3/4
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 289 times.
620 if (mov->write_btrt &&
1625 289 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1626 ✗ return ret;
1627
1628
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 42 times.
331 if (track->mode == MODE_MP4)
1629 289 track->entry_version = version;
1630
1631 331 ret = update_size(pb, pos);
1632 331 return ret;
1633 }
1634
1635 ✗ static int mov_write_d263_tag(AVIOContext *pb)
1636 {
1637 ✗ avio_wb32(pb, 0xf); /* size */
1638 ✗ ffio_wfourcc(pb, "d263");
1639 ✗ ffio_wfourcc(pb, "FFMP");
1640 ✗ avio_w8(pb, 0); /* decoder version */
1641 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1642 ✗ avio_w8(pb, 0xa); /* level */
1643 ✗ avio_w8(pb, 0); /* profile */
1644 ✗ return 0xf;
1645 }
1646
1647 2 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1648 {
1649 2 int64_t pos = avio_tell(pb);
1650
1651 2 avio_wb32(pb, 0);
1652 2 ffio_wfourcc(pb, "av1C");
1653 2 ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
1654 2 track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
1655 2 return update_size(pb, pos);
1656 }
1657
1658 60 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1659 {
1660 60 int64_t pos = avio_tell(pb);
1661
1662 60 avio_wb32(pb, 0);
1663 60 ffio_wfourcc(pb, "avcC");
1664 60 ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
1665 60 track->extradata_size[track->last_stsd_index]);
1666 60 return update_size(pb, pos);
1667 }
1668
1669 /* AVS3 Intelligent Media Coding
1670 * Information Technology - Intelligent Media Coding
1671 * Part 6: Intelligent Media Format
1672 */
1673 ✗ static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1674 {
1675 ✗ if (len < 4)
1676 ✗ return AVERROR_INVALIDDATA;
1677
1678 ✗ if (data[0] == 1) {
1679 // In Avs3DecoderConfigurationRecord format
1680 ✗ avio_write(pb, data, len);
1681 ✗ return 0;
1682 }
1683
1684 ✗ avio_w8(pb, 1); // version
1685 ✗ avio_wb16(pb, len); // sequence_header_length
1686 ✗ avio_write(pb, data, len); // sequence_header
1687 ✗ avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1688
1689 ✗ return 0;
1690 }
1691
1692 ✗ static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1693 {
1694 ✗ int64_t pos = avio_tell(pb);
1695 ✗ avio_wb32(pb, 0);
1696 ✗ ffio_wfourcc(pb, "av3c");
1697 ✗ mov_write_av3c(pb, track->extradata[track->last_stsd_index],
1698 ✗ track->extradata_size[track->last_stsd_index]);
1699 ✗ return update_size(pb, pos);
1700 }
1701
1702 ✗ static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1703 {
1704 ✗ int64_t pos = avio_tell(pb);
1705
1706 ✗ avio_wb32(pb, 0);
1707 ✗ ffio_wfourcc(pb, "vpcC");
1708 ✗ ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
1709 ✗ track->extradata_size[track->last_stsd_index], track->par);
1710 ✗ return update_size(pb, pos);
1711 }
1712
1713 11 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1714 {
1715 11 int64_t pos = avio_tell(pb);
1716
1717 11 avio_wb32(pb, 0);
1718 11 ffio_wfourcc(pb, "hvcC");
1719
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (track->tag == MKTAG('h','v','c','1'))
1720 3 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1721 3 track->extradata_size[track->last_stsd_index], 1, s);
1722 else
1723 8 ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
1724 8 track->extradata_size[track->last_stsd_index], 0, s);
1725 11 return update_size(pb, pos);
1726 }
1727
1728 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1729 {
1730 1 int64_t pos = avio_tell(pb);
1731 int ret;
1732
1733 1 avio_wb32(pb, 0);
1734 1 ffio_wfourcc(pb, "lhvC");
1735
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1736 1 ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1737 1 track->extradata_size[track->last_stsd_index], 1, s);
1738 else
1739 ✗ ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
1740 ✗ track->extradata_size[track->last_stsd_index], 0, s);
1741
1742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1743 ✗ avio_seek(pb, pos, SEEK_SET);
1744 ✗ return ret;
1745 }
1746
1747 1 return update_size(pb, pos);
1748 }
1749
1750 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1751 {
1752 1 int64_t pos = avio_tell(pb);
1753
1754 1 avio_wb32(pb, 0);
1755 1 ffio_wfourcc(pb, "evcC");
1756
1757
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1758 1 ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1759 1 track->extradata_size[track->last_stsd_index], 1);
1760 else
1761 ✗ ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
1762 ✗ track->extradata_size[track->last_stsd_index], 0);
1763
1764 1 return update_size(pb, pos);
1765 }
1766
1767 1 static int mov_write_lvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1768 {
1769 1 int64_t pos = avio_tell(pb);
1770
1771 1 avio_wb32(pb, 0);
1772 1 ffio_wfourcc(pb, "lvcC");
1773
1774 1 ff_isom_write_lvcc(pb, track->extradata[track->last_stsd_index],
1775 1 track->extradata_size[track->last_stsd_index], s);
1776
1777 1 return update_size(pb, pos);
1778 }
1779
1780 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1781 {
1782 1 int64_t pos = avio_tell(pb);
1783
1784 1 avio_wb32(pb, 0);
1785 1 ffio_wfourcc(pb, "vvcC");
1786
1787 1 avio_w8 (pb, 0); /* version */
1788 1 avio_wb24(pb, 0); /* flags */
1789
1790
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1791 1 ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1792 1 track->extradata_size[track->last_stsd_index], 1);
1793 else
1794 ✗ ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
1795 ✗ track->extradata_size[track->last_stsd_index], 0);
1796 1 return update_size(pb, pos);
1797 }
1798
1799 1 static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1800 {
1801 1 int64_t pos = avio_tell(pb);
1802
1803 1 avio_wb32(pb, 0);
1804 1 ffio_wfourcc(pb, "apvC");
1805
1806 1 avio_w8 (pb, 0); /* version */
1807 1 avio_wb24(pb, 0); /* flags */
1808
1809 1 ff_isom_write_apvc(pb, track->apv, s);
1810
1811 1 return update_size(pb, pos);
1812 }
1813
1814 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1815 /* https://community.avid.com/forums/t/136517.aspx */
1816 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1817 {
1818 int interlaced;
1819 int cid;
1820 23 int display_width = track->par->width;
1821 const uint8_t *extradata;
1822
1823
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (track->extradata[track->last_stsd_index] && track->extradata_size[track->last_stsd_index] > 0x29) {
1824
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->extradata[track->last_stsd_index]) != 0) {
1825 /* looks like a DNxHD bit stream */
1826 23 extradata = track->extradata[track->last_stsd_index];
1827 } else {
1828 ✗ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1829 ✗ return 0;
1830 }
1831 } else {
1832 ✗ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1833 ✗ return 0;
1834 }
1835
1836 23 cid = AV_RB32(extradata + 0x28);
1837
1838 23 avio_wb32(pb, 24); /* size */
1839 23 ffio_wfourcc(pb, "ACLR");
1840 23 ffio_wfourcc(pb, "ACLR");
1841 23 ffio_wfourcc(pb, "0001");
1842 // 1: CCIR (supercolors will be dropped, 16 will be displayed as black)
1843 // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey)
1844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1845 ✗ track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1846 23 avio_wb32(pb, 1);
1847 } else {
1848 ✗ avio_wb32(pb, 2);
1849 }
1850 23 avio_wb32(pb, 0); /* reserved */
1851
1852
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1853 12 int alp = extradata[0x07] & 1;
1854 12 int pma = (extradata[0x07] >> 2) & 1;
1855 12 int sbd = (extradata[0x21] >> 5) & 3;
1856 12 int ssc = (extradata[0x2C] >> 5) & 3;
1857 12 int clv = (extradata[0x2C] >> 1) & 3;
1858 12 int clf = extradata[0x2C] & 1;
1859
1860 12 avio_wb32(pb, 32);
1861 12 ffio_wfourcc(pb, "ADHR");
1862 12 ffio_wfourcc(pb, "0001");
1863 12 avio_wb32(pb, cid); // Compression ID
1864 // 0: 4:2:2 Sub Sampling
1865 // 1: 4:2:0 Sub Sampling
1866 // 2: 4:4:4 Sub Sampling
1867 12 avio_wb32(pb, ssc); // Sub Sampling Control
1868 // 1: 8-bits per sample
1869 // 2: 10-bits per sample
1870 // 3: 12-bits per sample
1871 12 avio_wb32(pb, sbd); // Sample Bit Depth
1872 // 0: Bitstream is encoded using the YCBCR format rules and tables
1873 // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270
1874 12 avio_wb16(pb, clf); // Color Format
1875 // 0: ITU-R BT.709
1876 // 1: ITU-R BT.2020
1877 // 2: ITU-R BT.2020 C
1878 // 3: Out-of-band
1879 12 avio_wb16(pb, clv); // Color Volume
1880 // 0: Alpha channel not present
1881 // 1: Alpha channel present
1882 12 avio_wb16(pb, alp); // Alpha Present
1883 // 0: Alpha has not been applied to video channels
1884 // 1: Alpha has been applied to the video channels prior to encoding
1885 12 avio_wb16(pb, pma); // Pre-Multiplied Alpha
1886 12 return 0;
1887 }
1888
1889 11 interlaced = extradata[5] & 2;
1890
1891 11 avio_wb32(pb, 24); /* size */
1892 11 ffio_wfourcc(pb, "APRG");
1893 11 ffio_wfourcc(pb, "APRG");
1894 11 ffio_wfourcc(pb, "0001");
1895 // 1 for progressive or 2 for interlaced
1896
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced)
1897 11 avio_wb32(pb, 2);
1898 else
1899 ✗ avio_wb32(pb, 1);
1900 11 avio_wb32(pb, 0); /* reserved */
1901
1902 11 avio_wb32(pb, 120); /* size */
1903 11 ffio_wfourcc(pb, "ARES");
1904 11 ffio_wfourcc(pb, "ARES");
1905 11 ffio_wfourcc(pb, "0001");
1906 11 avio_wb32(pb, cid); /* cid */
1907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1908 ✗ && track->par->sample_aspect_ratio.den > 0)
1909 ✗ display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1910 11 avio_wb32(pb, display_width); // field width
1911
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1912 11 avio_wb32(pb, track->par->height / 2); // field height
1913 11 avio_wb32(pb, 2); // num fields
1914 11 avio_wb32(pb, 0); // num black lines (must be 0)
1915 // 4: HD1080i
1916 // 5: HD1080P
1917 // 6: HD720P
1918 11 avio_wb32(pb, 4); // video format
1919 } else {
1920 ✗ avio_wb32(pb, track->par->height);
1921 ✗ avio_wb32(pb, 1); // num fields
1922 ✗ avio_wb32(pb, 0);
1923 ✗ if (track->par->height == 1080)
1924 ✗ avio_wb32(pb, 5);
1925 else
1926 ✗ avio_wb32(pb, 6);
1927 }
1928 /* padding */
1929 11 ffio_fill(pb, 0, 10 * 8);
1930
1931 11 return 0;
1932 }
1933
1934 ✗ static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1935 {
1936 ✗ avio_wb32(pb, 12);
1937 ✗ ffio_wfourcc(pb, "DpxE");
1938 ✗ if (track->extradata_size[track->last_stsd_index] >= 12 &&
1939 ✗ !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
1940 ✗ avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
1941 } else {
1942 ✗ avio_wb32(pb, 1);
1943 }
1944 ✗ return 0;
1945 }
1946
1947 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1948 {
1949 int tag;
1950
1951
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1952
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
1954 1 else tag = MKTAG('d','v','c',' ');
1955 ✗ }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1956 ✗ else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1957 ✗ else tag = MKTAG('d','v','p','p');
1958 ✗ } else if (track->par->height == 720) { /* HD 720 line */
1959 ✗ if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1960 ✗ else tag = MKTAG('d','v','h','p');
1961 ✗ } else if (track->par->height == 1080) { /* HD 1080 line */
1962 ✗ if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1963 ✗ else tag = MKTAG('d','v','h','6');
1964 } else {
1965 ✗ av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1966 ✗ return 0;
1967 }
1968
1969 1 return tag;
1970 }
1971
1972 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1973 {
1974 3 AVRational rational_framerate = st->avg_frame_rate;
1975 3 int rate = 0;
1976
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1977 3 rate = av_q2d(rational_framerate);
1978 3 return rate;
1979 }
1980
1981 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1982 {
1983 1 int tag = track->par->codec_tag;
1984 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1985 1 AVStream *st = track->st;
1986 1 int rate = defined_frame_rate(s, st);
1987
1988
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1989 ✗ tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1990
1991
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1992
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (track->par->width == 1280 && track->par->height == 720) {
1993 ✗ if (!interlaced) {
1994 ✗ if (rate == 24) tag = MKTAG('x','d','v','4');
1995 ✗ else if (rate == 25) tag = MKTAG('x','d','v','5');
1996 ✗ else if (rate == 30) tag = MKTAG('x','d','v','1');
1997 ✗ else if (rate == 50) tag = MKTAG('x','d','v','a');
1998 ✗ else if (rate == 60) tag = MKTAG('x','d','v','9');
1999 }
2000
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1440 && track->par->height == 1080) {
2001 ✗ if (!interlaced) {
2002 ✗ if (rate == 24) tag = MKTAG('x','d','v','6');
2003 ✗ else if (rate == 25) tag = MKTAG('x','d','v','7');
2004 ✗ else if (rate == 30) tag = MKTAG('x','d','v','8');
2005 } else {
2006 ✗ if (rate == 25) tag = MKTAG('x','d','v','3');
2007 ✗ else if (rate == 30) tag = MKTAG('x','d','v','2');
2008 }
2009
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1920 && track->par->height == 1080) {
2010 ✗ if (!interlaced) {
2011 ✗ if (rate == 24) tag = MKTAG('x','d','v','d');
2012 ✗ else if (rate == 25) tag = MKTAG('x','d','v','e');
2013 ✗ else if (rate == 30) tag = MKTAG('x','d','v','f');
2014 } else {
2015 ✗ if (rate == 25) tag = MKTAG('x','d','v','c');
2016 ✗ else if (rate == 30) tag = MKTAG('x','d','v','b');
2017 }
2018 }
2019 ✗ } else if (track->par->format == AV_PIX_FMT_YUV422P) {
2020 ✗ if (track->par->width == 1280 && track->par->height == 720) {
2021 ✗ if (!interlaced) {
2022 ✗ if (rate == 24) tag = MKTAG('x','d','5','4');
2023 ✗ else if (rate == 25) tag = MKTAG('x','d','5','5');
2024 ✗ else if (rate == 30) tag = MKTAG('x','d','5','1');
2025 ✗ else if (rate == 50) tag = MKTAG('x','d','5','a');
2026 ✗ else if (rate == 60) tag = MKTAG('x','d','5','9');
2027 }
2028 ✗ } else if (track->par->width == 1920 && track->par->height == 1080) {
2029 ✗ if (!interlaced) {
2030 ✗ if (rate == 24) tag = MKTAG('x','d','5','d');
2031 ✗ else if (rate == 25) tag = MKTAG('x','d','5','e');
2032 ✗ else if (rate == 30) tag = MKTAG('x','d','5','f');
2033 } else {
2034 ✗ if (rate == 25) tag = MKTAG('x','d','5','c');
2035 ✗ else if (rate == 30) tag = MKTAG('x','d','5','b');
2036 }
2037 }
2038 }
2039
2040 1 return tag;
2041 }
2042
2043 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
2044 {
2045 2 int tag = track->par->codec_tag;
2046 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2047 2 AVStream *st = track->st;
2048 2 int rate = defined_frame_rate(s, st);
2049
2050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
2051 ✗ tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
2052
2053
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->par->profile == AV_PROFILE_UNKNOWN ||
2054
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !(track->par->profile & AV_PROFILE_H264_INTRA))
2055 2 return tag;
2056
2057 ✗ if (track->par->format == AV_PIX_FMT_YUV420P10) {
2058 ✗ if (track->par->width == 960 && track->par->height == 720) {
2059 ✗ if (!interlaced) {
2060 ✗ if (rate == 24) tag = MKTAG('a','i','5','p');
2061 ✗ else if (rate == 25) tag = MKTAG('a','i','5','q');
2062 ✗ else if (rate == 30) tag = MKTAG('a','i','5','p');
2063 ✗ else if (rate == 50) tag = MKTAG('a','i','5','q');
2064 ✗ else if (rate == 60) tag = MKTAG('a','i','5','p');
2065 }
2066 ✗ } else if (track->par->width == 1440 && track->par->height == 1080) {
2067 ✗ if (!interlaced) {
2068 ✗ if (rate == 24) tag = MKTAG('a','i','5','3');
2069 ✗ else if (rate == 25) tag = MKTAG('a','i','5','2');
2070 ✗ else if (rate == 30) tag = MKTAG('a','i','5','3');
2071 } else {
2072 ✗ if (rate == 50) tag = MKTAG('a','i','5','5');
2073 ✗ else if (rate == 60) tag = MKTAG('a','i','5','6');
2074 }
2075 }
2076 ✗ } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
2077 ✗ if (track->par->width == 1280 && track->par->height == 720) {
2078 ✗ if (!interlaced) {
2079 ✗ if (rate == 24) tag = MKTAG('a','i','1','p');
2080 ✗ else if (rate == 25) tag = MKTAG('a','i','1','q');
2081 ✗ else if (rate == 30) tag = MKTAG('a','i','1','p');
2082 ✗ else if (rate == 50) tag = MKTAG('a','i','1','q');
2083 ✗ else if (rate == 60) tag = MKTAG('a','i','1','p');
2084 }
2085 ✗ } else if (track->par->width == 1920 && track->par->height == 1080) {
2086 ✗ if (!interlaced) {
2087 ✗ if (rate == 24) tag = MKTAG('a','i','1','3');
2088 ✗ else if (rate == 25) tag = MKTAG('a','i','1','2');
2089 ✗ else if (rate == 30) tag = MKTAG('a','i','1','3');
2090 } else {
2091 ✗ if (rate == 25) tag = MKTAG('a','i','1','5');
2092 ✗ else if (rate == 50) tag = MKTAG('a','i','1','5');
2093 ✗ else if (rate == 60) tag = MKTAG('a','i','1','6');
2094 }
2095 ✗ } else if ( track->par->width == 4096 && track->par->height == 2160
2096 ✗ || track->par->width == 3840 && track->par->height == 2160
2097 ✗ || track->par->width == 2048 && track->par->height == 1080) {
2098 ✗ tag = MKTAG('a','i','v','x');
2099 }
2100 }
2101
2102 ✗ return tag;
2103 }
2104
2105 ✗ static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
2106 {
2107 ✗ int tag = track->par->codec_tag;
2108
2109 ✗ if (!tag)
2110 ✗ tag = MKTAG('e', 'v', 'c', '1');
2111
2112 ✗ return tag;
2113 }
2114
2115 ✗ static int mov_get_apv_codec_tag(AVFormatContext *s, MOVTrack *track)
2116 {
2117 ✗ int tag = track->par->codec_tag;
2118
2119 ✗ if (!tag)
2120 ✗ tag = MKTAG('a', 'p', 'v', '1');
2121
2122 ✗ return tag;
2123 }
2124
2125
2126 static const struct {
2127 enum AVPixelFormat pix_fmt;
2128 uint32_t tag;
2129 unsigned bps;
2130 } mov_pix_fmt_tags[] = {
2131 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
2132 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
2133 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
2134 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
2135 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
2136 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
2137 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
2138 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
2139 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
2140 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
2141 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
2142 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
2143 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
2144 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
2145 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
2146 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
2147 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
2148 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
2149 };
2150
2151 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
2152 {
2153 23 int tag = MKTAG('A','V','d','n');
2154
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
2155
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
2156 12 tag = MKTAG('A','V','d','h');
2157 23 return tag;
2158 }
2159
2160 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
2161 {
2162 17 int tag = track->par->codec_tag;
2163 int i;
2164 enum AVPixelFormat pix_fmt;
2165
2166
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 12 times.
264 for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
2167
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
2168 17 tag = mov_pix_fmt_tags[i].tag;
2169 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
2170
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
2171 5 break;
2172 }
2173 }
2174
2175 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
2176 17 track->par->bits_per_coded_sample);
2177
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
2178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
2179 ✗ track->par->format != AV_PIX_FMT_GRAY8 &&
2180 ✗ track->par->format != AV_PIX_FMT_NONE)
2181 ✗ av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
2182 ✗ av_get_pix_fmt_name(track->par->format));
2183 17 return tag;
2184 }
2185
2186 170 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
2187 {
2188 170 unsigned int tag = track->par->codec_tag;
2189
2190 // "rtp " is used to distinguish internally created RTP-hint tracks
2191 // (with rtp_ctx) from other tracks.
2192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 if (tag == MKTAG('r','t','p',' '))
2193 ✗ tag = 0;
2194
3/4
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 36 times.
170 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
2195
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
2196
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 17 times.
133 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
2197
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 track->par->codec_id == AV_CODEC_ID_H263 ||
2198
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 2 times.
116 track->par->codec_id == AV_CODEC_ID_H264 ||
2199
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 23 times.
114 track->par->codec_id == AV_CODEC_ID_DNXHD ||
2200
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 72 times.
181 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
2201 90 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
2202
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
2203 1 tag = mov_get_dv_codec_tag(s, track);
2204
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
2205 17 tag = mov_get_rawvideo_codec_tag(s, track);
2206
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
2207 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
2208
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
2209 2 tag = mov_get_h264_codec_tag(s, track);
2210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
2211 ✗ tag = mov_get_evc_codec_tag(s, track);
2212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_APV)
2213 ✗ tag = mov_get_apv_codec_tag(s, track);
2214
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
2215 23 tag = mov_get_dnxhd_codec_tag(s, track);
2216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
2217 ✗ tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
2218 ✗ if (!tag) { // if no mac fcc found, try with Microsoft tags
2219 ✗ tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2220 ✗ if (tag)
2221 ✗ av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2222 "the file may be unplayable!\n");
2223 }
2224
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2225 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2227 ✗ int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2228 ✗ if (ms_tag) {
2229 ✗ tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2230 ✗ av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2231 "the file may be unplayable!\n");
2232 }
2233 }
2234 ✗ } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2235 ✗ tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2236 }
2237
2238 170 return tag;
2239 }
2240
2241 static const AVCodecTag codec_cover_image_tags[] = {
2242 { AV_CODEC_ID_MJPEG, 0xD },
2243 { AV_CODEC_ID_PNG, 0xE },
2244 { AV_CODEC_ID_BMP, 0x1B },
2245 { AV_CODEC_ID_NONE, 0 },
2246 };
2247
2248 238 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2249 unsigned int tag, int codec_id)
2250 {
2251 int i;
2252
2253 /**
2254 * Check that tag + id is in the table
2255 */
2256
2/4
✓ Branch 0 taken 238 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 238 times.
✗ Branch 3 not taken.
238 for (i = 0; tags && tags[i]; i++) {
2257 238 const AVCodecTag *codec_tags = tags[i];
2258
1/2
✓ Branch 0 taken 5030 times.
✗ Branch 1 not taken.
5030 while (codec_tags->id != AV_CODEC_ID_NONE) {
2259
2/2
✓ Branch 2 taken 560 times.
✓ Branch 3 taken 4470 times.
5030 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2260
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 322 times.
560 codec_tags->id == codec_id)
2261 238 return codec_tags->tag;
2262 4792 codec_tags++;
2263 }
2264 }
2265 ✗ return 0;
2266 }
2267
2268 410 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2269 {
2270
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 408 times.
410 if (is_cover_image(track->st))
2271 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2272
2273
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 407 times.
408 if (track->mode == MODE_IPOD)
2274
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 if (!av_match_ext(s->url, "m4a") &&
2275
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2276 1 !av_match_ext(s->url, "m4b"))
2277 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2278 "Quicktime/Ipod might not play the file\n");
2279
2280
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 238 times.
408 if (track->mode == MODE_MOV) {
2281 170 return mov_get_codec_tag(s, track);
2282 } else
2283 238 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2284 238 track->par->codec_id);
2285 }
2286
2287 /** Write uuid atom.
2288 * Needed to make file play in iPods running newest firmware
2289 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2290 */
2291 ✗ static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2292 {
2293 ✗ avio_wb32(pb, 28);
2294 ✗ ffio_wfourcc(pb, "uuid");
2295 ✗ avio_wb32(pb, 0x6b6840f2);
2296 ✗ avio_wb32(pb, 0x5f244fc5);
2297 ✗ avio_wb32(pb, 0xba39a51b);
2298 ✗ avio_wb32(pb, 0xcf0323f3);
2299 ✗ avio_wb32(pb, 0x0);
2300 ✗ return 28;
2301 }
2302
2303 static const uint16_t fiel_data[] = {
2304 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2305 };
2306
2307 101 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2308 {
2309 101 unsigned mov_field_order = 0;
2310
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2311 101 mov_field_order = fiel_data[field_order];
2312 else
2313 ✗ return 0;
2314 101 avio_wb32(pb, 10);
2315 101 ffio_wfourcc(pb, "fiel");
2316 101 avio_wb16(pb, mov_field_order);
2317 101 return 10;
2318 }
2319
2320 6 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2321 {
2322 6 MOVMuxContext *mov = s->priv_data;
2323 6 int ret = AVERROR_BUG;
2324 6 int64_t pos = avio_tell(pb);
2325 6 avio_wb32(pb, 0); /* size */
2326 6 avio_wl32(pb, track->tag); // store it byteswapped
2327 6 avio_wb32(pb, 0); /* Reserved */
2328 6 avio_wb16(pb, 0); /* Reserved */
2329 6 avio_wb16(pb, 1); /* Data-reference index */
2330
2331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2332 ✗ mov_write_esds_tag(pb, track);
2333
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2334
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 switch (track->par->codec_tag) {
2335 2 case MOV_ISMV_TTML_TAG:
2336 // ISMV dfxp requires no extradata.
2337 4 break;
2338 2 case MOV_MP4_TTML_TAG:
2339 // As specified in 14496-30, XMLSubtitleSampleEntry
2340 // Namespace
2341 2 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2342 // Empty schema_location
2343 2 avio_w8(pb, 0);
2344 // Empty auxiliary_mime_types
2345 2 avio_w8(pb, 0);
2346 2 break;
2347 ✗ default:
2348 ✗ av_log(NULL, AV_LOG_ERROR,
2349 "Unknown codec tag '%s' utilized for TTML stream with "
2350 "index %d (track id %d)!\n",
2351 ✗ av_fourcc2str(track->par->codec_tag), track->st->index,
2352 track->track_id);
2353 ✗ return AVERROR(EINVAL);
2354 }
2355
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->extradata_size[track->last_stsd_index])
2356 2 avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
2357
2358
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
11 if (mov->write_btrt &&
2359 5 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2360 ✗ return ret;
2361
2362 6 return update_size(pb, pos);
2363 }
2364
2365 1 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2366 {
2367 int8_t stereo_mode;
2368
2369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo_3d->flags != 0) {
2370 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2371 ✗ return 0;
2372 }
2373
2374
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo_3d->type) {
2375 ✗ case AV_STEREO3D_2D:
2376 ✗ stereo_mode = 0;
2377 ✗ break;
2378 ✗ case AV_STEREO3D_TOPBOTTOM:
2379 ✗ stereo_mode = 1;
2380 ✗ break;
2381 1 case AV_STEREO3D_SIDEBYSIDE:
2382 1 stereo_mode = 2;
2383 1 break;
2384 ✗ default:
2385 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2386 ✗ return 0;
2387 }
2388 1 avio_wb32(pb, 13); /* size */
2389 1 ffio_wfourcc(pb, "st3d");
2390 1 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2391 1 avio_w8(pb, stereo_mode);
2392 1 return 13;
2393 }
2394
2395 ✗ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2396 {
2397 int64_t sv3d_pos, svhd_pos, proj_pos;
2398 ✗ const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2399
2400 ✗ if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2401 ✗ spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2402 ✗ spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2403 ✗ av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2404 ✗ return 0;
2405 }
2406
2407 ✗ sv3d_pos = avio_tell(pb);
2408 ✗ avio_wb32(pb, 0); /* size */
2409 ✗ ffio_wfourcc(pb, "sv3d");
2410
2411 ✗ svhd_pos = avio_tell(pb);
2412 ✗ avio_wb32(pb, 0); /* size */
2413 ✗ ffio_wfourcc(pb, "svhd");
2414 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2415 ✗ avio_put_str(pb, metadata_source);
2416 ✗ update_size(pb, svhd_pos);
2417
2418 ✗ proj_pos = avio_tell(pb);
2419 ✗ avio_wb32(pb, 0); /* size */
2420 ✗ ffio_wfourcc(pb, "proj");
2421
2422 ✗ avio_wb32(pb, 24); /* size */
2423 ✗ ffio_wfourcc(pb, "prhd");
2424 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2425 ✗ avio_wb32(pb, spherical_mapping->yaw);
2426 ✗ avio_wb32(pb, spherical_mapping->pitch);
2427 ✗ avio_wb32(pb, spherical_mapping->roll);
2428
2429 ✗ switch (spherical_mapping->projection) {
2430 ✗ case AV_SPHERICAL_EQUIRECTANGULAR:
2431 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2432 ✗ avio_wb32(pb, 28); /* size */
2433 ✗ ffio_wfourcc(pb, "equi");
2434 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2435 ✗ avio_wb32(pb, spherical_mapping->bound_top);
2436 ✗ avio_wb32(pb, spherical_mapping->bound_bottom);
2437 ✗ avio_wb32(pb, spherical_mapping->bound_left);
2438 ✗ avio_wb32(pb, spherical_mapping->bound_right);
2439 ✗ break;
2440 ✗ case AV_SPHERICAL_CUBEMAP:
2441 ✗ avio_wb32(pb, 20); /* size */
2442 ✗ ffio_wfourcc(pb, "cbmp");
2443 ✗ avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2444 ✗ avio_wb32(pb, 0); /* layout */
2445 ✗ avio_wb32(pb, spherical_mapping->padding); /* padding */
2446 ✗ break;
2447 }
2448 ✗ update_size(pb, proj_pos);
2449
2450 ✗ return update_size(pb, sv3d_pos);
2451 }
2452
2453 5 static inline int64_t rescale_rational(AVRational q, int b)
2454 {
2455 5 return av_rescale(q.num, b, q.den);
2456 }
2457
2458 2 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2459 const AVStereo3D *stereo3d)
2460 {
2461
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!stereo3d->horizontal_field_of_view.num)
2462 1 return;
2463
2464 1 avio_wb32(pb, 12); /* size */
2465 1 ffio_wfourcc(pb, "hfov");
2466 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2467 }
2468
2469 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2470 const AVSphericalMapping *spherical_mapping)
2471 {
2472 1 avio_wb32(pb, 24); /* size */
2473 1 ffio_wfourcc(pb, "proj");
2474 1 avio_wb32(pb, 16); /* size */
2475 1 ffio_wfourcc(pb, "prji");
2476 1 avio_wb32(pb, 0); /* version + flags */
2477
2478
1/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (spherical_mapping->projection) {
2479 1 case AV_SPHERICAL_RECTILINEAR:
2480 1 ffio_wfourcc(pb, "rect");
2481 1 break;
2482 ✗ case AV_SPHERICAL_EQUIRECTANGULAR:
2483 ✗ ffio_wfourcc(pb, "equi");
2484 ✗ break;
2485 ✗ case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2486 ✗ ffio_wfourcc(pb, "hequ");
2487 ✗ break;
2488 ✗ case AV_SPHERICAL_FISHEYE:
2489 ✗ ffio_wfourcc(pb, "fish");
2490 ✗ break;
2491 ✗ default:
2492 ✗ av_assert0(0);
2493 }
2494 1 }
2495
2496 2 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2497 const AVStereo3D *stereo3d)
2498 {
2499 2 int64_t pos = avio_tell(pb);
2500 2 int view = 0;
2501
2502 2 avio_wb32(pb, 0); /* size */
2503 2 ffio_wfourcc(pb, "eyes");
2504
2505 // stri is mandatory
2506 2 avio_wb32(pb, 13); /* size */
2507 2 ffio_wfourcc(pb, "stri");
2508 2 avio_wb32(pb, 0); /* version + flags */
2509
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 switch (stereo3d->view) {
2510 ✗ case AV_STEREO3D_VIEW_LEFT:
2511 ✗ view |= 1 << 0;
2512 ✗ break;
2513 ✗ case AV_STEREO3D_VIEW_RIGHT:
2514 ✗ view |= 1 << 1;
2515 ✗ break;
2516 2 case AV_STEREO3D_VIEW_PACKED:
2517 2 view |= (1 << 0) | (1 << 1);
2518 2 break;
2519 }
2520 2 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2521 2 avio_w8(pb, view);
2522
2523 // hero is optional
2524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2525 ✗ avio_wb32(pb, 13); /* size */
2526 ✗ ffio_wfourcc(pb, "hero");
2527 ✗ avio_wb32(pb, 0); /* version + flags */
2528 ✗ avio_w8(pb, stereo3d->primary_eye);
2529 }
2530
2531 // it's not clear if cams is mandatory or optional
2532
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->baseline) {
2533 1 avio_wb32(pb, 24); /* size */
2534 1 ffio_wfourcc(pb, "cams");
2535 1 avio_wb32(pb, 16); /* size */
2536 1 ffio_wfourcc(pb, "blin");
2537 1 avio_wb32(pb, 0); /* version + flags */
2538 1 avio_wb32(pb, stereo3d->baseline);
2539 }
2540
2541 // it's not clear if cmfy is mandatory or optional
2542
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (stereo3d->horizontal_disparity_adjustment.num) {
2543 1 avio_wb32(pb, 24); /* size */
2544 1 ffio_wfourcc(pb, "cmfy");
2545 1 avio_wb32(pb, 16); /* size */
2546 1 ffio_wfourcc(pb, "dadj");
2547 1 avio_wb32(pb, 0); /* version + flags */
2548 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2549 }
2550
2551 2 return update_size(pb, pos);
2552 }
2553
2554 2 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2555 const AVStereo3D *stereo3d,
2556 const AVSphericalMapping *spherical_mapping)
2557 {
2558 int64_t pos;
2559
2560
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping &&
2561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2562 ✗ spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2563 ✗ spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2564 ✗ spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2565 ✗ av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2566 ✗ spherical_mapping->projection);
2567 ✗ spherical_mapping = NULL;
2568 }
2569
2570
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2571
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2573 ✗ stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2574 ✗ !stereo3d->baseline &&
2575 ✗ !stereo3d->horizontal_disparity_adjustment.num))) {
2576 ✗ av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2577 ✗ stereo3d = NULL;
2578 }
2579
2580
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (!spherical_mapping && !stereo3d)
2581 ✗ return 0;
2582
2583 2 pos = avio_tell(pb);
2584 2 avio_wb32(pb, 0); /* size */
2585 2 ffio_wfourcc(pb, "vexu");
2586
2587
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (spherical_mapping)
2588 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2589
2590
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (stereo3d)
2591 2 mov_write_eyes_tag(s, pb, stereo3d);
2592
2593 2 return update_size(pb, pos);
2594 }
2595
2596 2 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2597 {
2598 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2599
2600 2 avio_wb32(pb, 32); /* size = 8 + 24 */
2601
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (dovi->dv_profile > 10)
2602 ✗ ffio_wfourcc(pb, "dvwC");
2603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (dovi->dv_profile > 7)
2604 ✗ ffio_wfourcc(pb, "dvvC");
2605 else
2606 2 ffio_wfourcc(pb, "dvcC");
2607
2608 2 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2609 2 avio_write(pb, buf, sizeof(buf));
2610
2611 2 return 32; /* 8 + 24 */
2612 }
2613
2614 2 static int mov_write_hvce_tag(AVIOContext *pb, const AVPacketSideData *sd)
2615 {
2616 2 avio_wb32(pb, 8 + sd->size);
2617 2 ffio_wfourcc(pb, "hvcE");
2618 2 avio_write(pb, sd->data, sd->size);
2619 2 return 8 + sd->size;
2620 }
2621
2622 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2623 uint32_t top, uint32_t bottom,
2624 uint32_t left, uint32_t right)
2625 {
2626 5 uint32_t cropped_width = track->par->width - left - right;
2627 5 uint32_t cropped_height = track->height - top - bottom;
2628 AVRational horizOff =
2629 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2630 5 (AVRational) { left, 1 });
2631 AVRational vertOff =
2632 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2633 5 (AVRational) { top, 1 });
2634
2635 5 avio_wb32(pb, 40);
2636 5 ffio_wfourcc(pb, "clap");
2637 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2638 5 avio_wb32(pb, 1); /* apertureWidthD */
2639 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2640 5 avio_wb32(pb, 1); /* apertureHeightD */
2641
2642 5 avio_wb32(pb, -horizOff.num);
2643 5 avio_wb32(pb, horizOff.den);
2644 5 avio_wb32(pb, -vertOff.num);
2645 5 avio_wb32(pb, vertOff.den);
2646
2647 5 return 40;
2648 }
2649
2650 28 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2651 {
2652 AVRational sar;
2653 28 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2654 28 track->par->sample_aspect_ratio.den, INT_MAX);
2655
2656 28 avio_wb32(pb, 16);
2657 28 ffio_wfourcc(pb, "pasp");
2658 28 avio_wb32(pb, sar.num);
2659 28 avio_wb32(pb, sar.den);
2660 28 return 16;
2661 }
2662
2663 ✗ static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2664 {
2665 ✗ uint32_t gama = 0;
2666 ✗ if (gamma <= 0.0)
2667 ✗ gamma = av_csp_approximate_eotf_gamma(track->par->color_trc);
2668 ✗ av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2669
2670 ✗ if (gamma > 1e-6) {
2671 ✗ gama = (uint32_t)lrint((double)(1<<16) * gamma);
2672 ✗ av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2673
2674 ✗ av_assert0(track->mode == MODE_MOV);
2675 ✗ avio_wb32(pb, 12);
2676 ✗ ffio_wfourcc(pb, "gama");
2677 ✗ avio_wb32(pb, gama);
2678 ✗ return 12;
2679 } else {
2680 ✗ av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2681 }
2682 ✗ return 0;
2683 }
2684
2685 12 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2686 {
2687 12 int64_t pos = avio_tell(pb);
2688
2689 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2690 // Ref (MP4): ISO/IEC 14496-12:2012
2691
2692
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (prefer_icc) {
2693 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2694 4 track->st->codecpar->nb_coded_side_data,
2695 AV_PKT_DATA_ICC_PROFILE);
2696
2697
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2698 ✗ avio_wb32(pb, 12 + sd->size);
2699 ✗ ffio_wfourcc(pb, "colr");
2700 ✗ ffio_wfourcc(pb, "prof");
2701 ✗ avio_write(pb, sd->data, sd->size);
2702 ✗ return 12 + sd->size;
2703 }
2704 else {
2705 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2706 }
2707 }
2708
2709 /* We should only ever be called for MOV, MP4 and AVIF. */
2710
3/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
12 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2711 track->mode == MODE_AVIF);
2712
2713 12 avio_wb32(pb, 0); /* size */
2714 12 ffio_wfourcc(pb, "colr");
2715
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2716 4 ffio_wfourcc(pb, "nclx");
2717 else
2718 8 ffio_wfourcc(pb, "nclc");
2719 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2720 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2721 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2722 12 avio_wb16(pb, track->par->color_primaries);
2723 12 avio_wb16(pb, track->par->color_trc);
2724 12 avio_wb16(pb, track->par->color_space);
2725
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2726 4 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2727 4 avio_w8(pb, full_range << 7);
2728 }
2729
2730 12 return update_size(pb, pos);
2731 }
2732
2733 231 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2734 {
2735 const AVPacketSideData *side_data;
2736 const AVContentLightMetadata *content_light_metadata;
2737
2738 231 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2739 231 track->st->codecpar->nb_coded_side_data,
2740 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2741
1/2
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
231 if (!side_data) {
2742 231 return 0;
2743 }
2744 ✗ content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2745
2746 ✗ avio_wb32(pb, 12); // size
2747 ✗ ffio_wfourcc(pb, "clli");
2748 ✗ avio_wb16(pb, content_light_metadata->MaxCLL);
2749 ✗ avio_wb16(pb, content_light_metadata->MaxFALL);
2750 ✗ return 12;
2751 }
2752
2753 231 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2754 {
2755 231 const int chroma_den = 50000;
2756 231 const int luma_den = 10000;
2757 const AVPacketSideData *side_data;
2758 231 const AVMasteringDisplayMetadata *metadata = NULL;
2759
2760 231 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2761 231 track->st->codecpar->nb_coded_side_data,
2762 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 231 times.
231 if (side_data)
2764 ✗ metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2765
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
231 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2766 231 return 0;
2767 }
2768
2769 ✗ avio_wb32(pb, 32); // size
2770 ✗ ffio_wfourcc(pb, "mdcv");
2771 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2772 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2773 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2774 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2775 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2776 ✗ avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2777 ✗ avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2778 ✗ avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2779 ✗ avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2780 ✗ avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2781 ✗ return 32;
2782 }
2783
2784 231 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2785 {
2786 231 const int illuminance_den = 10000;
2787 231 const int ambient_den = 50000;
2788 const AVPacketSideData *side_data;
2789 const AVAmbientViewingEnvironment *ambient;
2790
2791
2792 231 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2793 231 track->st->codecpar->nb_coded_side_data,
2794 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2795
2796
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 1 times.
231 if (!side_data)
2797 230 return 0;
2798
2799 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2800
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ambient || !ambient->ambient_illuminance.num)
2801 ✗ return 0;
2802
2803 1 avio_wb32(pb, 16); // size
2804 1 ffio_wfourcc(pb, "amve");
2805 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2806 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2807 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2808 1 return 16;
2809 }
2810
2811 237 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2812 {
2813 AVDictionaryEntry *encoder;
2814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2815
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
236 || (track->par->width == 1440 && track->par->height == 1080)
2816
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 223 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
474 || (track->par->width == 1920 && track->par->height == 1080);
2817
2818
1/2
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
237 if ((track->mode == MODE_AVIF ||
2819
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 144 times.
237 track->mode == MODE_MOV ||
2820
4/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 160 times.
✓ Branch 3 taken 71 times.
324 track->mode == MODE_MP4) &&
2821 231 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2822 160 av_strlcpy(compressor_name, encoder->value, 32);
2823
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
77 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2824 ✗ int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2825 ✗ AVStream *st = track->st;
2826 ✗ int rate = defined_frame_rate(NULL, st);
2827 ✗ av_strlcatf(compressor_name, len, "XDCAM");
2828 ✗ if (track->par->format == AV_PIX_FMT_YUV422P) {
2829 ✗ av_strlcatf(compressor_name, len, " HD422");
2830 ✗ } else if(track->par->width == 1440) {
2831 ✗ av_strlcatf(compressor_name, len, " HD");
2832 } else
2833 ✗ av_strlcatf(compressor_name, len, " EX");
2834
2835 ✗ av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2836
2837 ✗ av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2838 }
2839 237 }
2840
2841 ✗ static int mov_write_ccst_tag(AVIOContext *pb)
2842 {
2843 ✗ int64_t pos = avio_tell(pb);
2844 // Write sane defaults:
2845 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2846 // intra_pred_used = 1 : intra prediction may or may not be used.
2847 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2848 // reference images can be used.
2849 ✗ uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2850 (1 << 6) | /* intra_pred_used */
2851 (15 << 2); /* max_ref_per_pic */
2852 ✗ avio_wb32(pb, 0); /* size */
2853 ✗ ffio_wfourcc(pb, "ccst");
2854 ✗ avio_wb32(pb, 0); /* Version & flags */
2855 ✗ avio_w8(pb, ccstValue);
2856 ✗ avio_wb24(pb, 0); /* reserved */
2857 ✗ return update_size(pb, pos);
2858 }
2859
2860 ✗ static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2861 {
2862 ✗ int64_t pos = avio_tell(pb);
2863 ✗ avio_wb32(pb, 0); /* size */
2864 ✗ ffio_wfourcc(pb, aux_type);
2865 ✗ avio_wb32(pb, 0); /* Version & flags */
2866 ✗ avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2867 ✗ return update_size(pb, pos);
2868 }
2869
2870 237 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2871 {
2872 237 int ret = AVERROR_BUG;
2873 237 int64_t pos = avio_tell(pb);
2874 const AVPacketSideData *sd;
2875 237 char compressor_name[32] = { 0 };
2876 237 int avid = 0;
2877
2878
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422)
2879
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
237 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2880
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
237 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2881
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
237 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2882
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
237 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2883
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 233 times.
474 || track->par->codec_id == AV_CODEC_ID_V210);
2884
2885 237 avio_wb32(pb, 0); /* size */
2886
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 231 times.
237 if (mov->encryption_scheme != MOV_ENC_NONE) {
2887 6 ffio_wfourcc(pb, "encv");
2888 } else {
2889 231 avio_wl32(pb, track->tag); // store it byteswapped
2890 }
2891 237 avio_wb32(pb, 0); /* Reserved */
2892 237 avio_wb16(pb, 0); /* Reserved */
2893 237 avio_wb16(pb, 1); /* Data-reference index */
2894
2895
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 233 times.
237 if (uncompressed_ycbcr) {
2896 4 avio_wb16(pb, 2); /* Codec stream version */
2897 } else {
2898 233 avio_wb16(pb, 0); /* Codec stream version */
2899 }
2900 237 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2901
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 93 times.
237 if (track->mode == MODE_MOV) {
2902 144 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2903
3/4
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 127 times.
144 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2904 17 avio_wb32(pb, 0); /* Temporal Quality */
2905 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2906 } else {
2907 127 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2908 127 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2909 }
2910 } else {
2911 93 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2912 }
2913 237 avio_wb16(pb, track->par->width); /* Video width */
2914 237 avio_wb16(pb, track->height); /* Video height */
2915 237 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2916 237 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2917 237 avio_wb32(pb, 0); /* Data size (= 0) */
2918 237 avio_wb16(pb, 1); /* Frame count (= 1) */
2919
2920 237 find_compressor(compressor_name, 32, track);
2921 237 avio_w8(pb, strlen(compressor_name));
2922 237 avio_write(pb, compressor_name, 31);
2923
2924
3/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
237 if (track->mode == MODE_MOV && track->par->codec_id == AV_CODEC_ID_V210)
2925 ✗ avio_wb16(pb, 0x18);
2926
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 111 times.
237 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2927 33 avio_wb16(pb, track->par->bits_per_coded_sample |
2928
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2929 else
2930 204 avio_wb16(pb, 0x18); /* Reserved */
2931
2932
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 139 times.
242 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2933 int pal_size, i;
2934 5 avio_wb16(pb, 0); /* Color table ID */
2935 5 avio_wb32(pb, 0); /* Color table seed */
2936 5 avio_wb16(pb, 0x8000); /* Color table flags */
2937
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (track->par->bits_per_coded_sample < 0 || track->par->bits_per_coded_sample > 8)
2938 ✗ return AVERROR(EINVAL);
2939 5 pal_size = 1 << track->par->bits_per_coded_sample;
2940 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2941
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2942 1040 uint32_t rgb = track->palette[i];
2943 1040 uint16_t r = (rgb >> 16) & 0xff;
2944 1040 uint16_t g = (rgb >> 8) & 0xff;
2945 1040 uint16_t b = rgb & 0xff;
2946 1040 avio_wb16(pb, 0);
2947 1040 avio_wb16(pb, (r << 8) | r);
2948 1040 avio_wb16(pb, (g << 8) | g);
2949 1040 avio_wb16(pb, (b << 8) | b);
2950 }
2951 } else
2952 232 avio_wb16(pb, 0xffff); /* Reserved */
2953
2954
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 200 times.
237 if (track->tag == MKTAG('m','p','4','v'))
2955 37 mov_write_esds_tag(pb, track);
2956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 else if (track->par->codec_id == AV_CODEC_ID_H263)
2957 ✗ mov_write_d263_tag(pb);
2958
2/2
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 3 times.
200 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2960 3 mov_write_extradata_tag(pb, track);
2961 3 avio_wb32(pb, 0);
2962
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 174 times.
197 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2963 23 mov_write_avid_tag(pb, track);
2964 23 avid = 1;
2965
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 163 times.
174 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2966 11 mov_write_hvcc_tag(mov->fc, pb, track);
2967
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2968 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2970 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2971 }
2972
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 162 times.
163 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2973 1 mov_write_vvcc_tag(pb, track);
2974
16/30
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 102 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 60 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 60 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 60 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 60 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 60 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 60 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 60 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 60 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 60 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 60 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 60 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 60 times.
✗ Branch 29 not taken.
162 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2975 60 mov_write_avcc_tag(pb, track);
2976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (track->mode == MODE_IPOD)
2977 ✗ mov_write_uuid_tag_ipod(pb);
2978 }
2979
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 101 times.
102 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2980 1 mov_write_evcc_tag(pb, track);
2981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 } else if (track->par->codec_id == AV_CODEC_ID_LCEVC) {
2982 1 mov_write_lvcc_tag(mov->fc, pb, track);
2983
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
100 } else if (track->par->codec_id ==AV_CODEC_ID_APV) {
2984 1 mov_write_apvc_tag(mov->fc, pb, track);
2985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2986 ✗ mov_write_vpcc_tag(mov->fc, pb, track);
2987
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 97 times.
99 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2988 2 mov_write_av1c_tag(pb, track);
2989
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
97 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->extradata_size[track->last_stsd_index] > 0)
2990 ✗ mov_write_dvc1_tag(pb, track);
2991
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2992
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 track->par->codec_id == AV_CODEC_ID_VP6A) {
2993 /* Don't write any potential extradata here - the cropping
2994 * is signalled via the normal width/height fields. */
2995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2996 ✗ if (track->par->codec_tag == MKTAG('R','1','0','k'))
2997 ✗ mov_write_dpxe_tag(pb, track);
2998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2999 ✗ mov_write_av3c_tag(pb, track);
3000
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 } else if (track->extradata_size[track->last_stsd_index] > 0)
3001 4 mov_write_glbl_tag(pb, track);
3002
3003
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 60 times.
237 if (track->par->codec_id != AV_CODEC_ID_H264 &&
3004
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 31 times.
177 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
3005
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 23 times.
146 track->par->codec_id != AV_CODEC_ID_DNXHD) {
3006 123 int field_order = track->par->field_order;
3007
3008
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 22 times.
123 if (field_order != AV_FIELD_UNKNOWN)
3009 101 mov_write_fiel_tag(pb, track, field_order);
3010 }
3011
3012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
3013 ✗ if (track->mode == MODE_MOV)
3014 ✗ mov_write_gama_tag(s, pb, track, mov->gamma);
3015 else
3016 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
3017 }
3018
5/6
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 87 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
468 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
3019 470 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
3020
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 223 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
239 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
3021
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
3022
5/6
✓ Branch 0 taken 223 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 219 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 219 times.
450 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
3023 219 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
3024 AV_PKT_DATA_ICC_PROFILE)) {
3025
3/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
12 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
3026 12 mov_write_colr_tag(pb, track, prefer_icc);
3027 }
3028
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
3029 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
3030 }
3031
3032
4/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 6 times.
237 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
3033 231 mov_write_clli_tag(pb, track);
3034 231 mov_write_mdcv_tag(pb, track);
3035 231 mov_write_amve_tag(pb, track);
3036 }
3037
3038
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 150 times.
237 if (track->mode == MODE_MP4) {
3039 87 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3040 87 track->st->codecpar->nb_coded_side_data,
3041 AV_PKT_DATA_STEREO3D);
3042 87 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3043 87 track->st->codecpar->nb_coded_side_data,
3044 AV_PKT_DATA_SPHERICAL);
3045
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
87 if (stereo_3d && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3046 1 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
3047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
86 else if (stereo_3d)
3048 ✗ av_log(s, AV_LOG_WARNING, "Writing supported 'st3d' metadata requires -strict unofficial.\n");
3049
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
87 if (spherical_mapping && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)
3050 ✗ mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
3051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
87 else if (spherical_mapping)
3052 ✗ av_log(s, AV_LOG_WARNING, "Writing supported 'sv3d' metadata requires -strict unofficial.\n");
3053 }
3054
3055
4/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 6 times.
237 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
3056
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 84 times.
87 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
3057 147 const AVStereo3D *stereo3d = NULL;
3058 147 const AVSphericalMapping *spherical_mapping = NULL;
3059
3060 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3061 147 track->st->codecpar->nb_coded_side_data,
3062 AV_PKT_DATA_STEREO3D);
3063
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (sd)
3064 2 stereo3d = (AVStereo3D *)sd->data;
3065
3066 147 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3067 147 track->st->codecpar->nb_coded_side_data,
3068 AV_PKT_DATA_SPHERICAL);
3069
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 146 times.
147 if (sd)
3070 1 spherical_mapping = (AVSphericalMapping *)sd->data;
3071
3072
3/4
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 145 times.
147 if (stereo3d || spherical_mapping)
3073 2 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
3074
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145 times.
147 if (stereo3d)
3075 2 mov_write_hfov_tag(s, pb, stereo3d);
3076 }
3077
3078
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 150 times.
237 if (track->mode == MODE_MP4) {
3079 87 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3080 87 track->st->codecpar->nb_coded_side_data,
3081 AV_PKT_DATA_DOVI_CONF);
3082
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
87 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3083 2 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
3084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 } else if (dovi) {
3085 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
3086 }
3087
3088 87 const AVPacketSideData *hvce = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3089 87 track->st->codecpar->nb_coded_side_data,
3090 AV_PKT_DATA_HEVC_CONF);
3091
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
87 if (hvce && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
3092 2 mov_write_hvce_tag(pb, hvce);
3093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 } else if (hvce) {
3094 ✗ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'hvcE' box. Requires -strict unofficial.\n");
3095 }
3096 }
3097
3098
3/4
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 209 times.
237 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
3099 28 mov_write_pasp_tag(pb, track);
3100 }
3101
3102 237 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
3103 237 track->st->codecpar->nb_coded_side_data,
3104 AV_PKT_DATA_FRAME_CROPPING);
3105
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
238 if (sd && sd->size >= sizeof(uint32_t) * 4) {
3106 1 uint64_t top = AV_RL32(sd->data + 0);
3107 1 uint64_t bottom = AV_RL32(sd->data + 4);
3108 1 uint64_t left = AV_RL32(sd->data + 8);
3109 1 uint64_t right = AV_RL32(sd->data + 12);
3110
3111
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
3112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
3113 ✗ av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
3114 ✗ return AVERROR(EINVAL);
3115 }
3116
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (top || bottom || left || right)
3117 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
3118
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 232 times.
236 } else if (uncompressed_ycbcr)
3119 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
3120
3121
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 231 times.
237 if (mov->encryption_scheme != MOV_ENC_NONE) {
3122 6 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
3123 }
3124
3125
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 87 times.
324 if (mov->write_btrt &&
3126 87 ((ret = mov_write_btrt_tag(pb, track)) < 0))
3127 ✗ return ret;
3128
3129 /* extra padding for avid stsd */
3130 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
3131
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 214 times.
237 if (avid)
3132 23 avio_wb32(pb, 0);
3133
3134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (track->mode == MODE_AVIF) {
3135 ✗ mov_write_ccst_tag(pb);
3136 ✗ if (mov->nb_streams > 0 && track == &mov->tracks[1])
3137 ✗ mov_write_aux_tag(pb, "auxi");
3138 }
3139
3140 237 return update_size(pb, pos);
3141 }
3142
3143 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
3144 {
3145 2 int64_t pos = avio_tell(pb);
3146 2 avio_wb32(pb, 0); /* size */
3147 2 ffio_wfourcc(pb, "rtp ");
3148 2 avio_wb32(pb, 0); /* Reserved */
3149 2 avio_wb16(pb, 0); /* Reserved */
3150 2 avio_wb16(pb, 1); /* Data-reference index */
3151
3152 2 avio_wb16(pb, 1); /* Hint track version */
3153 2 avio_wb16(pb, 1); /* Highest compatible version */
3154 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
3155
3156 2 avio_wb32(pb, 12); /* size */
3157 2 ffio_wfourcc(pb, "tims");
3158 2 avio_wb32(pb, track->timescale);
3159
3160 2 return update_size(pb, pos);
3161 }
3162
3163 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
3164 {
3165 2 uint64_t str_size =strlen(reel_name);
3166 2 int64_t pos = avio_tell(pb);
3167
3168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
3169 ✗ av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
3170 ✗ avio_wb16(pb, 0);
3171 ✗ return AVERROR(EINVAL);
3172 }
3173
3174 2 avio_wb32(pb, 0); /* size */
3175 2 ffio_wfourcc(pb, "name"); /* Data format */
3176 2 avio_wb16(pb, str_size); /* string size */
3177 2 avio_wb16(pb, track->language); /* langcode */
3178 2 avio_write(pb, reel_name, str_size); /* reel name */
3179 2 return update_size(pb,pos);
3180 }
3181
3182 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
3183 {
3184 13 int64_t pos = avio_tell(pb);
3185 #if 1
3186 int frame_duration;
3187 int nb_frames;
3188 13 AVDictionaryEntry *t = NULL;
3189
3190
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 if (!track->st->avg_frame_rate.num || !track->st->avg_frame_rate.den) {
3191 ✗ av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
3192 ✗ return AVERROR(EINVAL);
3193 } else {
3194 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
3195
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 nb_frames = ROUNDED_DIV(track->st->avg_frame_rate.num, track->st->avg_frame_rate.den);
3196 }
3197
3198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
3199 ✗ av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
3200 ✗ return AVERROR(EINVAL);
3201 }
3202
3203 13 avio_wb32(pb, 0); /* size */
3204 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
3205 13 avio_wb32(pb, 0); /* Reserved */
3206 13 avio_wb32(pb, 1); /* Data reference index */
3207 13 avio_wb32(pb, 0); /* Flags */
3208 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
3209 13 avio_wb32(pb, track->timescale); /* Timescale */
3210 13 avio_wb32(pb, frame_duration); /* Frame duration */
3211 13 avio_w8(pb, nb_frames); /* Number of frames */
3212 13 avio_w8(pb, 0); /* Reserved */
3213
3214 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
3215
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
13 if (t && utf8len(t->value) && track->mode != MODE_MP4)
3216 2 mov_write_source_reference_tag(pb, track, t->value);
3217 else
3218 11 avio_wb16(pb, 0); /* zero size */
3219 #else
3220
3221 avio_wb32(pb, 0); /* size */
3222 ffio_wfourcc(pb, "tmcd"); /* Data format */
3223 avio_wb32(pb, 0); /* Reserved */
3224 avio_wb32(pb, 1); /* Data reference index */
3225 if (track->par->extradata_size)
3226 avio_write(pb, track->par->extradata, track->par->extradata_size);
3227 #endif
3228 13 return update_size(pb, pos);
3229 }
3230
3231 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
3232 {
3233 1 int64_t pos = avio_tell(pb);
3234 1 avio_wb32(pb, 0); /* size */
3235 1 ffio_wfourcc(pb, "gpmd");
3236 1 avio_wb32(pb, 0); /* Reserved */
3237 1 avio_wb16(pb, 0); /* Reserved */
3238 1 avio_wb16(pb, 1); /* Data-reference index */
3239 1 avio_wb32(pb, 0); /* Reserved */
3240 1 return update_size(pb, pos);
3241 }
3242
3243 588 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3244 {
3245 588 int64_t pos = avio_tell(pb);
3246 588 int ret = 0;
3247 588 avio_wb32(pb, 0); /* size */
3248 588 ffio_wfourcc(pb, "stsd");
3249 588 avio_wb32(pb, 0); /* version & flags */
3250 588 avio_wb32(pb, track->stsd_count);
3251
3252 588 int stsd_index_back = track->last_stsd_index;
3253 588 for (track->last_stsd_index = 0;
3254
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 588 times.
1178 track->last_stsd_index < track->stsd_count;
3255 590 track->last_stsd_index++) {
3256
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 353 times.
590 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3257 237 ret = mov_write_video_tag(s, pb, mov, track);
3258
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 22 times.
353 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3259 331 ret = mov_write_audio_tag(s, pb, mov, track);
3260
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3261 6 ret = mov_write_subtitle_tag(s, pb, track);
3262
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3263 2 ret = mov_write_rtp_tag(pb, track);
3264
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3265 13 ret = mov_write_tmcd_tag(pb, track);
3266
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3267 1 ret = mov_write_gpmd_tag(pb, track);
3268
3269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 590 times.
590 if (ret < 0)
3270 ✗ return ret;
3271 }
3272
3273 588 track->last_stsd_index = stsd_index_back;
3274
3275 588 return update_size_and_version(pb, pos, track->entry_version);
3276 }
3277
3278 17 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3279 {
3280 17 MOVMuxContext *mov = s->priv_data;
3281 MOVCtts *ctts_entries;
3282 17 uint32_t entries = 0;
3283 uint32_t atom_size;
3284 int i;
3285
3286 17 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!ctts_entries)
3288 ✗ return AVERROR(ENOMEM);
3289 17 ctts_entries[0].count = 1;
3290 17 ctts_entries[0].offset = track->cluster[0].cts;
3291
2/2
✓ Branch 0 taken 818 times.
✓ Branch 1 taken 17 times.
835 for (i = 1; i < track->entry; i++) {
3292
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 677 times.
818 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3293 141 ctts_entries[entries].count++; /* compress */
3294 } else {
3295 677 entries++;
3296 677 ctts_entries[entries].offset = track->cluster[i].cts;
3297 677 ctts_entries[entries].count = 1;
3298 }
3299 }
3300 17 entries++; /* last one */
3301 17 atom_size = 16 + (entries * 8);
3302 17 avio_wb32(pb, atom_size); /* size */
3303 17 ffio_wfourcc(pb, "ctts");
3304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3305 ✗ avio_w8(pb, 1); /* version */
3306 else
3307 17 avio_w8(pb, 0); /* version */
3308 17 avio_wb24(pb, 0); /* flags */
3309 17 avio_wb32(pb, entries); /* entry count */
3310
2/2
✓ Branch 0 taken 694 times.
✓ Branch 1 taken 17 times.
711 for (i = 0; i < entries; i++) {
3311 694 avio_wb32(pb, ctts_entries[i].count);
3312 694 avio_wb32(pb, ctts_entries[i].offset);
3313 }
3314 17 av_free(ctts_entries);
3315 17 return atom_size;
3316 }
3317
3318 /* Time to sample atom */
3319 588 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3320 {
3321 588 MOVStts *stts_entries = NULL;
3322 588 uint32_t entries = -1;
3323 uint32_t atom_size;
3324 int i;
3325
3326
4/4
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 257 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 296 times.
588 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3327 35 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (!stts_entries)
3329 ✗ return AVERROR(ENOMEM);
3330 35 stts_entries[0].count = track->sample_count;
3331 35 stts_entries[0].duration = 1;
3332 35 entries = 1;
3333 } else {
3334
2/2
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 307 times.
553 if (track->entry) {
3335 246 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
246 if (!stts_entries)
3337 ✗ return AVERROR(ENOMEM);
3338 }
3339
2/2
✓ Branch 0 taken 16715 times.
✓ Branch 1 taken 553 times.
17268 for (i = 0; i < track->entry; i++) {
3340 16715 int duration = get_cluster_duration(track, i);
3341 #if CONFIG_IAMFENC
3342
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 16660 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
16715 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3343 ✗ duration = av_rescale(duration, 48000, track->par->sample_rate);
3344 #endif
3345
4/4
✓ Branch 0 taken 16469 times.
✓ Branch 1 taken 246 times.
✓ Branch 2 taken 16039 times.
✓ Branch 3 taken 430 times.
16715 if (i && duration == stts_entries[entries].duration) {
3346 16039 stts_entries[entries].count++; /* compress */
3347 } else {
3348 676 entries++;
3349 676 stts_entries[entries].duration = duration;
3350 676 stts_entries[entries].count = 1;
3351 }
3352 }
3353 553 entries++; /* last one */
3354 }
3355 588 atom_size = 16 + (entries * 8);
3356 588 avio_wb32(pb, atom_size); /* size */
3357 588 ffio_wfourcc(pb, "stts");
3358 588 avio_wb32(pb, 0); /* version & flags */
3359 588 avio_wb32(pb, entries); /* entry count */
3360
2/2
✓ Branch 0 taken 711 times.
✓ Branch 1 taken 588 times.
1299 for (i = 0; i < entries; i++) {
3361 711 avio_wb32(pb, stts_entries[i].count);
3362 711 avio_wb32(pb, stts_entries[i].duration);
3363 }
3364 588 av_free(stts_entries);
3365 588 return atom_size;
3366 }
3367
3368 588 static int mov_write_dref_tag(AVIOContext *pb)
3369 {
3370 588 avio_wb32(pb, 28); /* size */
3371 588 ffio_wfourcc(pb, "dref");
3372 588 avio_wb32(pb, 0); /* version & flags */
3373 588 avio_wb32(pb, 1); /* entry count */
3374
3375 588 avio_wb32(pb, 0xc); /* size */
3376 //FIXME add the alis and rsrc atom
3377 588 ffio_wfourcc(pb, "url ");
3378 588 avio_wb32(pb, 1); /* version & flags */
3379
3380 588 return 28;
3381 }
3382
3383 67 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3384 {
3385 struct sgpd_entry {
3386 int count;
3387 int16_t roll_distance;
3388 int group_description_index;
3389 };
3390
3391 67 struct sgpd_entry *sgpd_entries = NULL;
3392 67 int entries = -1;
3393 67 int group = 0;
3394 int i, j;
3395
3396 67 const int OPUS_SEEK_PREROLL_MS = 80;
3397 67 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3398 67 (AVRational){1, 1000},
3399 67 (AVRational){1, 48000});
3400
3401
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 22 times.
67 if (!track->entry)
3402 45 return 0;
3403
3404 22 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!sgpd_entries)
3406 ✗ return AVERROR(ENOMEM);
3407
3408
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3409
3410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3411 ✗ for (i = 0; i < track->entry; i++) {
3412 ✗ int roll_samples_remaining = roll_samples;
3413 ✗ int distance = 0;
3414 ✗ for (j = i - 1; j >= 0; j--) {
3415 ✗ roll_samples_remaining -= get_cluster_duration(track, j);
3416 ✗ distance++;
3417 ✗ if (roll_samples_remaining <= 0)
3418 ✗ break;
3419 }
3420 /* We don't have enough preceding samples to compute a valid
3421 roll_distance here, so this sample can't be independently
3422 decoded. */
3423 ✗ if (roll_samples_remaining > 0)
3424 ✗ distance = 0;
3425 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3426 ✗ if (distance > 32) {
3427 ✗ av_freep(&sgpd_entries);
3428 ✗ return AVERROR_INVALIDDATA;
3429 }
3430 ✗ if (i && distance == sgpd_entries[entries].roll_distance) {
3431 ✗ sgpd_entries[entries].count++;
3432 } else {
3433 ✗ entries++;
3434 ✗ sgpd_entries[entries].count = 1;
3435 ✗ sgpd_entries[entries].roll_distance = distance;
3436 ✗ sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3437 }
3438 }
3439 } else {
3440 22 entries++;
3441 22 sgpd_entries[entries].count = track->sample_count;
3442 22 sgpd_entries[entries].roll_distance = 1;
3443 22 sgpd_entries[entries].group_description_index = ++group;
3444 }
3445 22 entries++;
3446
3447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!group) {
3448 ✗ av_free(sgpd_entries);
3449 ✗ return 0;
3450 }
3451
3452 /* Write sgpd tag */
3453 22 avio_wb32(pb, 24 + (group * 2)); /* size */
3454 22 ffio_wfourcc(pb, "sgpd");
3455 22 avio_wb32(pb, 1 << 24); /* fullbox */
3456 22 ffio_wfourcc(pb, "roll");
3457 22 avio_wb32(pb, 2); /* default_length */
3458 22 avio_wb32(pb, group); /* entry_count */
3459
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 for (i = 0; i < entries; i++) {
3460
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (sgpd_entries[i].group_description_index) {
3461 22 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3462 }
3463 }
3464
3465 /* Write sbgp tag */
3466 22 avio_wb32(pb, 20 + (entries * 8)); /* size */
3467 22 ffio_wfourcc(pb, "sbgp");
3468 22 avio_wb32(pb, 0); /* fullbox */
3469 22 ffio_wfourcc(pb, "roll");
3470 22 avio_wb32(pb, entries); /* entry_count */
3471
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 for (i = 0; i < entries; i++) {
3472 22 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3473 22 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3474 }
3475
3476 22 av_free(sgpd_entries);
3477 22 return 0;
3478 }
3479
3480 588 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3481 {
3482 588 int64_t pos = avio_tell(pb);
3483 588 int ret = 0;
3484
3485 588 avio_wb32(pb, 0); /* size */
3486 588 ffio_wfourcc(pb, "stbl");
3487
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 588 times.
588 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3488 ✗ return ret;
3489 588 mov_write_stts_tag(pb, track);
3490
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 235 times.
588 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3491
1/2
✓ Branch 0 taken 353 times.
✗ Branch 1 not taken.
353 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3492
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 1 times.
353 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3493
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 285 times.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
352 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3494
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 350 times.
352 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3495
4/4
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 111 times.
238 track->has_keyframes && track->has_keyframes < track->entry)
3496 71 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3497
5/6
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 353 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 232 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
588 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable && track->entry)
3498 3 mov_write_sdtp_tag(pb, track);
3499
3/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
588 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3500 ✗ mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3501
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 353 times.
588 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3502
4/4
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 24 times.
235 track->flags & MOV_TRACK_CTTS && track->entry) {
3503
3504
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3505 ✗ return ret;
3506 }
3507 588 mov_write_stsc_tag(pb, track);
3508 588 mov_write_stsz_tag(pb, track);
3509 588 mov_write_stco_tag(pb, track);
3510
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 583 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
588 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3511 5 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3512 }
3513
3/4
✓ Branch 0 taken 588 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 521 times.
588 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3514 67 mov_preroll_write_stbl_atoms(pb, track);
3515 }
3516 588 return update_size(pb, pos);
3517 }
3518
3519 588 static int mov_write_dinf_tag(AVIOContext *pb)
3520 {
3521 588 int64_t pos = avio_tell(pb);
3522 588 avio_wb32(pb, 0); /* size */
3523 588 ffio_wfourcc(pb, "dinf");
3524 588 mov_write_dref_tag(pb);
3525 588 return update_size(pb, pos);
3526 }
3527
3528 7 static int mov_write_nmhd_tag(AVIOContext *pb)
3529 {
3530 7 avio_wb32(pb, 12);
3531 7 ffio_wfourcc(pb, "nmhd");
3532 7 avio_wb32(pb, 0);
3533 7 return 12;
3534 }
3535
3536 2 static int mov_write_sthd_tag(AVIOContext *pb)
3537 {
3538 2 avio_wb32(pb, 12);
3539 2 ffio_wfourcc(pb, "sthd");
3540 2 avio_wb32(pb, 0);
3541 2 return 12;
3542 }
3543
3544 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3545 {
3546 9 int64_t pos = avio_tell(pb);
3547 9 const char *font = "Lucida Grande";
3548 9 avio_wb32(pb, 0); /* size */
3549 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3550 9 avio_wb32(pb, 0); /* version & flags */
3551 9 avio_wb16(pb, 0); /* text font */
3552 9 avio_wb16(pb, 0); /* text face */
3553 9 avio_wb16(pb, 12); /* text size */
3554 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3555 9 avio_wb16(pb, 0x0000); /* text color (red) */
3556 9 avio_wb16(pb, 0x0000); /* text color (green) */
3557 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3558 9 avio_wb16(pb, 0xffff); /* background color (red) */
3559 9 avio_wb16(pb, 0xffff); /* background color (green) */
3560 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3561 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3562 9 avio_write(pb, font, strlen(font)); /* font name */
3563 9 return update_size(pb, pos);
3564 }
3565
3566 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3567 {
3568 11 int64_t pos = avio_tell(pb);
3569 11 avio_wb32(pb, 0); /* size */
3570 11 ffio_wfourcc(pb, "gmhd");
3571 11 avio_wb32(pb, 0x18); /* gmin size */
3572 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3573 11 avio_wb32(pb, 0); /* version & flags */
3574 11 avio_wb16(pb, 0x40); /* graphics mode = */
3575 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3576 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3577 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3578 11 avio_wb16(pb, 0); /* balance */
3579 11 avio_wb16(pb, 0); /* reserved */
3580
3581 /*
3582 * This special text atom is required for
3583 * Apple Quicktime chapters. The contents
3584 * don't appear to be documented, so the
3585 * bytes are copied verbatim.
3586 */
3587
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3588 11 avio_wb32(pb, 0x2C); /* size */
3589 11 ffio_wfourcc(pb, "text");
3590 11 avio_wb16(pb, 0x01);
3591 11 avio_wb32(pb, 0x00);
3592 11 avio_wb32(pb, 0x00);
3593 11 avio_wb32(pb, 0x00);
3594 11 avio_wb32(pb, 0x01);
3595 11 avio_wb32(pb, 0x00);
3596 11 avio_wb32(pb, 0x00);
3597 11 avio_wb32(pb, 0x00);
3598 11 avio_wb32(pb, 0x00004000);
3599 11 avio_wb16(pb, 0x0000);
3600 }
3601
3602
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3603 9 int64_t tmcd_pos = avio_tell(pb);
3604 9 avio_wb32(pb, 0); /* size */
3605 9 ffio_wfourcc(pb, "tmcd");
3606 9 mov_write_tcmi_tag(pb, track);
3607 9 update_size(pb, tmcd_pos);
3608
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3609 1 int64_t gpmd_pos = avio_tell(pb);
3610 1 avio_wb32(pb, 0); /* size */
3611 1 ffio_wfourcc(pb, "gpmd");
3612 1 avio_wb32(pb, 0); /* version */
3613 1 update_size(pb, gpmd_pos);
3614 }
3615 11 return update_size(pb, pos);
3616 }
3617
3618 331 static int mov_write_smhd_tag(AVIOContext *pb)
3619 {
3620 331 avio_wb32(pb, 16); /* size */
3621 331 ffio_wfourcc(pb, "smhd");
3622 331 avio_wb32(pb, 0); /* version & flags */
3623 331 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3624 331 avio_wb16(pb, 0); /* reserved */
3625 331 return 16;
3626 }
3627
3628 235 static uint16_t mov_graphics_mode(MOVTrack *track)
3629 {
3630
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 144 times.
235 if (track->mode != MODE_MOV)
3631 91 return 0; /* ISO/IEC 14496-12 doesn't define any other modes */
3632
3633
1/3
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
144 switch (track->par->alpha_mode) {
3634 144 default: return MOV_GRAPHICS_MODE_COPY;
3635 ✗ case AVALPHA_MODE_STRAIGHT: return MOV_GRAPHICS_MODE_STRAIGHT_ALPHA;
3636 ✗ case AVALPHA_MODE_PREMULTIPLIED: return MOV_GRAPHICS_MODE_PREMUL_BLACK_ALPHA;
3637 }
3638 }
3639
3640 235 static int mov_write_vmhd_tag(AVIOContext *pb, MOVTrack *track)
3641 {
3642 235 avio_wb32(pb, 0x14); /* size (always 0x14) */
3643 235 ffio_wfourcc(pb, "vmhd");
3644 235 avio_wb32(pb, 0x01); /* version & flags */
3645 235 avio_wb16(pb, mov_graphics_mode(track));
3646
2/2
✓ Branch 0 taken 705 times.
✓ Branch 1 taken 235 times.
940 for (int i = 0; i < 3; i++)
3647 705 avio_wb16(pb, 0); /* opcolor */
3648 235 return 0x14;
3649 }
3650
3651 229 static int is_clcp_track(MOVTrack *track)
3652 {
3653
1/2
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
458 return track->tag == MKTAG('c','7','0','8') ||
3654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 track->tag == MKTAG('c','6','0','8');
3655 }
3656
3657 780 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3658 {
3659 780 MOVMuxContext *mov = s->priv_data;
3660 780 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3661 780 int64_t pos = avio_tell(pb);
3662 size_t descr_len;
3663
3664 780 hdlr = "dhlr";
3665 780 hdlr_type = "url ";
3666 780 descr = "DataHandler";
3667
3668
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 192 times.
780 if (track) {
3669
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 396 times.
588 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3670
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 353 times.
588 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 if (track->mode == MODE_AVIF) {
3672 ✗ hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3673 ✗ descr = "PictureHandler";
3674 } else {
3675 235 hdlr_type = "vide";
3676 235 descr = "VideoHandler";
3677 }
3678
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 22 times.
353 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3679 331 hdlr_type = "soun";
3680 331 descr = "SoundHandler";
3681
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3682
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_clcp_track(track)) {
3683 ✗ hdlr_type = "clcp";
3684 ✗ descr = "ClosedCaptionHandler";
3685 } else {
3686
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (track->tag == MKTAG('t','x','3','g')) {
3687 1 hdlr_type = "sbtl";
3688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (track->tag == MKTAG('m','p','4','s')) {
3689 ✗ hdlr_type = "subp";
3690
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3691 2 hdlr_type = "subt";
3692 } else {
3693 3 hdlr_type = "text";
3694 }
3695 6 descr = "SubtitleHandler";
3696 }
3697
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3698 2 hdlr_type = "hint";
3699 2 descr = "HintHandler";
3700
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3701 13 hdlr_type = "tmcd";
3702 13 descr = "TimeCodeHandler";
3703
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3704 1 hdlr_type = "meta";
3705 1 descr = "GoPro MET"; // GoPro Metadata
3706 } else {
3707 ✗ av_log(s, AV_LOG_WARNING,
3708 "Unknown hdlr_type for %s, writing dummy values\n",
3709 ✗ av_fourcc2str(track->par->codec_tag));
3710 }
3711
2/2
✓ Branch 0 taken 585 times.
✓ Branch 1 taken 3 times.
588 if (track->st) {
3712 // hdlr.name is used by some players to identify the content title
3713 // of the track. So if an alternate handler description is
3714 // specified, use it.
3715 AVDictionaryEntry *t;
3716 585 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3717
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 557 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
585 if (t && utf8len(t->value))
3718 28 descr = t->value;
3719 }
3720 }
3721
3722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 780 times.
780 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3723 ✗ descr = "";
3724
3725 780 avio_wb32(pb, 0); /* size */
3726 780 ffio_wfourcc(pb, "hdlr");
3727 780 avio_wb32(pb, 0); /* Version & flags */
3728 780 avio_write(pb, hdlr, 4); /* handler */
3729 780 ffio_wfourcc(pb, hdlr_type); /* handler type */
3730 780 avio_wb32(pb, 0); /* reserved */
3731 780 avio_wb32(pb, 0); /* reserved */
3732 780 avio_wb32(pb, 0); /* reserved */
3733 780 descr_len = strlen(descr);
3734
4/4
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 396 times.
780 if (!track || track->mode == MODE_MOV)
3735 384 avio_w8(pb, descr_len); /* pascal string */
3736 780 avio_write(pb, descr, descr_len); /* handler description */
3737
4/4
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 192 times.
780 if (track && track->mode != MODE_MOV)
3738 396 avio_w8(pb, 0); /* c string */
3739 780 return update_size(pb, pos);
3740 }
3741
3742 ✗ static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3743 {
3744 ✗ int64_t pos = avio_tell(pb);
3745 ✗ avio_wb32(pb, 0); /* size */
3746 ✗ ffio_wfourcc(pb, "pitm");
3747 ✗ avio_wb32(pb, 0); /* Version & flags */
3748 ✗ avio_wb16(pb, item_id); /* item_id */
3749 ✗ return update_size(pb, pos);
3750 }
3751
3752 ✗ static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3753 {
3754 ✗ int64_t pos = avio_tell(pb);
3755 ✗ avio_wb32(pb, 0); /* size */
3756 ✗ ffio_wfourcc(pb, "iloc");
3757 ✗ avio_wb32(pb, 0); /* Version & flags */
3758 ✗ avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3759 ✗ avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3760 ✗ avio_wb16(pb, mov->nb_streams); /* item_count */
3761
3762 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3763 ✗ avio_wb16(pb, i + 1); /* item_id */
3764 ✗ avio_wb16(pb, 0); /* data_reference_index */
3765 ✗ avio_wb16(pb, 1); /* extent_count */
3766 ✗ mov->avif_extent_pos[i] = avio_tell(pb);
3767 ✗ avio_wb32(pb, 0); /* extent_offset (written later) */
3768 // For animated AVIF, we simply write the first packet's size.
3769 ✗ avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3770 }
3771
3772 ✗ return update_size(pb, pos);
3773 }
3774
3775 ✗ static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3776 {
3777 ✗ int64_t iinf_pos = avio_tell(pb);
3778 ✗ avio_wb32(pb, 0); /* size */
3779 ✗ ffio_wfourcc(pb, "iinf");
3780 ✗ avio_wb32(pb, 0); /* Version & flags */
3781 ✗ avio_wb16(pb, mov->nb_streams); /* entry_count */
3782
3783 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3784 ✗ int64_t infe_pos = avio_tell(pb);
3785 ✗ avio_wb32(pb, 0); /* size */
3786 ✗ ffio_wfourcc(pb, "infe");
3787 ✗ avio_w8(pb, 0x2); /* Version */
3788 ✗ avio_wb24(pb, 0); /* flags */
3789 ✗ avio_wb16(pb, i + 1); /* item_id */
3790 ✗ avio_wb16(pb, 0); /* item_protection_index */
3791 ✗ avio_write(pb, "av01", 4); /* item_type */
3792 ✗ avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3793 ✗ update_size(pb, infe_pos);
3794 }
3795
3796 ✗ return update_size(pb, iinf_pos);
3797 }
3798
3799
3800 ✗ static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3801 {
3802 int64_t auxl_pos;
3803 ✗ int64_t iref_pos = avio_tell(pb);
3804 ✗ avio_wb32(pb, 0); /* size */
3805 ✗ ffio_wfourcc(pb, "iref");
3806 ✗ avio_wb32(pb, 0); /* Version & flags */
3807
3808 ✗ auxl_pos = avio_tell(pb);
3809 ✗ avio_wb32(pb, 0); /* size */
3810 ✗ ffio_wfourcc(pb, "auxl");
3811 ✗ avio_wb16(pb, 2); /* from_item_ID */
3812 ✗ avio_wb16(pb, 1); /* reference_count */
3813 ✗ avio_wb16(pb, 1); /* to_item_ID */
3814 ✗ update_size(pb, auxl_pos);
3815
3816 ✗ return update_size(pb, iref_pos);
3817 }
3818
3819 ✗ static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3820 int stream_index)
3821 {
3822 ✗ int64_t pos = avio_tell(pb);
3823 ✗ avio_wb32(pb, 0); /* size */
3824 ✗ ffio_wfourcc(pb, "ispe");
3825 ✗ avio_wb32(pb, 0); /* Version & flags */
3826 ✗ avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3827 ✗ avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3828 ✗ return update_size(pb, pos);
3829 }
3830
3831 ✗ static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3832 int stream_index)
3833 {
3834 ✗ int64_t pos = avio_tell(pb);
3835 const AVPixFmtDescriptor *pixdesc =
3836 ✗ av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3837 ✗ avio_wb32(pb, 0); /* size */
3838 ✗ ffio_wfourcc(pb, "pixi");
3839 ✗ avio_wb32(pb, 0); /* Version & flags */
3840 ✗ avio_w8(pb, pixdesc->nb_components); /* num_channels */
3841 ✗ for (int i = 0; i < pixdesc->nb_components; ++i) {
3842 ✗ avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3843 }
3844 ✗ return update_size(pb, pos);
3845 }
3846
3847 ✗ static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3848 {
3849 ✗ int64_t pos = avio_tell(pb);
3850 ✗ avio_wb32(pb, 0); /* size */
3851 ✗ ffio_wfourcc(pb, "ipco");
3852 ✗ for (int i = 0; i < mov->nb_streams; i++) {
3853 ✗ mov_write_ispe_tag(pb, mov, s, i);
3854 ✗ mov_write_pixi_tag(pb, mov, s, i);
3855 ✗ mov_write_av1c_tag(pb, &mov->tracks[i]);
3856 ✗ if (!i)
3857 ✗ mov_write_colr_tag(pb, &mov->tracks[0], 0);
3858 else
3859 ✗ mov_write_aux_tag(pb, "auxC");
3860 }
3861 ✗ return update_size(pb, pos);
3862 }
3863
3864 ✗ static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3865 {
3866 ✗ int64_t pos = avio_tell(pb);
3867 ✗ avio_wb32(pb, 0); /* size */
3868 ✗ ffio_wfourcc(pb, "ipma");
3869 ✗ avio_wb32(pb, 0); /* Version & flags */
3870 ✗ avio_wb32(pb, mov->nb_streams); /* entry_count */
3871
3872 ✗ for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3873 ✗ avio_wb16(pb, i + 1); /* item_ID */
3874 ✗ avio_w8(pb, 4); /* association_count */
3875
3876 // ispe association.
3877 ✗ avio_w8(pb, index++); /* essential and property_index */
3878 // pixi association.
3879 ✗ avio_w8(pb, index++); /* essential and property_index */
3880 // av1C association.
3881 ✗ avio_w8(pb, 0x80 | index++); /* essential and property_index */
3882 // colr/auxC association.
3883 ✗ avio_w8(pb, index++); /* essential and property_index */
3884 }
3885 ✗ return update_size(pb, pos);
3886 }
3887
3888 ✗ static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3889 {
3890 ✗ int64_t pos = avio_tell(pb);
3891 ✗ avio_wb32(pb, 0); /* size */
3892 ✗ ffio_wfourcc(pb, "iprp");
3893 ✗ mov_write_ipco_tag(pb, mov, s);
3894 ✗ mov_write_ipma_tag(pb, mov, s);
3895 ✗ return update_size(pb, pos);
3896 }
3897
3898 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3899 {
3900 /* This atom must be present, but leaving the values at zero
3901 * seems harmless. */
3902 2 avio_wb32(pb, 28); /* size */
3903 2 ffio_wfourcc(pb, "hmhd");
3904 2 avio_wb32(pb, 0); /* version, flags */
3905 2 avio_wb16(pb, 0); /* maxPDUsize */
3906 2 avio_wb16(pb, 0); /* avgPDUsize */
3907 2 avio_wb32(pb, 0); /* maxbitrate */
3908 2 avio_wb32(pb, 0); /* avgbitrate */
3909 2 avio_wb32(pb, 0); /* reserved */
3910 2 return 28;
3911 }
3912
3913 588 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3914 {
3915 588 int64_t pos = avio_tell(pb);
3916 int ret;
3917
3918 588 avio_wb32(pb, 0); /* size */
3919 588 ffio_wfourcc(pb, "minf");
3920
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 353 times.
588 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3921 235 mov_write_vmhd_tag(pb, track);
3922
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 22 times.
353 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3923 331 mov_write_smhd_tag(pb);
3924
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3925
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
6 if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
3926 1 mov_write_gmhd_tag(pb, track);
3927
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } else if (track->tag == MOV_MP4_TTML_TAG) {
3928 2 mov_write_sthd_tag(pb);
3929 } else {
3930 3 mov_write_nmhd_tag(pb);
3931 }
3932
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3933 2 mov_write_hmhd_tag(pb);
3934
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3935
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3936 4 mov_write_nmhd_tag(pb);
3937 else
3938 9 mov_write_gmhd_tag(pb, track);
3939
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3940 1 mov_write_gmhd_tag(pb, track);
3941 }
3942
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 396 times.
588 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3943 192 mov_write_hdlr_tag(s, pb, NULL);
3944 588 mov_write_dinf_tag(pb);
3945
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 588 times.
588 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3946 ✗ return ret;
3947 588 return update_size(pb, pos);
3948 }
3949
3950 2288 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3951 int64_t *start, int64_t *end, int elst, int mdhd)
3952 {
3953
5/6
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2238 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
2288 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd && track->nb_src_track) {
3954 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3955 // another track's duration, while the end_pts may be left at zero.
3956 // Calculate the pts duration for that track instead.
3957 38 get_pts_range(mov, &mov->tracks[*track->src_track], start, end, elst, mdhd);
3958 38 *start = av_rescale(*start, track->timescale,
3959 38 mov->tracks[*track->src_track].timescale);
3960 38 *end = av_rescale(*end, track->timescale,
3961 38 mov->tracks[*track->src_track].timescale);
3962 38 return;
3963 }
3964
4/4
✓ Branch 0 taken 1662 times.
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 1620 times.
✓ Branch 3 taken 42 times.
2250 if (!mdhd && track->end_pts != AV_NOPTS_VALUE &&
3965
1/2
✓ Branch 0 taken 1620 times.
✗ Branch 1 not taken.
1620 track->start_dts != AV_NOPTS_VALUE &&
3966
1/2
✓ Branch 0 taken 1620 times.
✗ Branch 1 not taken.
1620 track->start_cts != AV_NOPTS_VALUE) {
3967 1620 *start = track->start_dts + track->start_cts;
3968
2/2
✓ Branch 0 taken 524 times.
✓ Branch 1 taken 1096 times.
1620 *end = elst ? track->elst_end_pts : track->end_pts;
3969 1620 return;
3970 }
3971 630 *start = 0;
3972 630 *end = track->track_duration;
3973 }
3974
3975 588 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3976 {
3977 int64_t start, end;
3978 588 get_pts_range(mov, track, &start, &end, 0, 1);
3979 588 return end - start;
3980 }
3981
3982 // Calculate the actual duration of the track, after edits.
3983 // If it starts with a pts < 0, that is removed by the edit list.
3984 // If it starts with a pts > 0, the edit list adds a delay before that.
3985 // Thus, with edit lists enabled, the post-edit output of the file is
3986 // starting with pts=0.
3987 1138 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3988 {
3989 int64_t start, end;
3990 1138 get_pts_range(mov, track, &start, &end, 0, 0);
3991
2/2
✓ Branch 0 taken 1054 times.
✓ Branch 1 taken 84 times.
1138 if (mov->use_editlist != 0)
3992 1054 start = 0;
3993 1138 return end - start;
3994 }
3995
3996 524 static int64_t calc_elst_duration(MOVMuxContext *mov, MOVTrack *track)
3997 {
3998 int64_t start, end;
3999 524 get_pts_range(mov, track, &start, &end, 1, 0);
4000 524 return end - start;
4001 }
4002
4003 1463 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
4004 {
4005
4/4
✓ Branch 0 taken 1176 times.
✓ Branch 1 taken 287 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 1158 times.
1463 if (track && track->mode == MODE_ISM)
4006 18 return 1;
4007
2/2
✓ Branch 0 taken 1437 times.
✓ Branch 1 taken 8 times.
1445 if (duration < INT32_MAX)
4008 1437 return 0;
4009 8 return 1;
4010 }
4011
4012 588 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4013 MOVTrack *track)
4014 {
4015 588 int64_t duration = calc_samples_pts_duration(mov, track);
4016 588 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4017
4018
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 575 times.
588 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
4019 588 ffio_wfourcc(pb, "mdhd");
4020 588 avio_w8(pb, version);
4021 588 avio_wb24(pb, 0); /* flags */
4022
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 575 times.
588 if (version == 1) {
4023 13 avio_wb64(pb, track->time);
4024 13 avio_wb64(pb, track->time);
4025 } else {
4026 575 avio_wb32(pb, track->time); /* creation time */
4027 575 avio_wb32(pb, track->time); /* modification time */
4028 }
4029 588 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
4030
4/4
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 299 times.
588 if (!track->entry && mov->mode == MODE_ISM)
4031
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4032
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 280 times.
579 else if (!track->entry)
4033
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 295 times.
299 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4034 else
4035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
4036 588 avio_wb16(pb, track->language); /* language */
4037 588 avio_wb16(pb, 0); /* reserved (quality) */
4038
4039
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 575 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
588 if (version != 0 && track->mode == MODE_MOV) {
4040 ✗ av_log(NULL, AV_LOG_ERROR,
4041 "FATAL error, file duration too long for timebase, this file will not be\n"
4042 "playable with QuickTime. Choose a different timebase with "
4043 "-video_track_timescale or a different container format\n");
4044 }
4045
4046 588 return 32;
4047 }
4048
4049 588 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
4050 MOVMuxContext *mov, MOVTrack *track)
4051 {
4052 588 int64_t pos = avio_tell(pb);
4053 int ret;
4054
4055 588 avio_wb32(pb, 0); /* size */
4056 588 ffio_wfourcc(pb, "mdia");
4057 588 mov_write_mdhd_tag(pb, mov, track);
4058 588 mov_write_hdlr_tag(s, pb, track);
4059
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 588 times.
588 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
4060 ✗ return ret;
4061 588 return update_size(pb, pos);
4062 }
4063
4064 /* transformation matrix
4065 |a b u|
4066 |c d v|
4067 |tx ty w| */
4068 874 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
4069 int16_t d, int16_t tx, int16_t ty)
4070 {
4071 874 avio_wb32(pb, a << 16); /* 16.16 format */
4072 874 avio_wb32(pb, b << 16); /* 16.16 format */
4073 874 avio_wb32(pb, 0); /* u in 2.30 format */
4074 874 avio_wb32(pb, c << 16); /* 16.16 format */
4075 874 avio_wb32(pb, d << 16); /* 16.16 format */
4076 874 avio_wb32(pb, 0); /* v in 2.30 format */
4077 874 avio_wb32(pb, tx << 16); /* 16.16 format */
4078 874 avio_wb32(pb, ty << 16); /* 16.16 format */
4079 874 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
4080 874 }
4081
4082 588 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4083 MOVTrack *track, AVStream *st)
4084 {
4085 1176 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
4086 588 mov->movie_timescale, track->timescale,
4087 AV_ROUND_UP);
4088 int version;
4089 588 int flags = MOV_TKHD_FLAG_IN_MOVIE;
4090 588 int group = 0;
4091
4092 588 uint32_t *display_matrix = NULL;
4093 int i;
4094
4095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (mov->mode == MODE_AVIF)
4096 ✗ if (!mov->avif_loop_count)
4097 ✗ duration = INT64_MAX;
4098 else
4099 ✗ duration *= mov->avif_loop_count;
4100
4101
2/2
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 13 times.
588 if (st) {
4102 const AVPacketSideData *sd;
4103
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 573 times.
575 if (mov->per_stream_grouping)
4104 2 group = st->index;
4105 else
4106 573 group = st->codecpar->codec_type;
4107
4108 575 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4109 575 st->codecpar->nb_coded_side_data,
4110 AV_PKT_DATA_DISPLAYMATRIX);
4111
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 574 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
575 if (sd && sd->size == 9 * sizeof(*display_matrix))
4112 1 display_matrix = (uint32_t *)sd->data;
4113 }
4114
4115
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 224 times.
588 if (track->flags & MOV_TRACK_ENABLED)
4116 364 flags |= MOV_TKHD_FLAG_ENABLED;
4117
4118 588 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
4119
4120
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 575 times.
588 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
4121 588 ffio_wfourcc(pb, "tkhd");
4122 588 avio_w8(pb, version);
4123 588 avio_wb24(pb, flags);
4124
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 575 times.
588 if (version == 1) {
4125 13 avio_wb64(pb, track->time);
4126 13 avio_wb64(pb, track->time);
4127 } else {
4128 575 avio_wb32(pb, track->time); /* creation time */
4129 575 avio_wb32(pb, track->time); /* modification time */
4130 }
4131 588 avio_wb32(pb, track->track_id); /* track-id */
4132 588 avio_wb32(pb, 0); /* reserved */
4133
4/4
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 299 times.
588 if (!track->entry && mov->mode == MODE_ISM)
4134
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
4135
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 280 times.
579 else if (!track->entry)
4136
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 295 times.
299 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
4137 else
4138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
280 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
4139
4140 588 avio_wb32(pb, 0); /* reserved */
4141 588 avio_wb32(pb, 0); /* reserved */
4142 588 avio_wb16(pb, 0); /* layer */
4143 588 avio_wb16(pb, group); /* alternate group) */
4144 /* Volume, only for audio */
4145
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 257 times.
588 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
4146 331 avio_wb16(pb, 0x0100);
4147 else
4148 257 avio_wb16(pb, 0);
4149 588 avio_wb16(pb, 0); /* reserved */
4150
4151 /* Matrix structure */
4152
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 587 times.
588 if (display_matrix) {
4153
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
4154 9 avio_wb32(pb, display_matrix[i]);
4155 } else {
4156 587 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4157 }
4158 /* Track width and height, for visual only */
4159
4/4
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 340 times.
✓ Branch 3 taken 235 times.
588 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
4160
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 335 times.
580 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
4161 int64_t track_width_1616;
4162
3/4
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 96 times.
240 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
4163 144 track_width_1616 = track->par->width * 0x10000ULL;
4164 } else {
4165 96 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
4166 96 track->par->width * 0x10000LL,
4167 96 st->sample_aspect_ratio.den);
4168
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 75 times.
96 if (!track_width_1616 ||
4169
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
21 track->height != track->par->height ||
4170 track_width_1616 > UINT32_MAX)
4171 75 track_width_1616 = track->par->width * 0x10000ULL;
4172 }
4173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (track_width_1616 > UINT32_MAX) {
4174 ✗ av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
4175 ✗ track_width_1616 = 0;
4176 }
4177 240 avio_wb32(pb, track_width_1616);
4178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (track->height > 0xFFFF) {
4179 ✗ av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
4180 ✗ avio_wb32(pb, 0);
4181 } else
4182 240 avio_wb32(pb, track->height * 0x10000U);
4183 } else {
4184 348 avio_wb32(pb, 0);
4185 348 avio_wb32(pb, 0);
4186 }
4187 588 return 0x5c;
4188 }
4189
4190 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
4191 {
4192 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
4193 1 track->par->sample_aspect_ratio.den);
4194
4195 1 int64_t pos = avio_tell(pb);
4196
4197 1 avio_wb32(pb, 0); /* size */
4198 1 ffio_wfourcc(pb, "tapt");
4199
4200 1 avio_wb32(pb, 20);
4201 1 ffio_wfourcc(pb, "clef");
4202 1 avio_wb32(pb, 0);
4203 1 avio_wb32(pb, width << 16);
4204 1 avio_wb32(pb, track->par->height << 16);
4205
4206 1 avio_wb32(pb, 20);
4207 1 ffio_wfourcc(pb, "prof");
4208 1 avio_wb32(pb, 0);
4209 1 avio_wb32(pb, width << 16);
4210 1 avio_wb32(pb, track->par->height << 16);
4211
4212 1 avio_wb32(pb, 20);
4213 1 ffio_wfourcc(pb, "enof");
4214 1 avio_wb32(pb, 0);
4215 1 avio_wb32(pb, track->par->width << 16);
4216 1 avio_wb32(pb, track->par->height << 16);
4217
4218 1 return update_size(pb, pos);
4219 }
4220
4221 // This box is written in the following cases:
4222 // * Seems important for the psp playback. Without it the movie seems to hang.
4223 // * Used for specifying the looping behavior of animated AVIF (as specified
4224 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
4225 524 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
4226 MOVTrack *track)
4227 {
4228 1048 int64_t duration = av_rescale_rnd(calc_elst_duration(mov, track),
4229 524 mov->movie_timescale, track->timescale,
4230 AV_ROUND_UP);
4231 524 int version = duration < INT32_MAX ? 0 : 1;
4232 int entry_size, entry_count, size;
4233 524 int64_t delay, start_ct = track->start_cts;
4234 524 int64_t start_dts = track->start_dts;
4235 524 int flags = 0;
4236
4237
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 260 times.
524 if (track->entry) {
4238
4/6
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 261 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
264 if (start_dts != track->cluster[0].dts || (start_ct != track->cluster[0].cts && track->cluster[0].dts >= 0)) {
4239
4240 ✗ av_log(mov->fc, AV_LOG_DEBUG,
4241 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
4242 ✗ track->cluster[0].dts, track->cluster[0].cts,
4243 start_dts, start_ct, track->track_id);
4244 ✗ start_dts = track->cluster[0].dts;
4245 ✗ start_ct = track->cluster[0].cts;
4246 }
4247 }
4248
4249 524 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
4250 524 track->timescale, AV_ROUND_DOWN);
4251
4252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524 times.
524 if (mov->mode == MODE_AVIF) {
4253 ✗ delay = 0;
4254 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
4255 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
4256 // list is not repeated, while (flags & 1) equal to 1 specifies that the
4257 // edit list is repeated.
4258 ✗ flags = mov->avif_loop_count != 1;
4259 ✗ start_ct = 0;
4260 }
4261
4262 524 version |= delay < INT32_MAX ? 0 : 1;
4263
4264
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 520 times.
524 entry_size = (version == 1) ? 20 : 12;
4265
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 520 times.
524 entry_count = 1 + (delay > 0);
4266 524 size = 24 + entry_count * entry_size;
4267
4268 /* write the atom data */
4269 524 avio_wb32(pb, size);
4270 524 ffio_wfourcc(pb, "edts");
4271 524 avio_wb32(pb, size - 8);
4272 524 ffio_wfourcc(pb, "elst");
4273 524 avio_w8(pb, version);
4274 524 avio_wb24(pb, flags); /* flags */
4275
4276 524 avio_wb32(pb, entry_count);
4277
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 520 times.
524 if (delay > 0) { /* add an empty edit to delay presentation */
4278 /* In the positive delay case, the delay includes the cts
4279 * offset, and the second edit list entry below trims out
4280 * the same amount from the actual content. This makes sure
4281 * that the offset last sample is included in the edit
4282 * list duration as well. */
4283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (version == 1) {
4284 ✗ avio_wb64(pb, delay);
4285 ✗ avio_wb64(pb, -1);
4286 } else {
4287 4 avio_wb32(pb, delay);
4288 4 avio_wb32(pb, -1);
4289 }
4290 4 avio_wb32(pb, 0x00010000);
4291
1/2
✓ Branch 0 taken 520 times.
✗ Branch 1 not taken.
520 } else if (mov->mode != MODE_AVIF) {
4292 /* Avoid accidentally ending up with start_ct = -1 which has got a
4293 * special meaning. Normally start_ct should end up positive or zero
4294 * here, but use FFMIN in case dts is a small positive integer
4295 * rounded to 0 when represented in movie timescale units. */
4296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 520 times.
520 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4297 520 start_ct = -FFMIN(start_dts, 0);
4298
4299 #if CONFIG_IAMFENC
4300
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 515 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
520 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4301 ✗ start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4302 #endif
4303 /* Note, this delay is calculated from the pts of the first sample,
4304 * ensuring that we don't reduce the duration for cases with
4305 * dts<0 pts=0. */
4306 520 duration += delay;
4307 }
4308
4309 /* For fragmented files, we don't know the full length yet. Setting
4310 * duration to 0 allows us to only specify the offset, including
4311 * the rest of the content (from all future fragments) without specifying
4312 * an explicit duration.
4313 *
4314 * For hybrid_fragmented during mov_write_trailer (mov->moov_written != 0),
4315 * don't reset duration to zero.
4316 */
4317
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 260 times.
524 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
4318
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
264 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
4319 264 duration = 0;
4320
4321 /* duration */
4322
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 520 times.
524 if (version == 1) {
4323 4 avio_wb64(pb, duration);
4324 4 avio_wb64(pb, start_ct);
4325 } else {
4326 520 avio_wb32(pb, duration);
4327 520 avio_wb32(pb, start_ct);
4328 }
4329 524 avio_wb32(pb, 0x00010000);
4330 524 return size;
4331 }
4332
4333 15 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4334 {
4335 15 int64_t pos = avio_tell(pb);
4336 15 avio_wb32(pb, 0); // size placeholder
4337 15 ffio_wfourcc(pb, "tref");
4338
4339
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 for (int i = 0; i < track->nb_tref_tags; i++) {
4340 15 MovTag *tag = &track->tref_tags[i];
4341 15 avio_wb32(pb, 8 + tag->nb_id * sizeof(*tag->id)); // size (subatom)
4342 15 avio_wl32(pb, tag->name);
4343
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 15 times.
32 for (int j = 0; j < tag->nb_id; j++)
4344 17 avio_wb32(pb, tag->id[j]);
4345 }
4346 15 return update_size(pb, pos);
4347 }
4348
4349 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4350 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4351 {
4352 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4353 2 ffio_wfourcc(pb, "uuid");
4354 2 ffio_wfourcc(pb, "USMT");
4355 2 avio_wb32(pb, 0x21d24fce);
4356 2 avio_wb32(pb, 0xbb88695c);
4357 2 avio_wb32(pb, 0xfac9c740);
4358 2 avio_wb32(pb, 0x1c); // another size here!
4359 2 ffio_wfourcc(pb, "MTDT");
4360 2 avio_wb32(pb, 0x00010012);
4361 2 avio_wb32(pb, 0x0a);
4362 2 avio_wb32(pb, 0x55c40000);
4363 2 avio_wb32(pb, 0x1);
4364 2 avio_wb32(pb, 0x0);
4365 2 return 0x34;
4366 }
4367
4368 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4369 {
4370 2 AVFormatContext *ctx = track->rtp_ctx;
4371 2 char buf[1000] = "";
4372 int len;
4373
4374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
4375 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], *track->src_track,
4376 NULL, NULL, 0, 0, ctx);
4377 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4378 2 len = strlen(buf);
4379
4380 2 avio_wb32(pb, len + 24);
4381 2 ffio_wfourcc(pb, "udta");
4382 2 avio_wb32(pb, len + 16);
4383 2 ffio_wfourcc(pb, "hnti");
4384 2 avio_wb32(pb, len + 8);
4385 2 ffio_wfourcc(pb, "sdp ");
4386 2 avio_write(pb, buf, len);
4387 2 return len + 24;
4388 }
4389
4390 565 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4391 const char *tag, const char *str)
4392 {
4393 565 int64_t pos = avio_tell(pb);
4394 565 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4395
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 564 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
565 if (!t || !utf8len(t->value))
4396 564 return 0;
4397
4398 1 avio_wb32(pb, 0); /* size */
4399 1 ffio_wfourcc(pb, tag); /* type */
4400 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4401 1 return update_size(pb, pos);
4402 }
4403
4404 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4405 const char *value)
4406 {
4407 2 int64_t pos = avio_tell(pb);
4408
4409 /* Box|FullBox basics */
4410 2 avio_wb32(pb, 0); /* size placeholder */
4411 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4412 2 avio_w8(pb, 0); /* version = 0 */
4413 2 avio_wb24(pb, 0); /* flags = 0 */
4414
4415 /* Required null-terminated scheme URI */
4416 2 avio_write(pb, (const unsigned char *)scheme_uri,
4417 2 strlen(scheme_uri));
4418 2 avio_w8(pb, 0);
4419
4420 /* Optional value string */
4421
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (value && value[0])
4422 2 avio_write(pb, (const unsigned char *)value,
4423 2 strlen(value));
4424
4425 2 avio_w8(pb, 0);
4426
4427 2 return update_size(pb, pos);
4428 }
4429
4430 379 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4431 {
4432 379 int ret = AVERROR_BUG;
4433
4434
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 379 times.
758 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4435 379 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4436
4437
2/2
✓ Branch 0 taken 1895 times.
✓ Branch 1 taken 379 times.
2274 for (int j = 0; map.value_maps[j].disposition; j++) {
4438 1895 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4439
2/2
✓ Branch 0 taken 1893 times.
✓ Branch 1 taken 2 times.
1895 if (!(st->disposition & value_map.disposition))
4440 1893 continue;
4441
4442
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_track_kind(pb, map.scheme_uri, value_map.value)) < 0)
4443 ✗ return ret;
4444 }
4445 }
4446
4447 379 return 0;
4448 }
4449
4450 588 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4451 AVStream *st)
4452 {
4453 AVIOContext *pb_buf;
4454 int ret, size;
4455 uint8_t *buf;
4456
4457
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 575 times.
588 if (!st)
4458 13 return 0;
4459
4460 575 ret = avio_open_dyn_buf(&pb_buf);
4461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 575 times.
575 if (ret < 0)
4462 ✗ return ret;
4463
4464
2/2
✓ Branch 0 taken 565 times.
✓ Branch 1 taken 10 times.
575 if (mov->mode & (MODE_MP4|MODE_MOV))
4465 565 mov_write_track_metadata(pb_buf, st, "name", "title");
4466
4467
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 196 times.
575 if (mov->mode & MODE_MP4) {
4468
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 379 times.
379 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4469 ✗ goto end;
4470 }
4471
4472
2/2
✓ Branch 1 taken 572 times.
✓ Branch 2 taken 3 times.
575 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4473 3 avio_wb32(pb, size + 8);
4474 3 ffio_wfourcc(pb, "udta");
4475 3 avio_write(pb, buf, size);
4476 }
4477 572 end:
4478 575 ffio_free_dyn_buf(&pb_buf);
4479
4480 575 return ret;
4481 }
4482
4483 588 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4484 MOVTrack *track, AVStream *st)
4485 {
4486 588 int64_t pos = avio_tell(pb);
4487 588 int entry_backup = track->entry;
4488 588 int chunk_backup = track->chunkCount;
4489 int ret;
4490
4491 /* If we want to have an empty moov, but some samples already have been
4492 * buffered (delay_moov), pretend that no samples have been written yet. */
4493
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 284 times.
588 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4494 304 track->chunkCount = track->entry = 0;
4495
4496 588 avio_wb32(pb, 0); /* size */
4497 588 ffio_wfourcc(pb, "trak");
4498 588 mov_write_tkhd_tag(pb, mov, track, st);
4499
4500 av_assert2(mov->use_editlist >= 0);
4501
4502
2/2
✓ Branch 0 taken 550 times.
✓ Branch 1 taken 38 times.
588 if (track->start_dts != AV_NOPTS_VALUE) {
4503
2/2
✓ Branch 0 taken 524 times.
✓ Branch 1 taken 26 times.
550 if (mov->use_editlist)
4504 524 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4505
5/8
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 26 times.
26 else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
4506 ✗ av_log(mov->fc, AV_LOG_WARNING,
4507 "Not writing any edit list even though one would have been required\n");
4508 }
4509
4510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (mov->is_animated_avif)
4511 ✗ mov_write_edts_tag(pb, mov, track);
4512
4513
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 573 times.
588 if (track->nb_tref_tags)
4514 15 mov_write_tref_tag(pb, track);
4515
4516
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 588 times.
588 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4517 ✗ return ret;
4518
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 586 times.
588 if (track->mode == MODE_PSP)
4519 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4520
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 586 times.
588 if (track->tag == MKTAG('r','t','p',' '))
4521 2 mov_write_udta_sdp(pb, track);
4522
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 396 times.
588 if (track->mode == MODE_MOV) {
4523
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 48 times.
192 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4524 144 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4525
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
144 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4526 1 mov_write_tapt_tag(pb, track);
4527 }
4528 }
4529
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
192 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4530 ✗ mov_write_tapt_tag(pb, track);
4531 }
4532 }
4533 588 mov_write_track_udta_tag(pb, mov, st);
4534 588 track->entry = entry_backup;
4535 588 track->chunkCount = chunk_backup;
4536 588 return update_size(pb, pos);
4537 }
4538
4539 ✗ static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4540 {
4541 ✗ int i, has_audio = 0, has_video = 0;
4542 ✗ int64_t pos = avio_tell(pb);
4543 ✗ int audio_profile = mov->iods_audio_profile;
4544 ✗ int video_profile = mov->iods_video_profile;
4545 ✗ for (i = 0; i < mov->nb_tracks; i++) {
4546 ✗ if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4547 ✗ has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4548 ✗ has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4549 }
4550 }
4551 ✗ if (audio_profile < 0)
4552 ✗ audio_profile = 0xFF - has_audio;
4553 ✗ if (video_profile < 0)
4554 ✗ video_profile = 0xFF - has_video;
4555 ✗ avio_wb32(pb, 0x0); /* size */
4556 ✗ ffio_wfourcc(pb, "iods");
4557 ✗ avio_wb32(pb, 0); /* version & flags */
4558 ✗ put_descr(pb, 0x10, 7);
4559 ✗ avio_wb16(pb, 0x004f);
4560 ✗ avio_w8(pb, 0xff);
4561 ✗ avio_w8(pb, 0xff);
4562 ✗ avio_w8(pb, audio_profile);
4563 ✗ avio_w8(pb, video_profile);
4564 ✗ avio_w8(pb, 0xff);
4565 ✗ return update_size(pb, pos);
4566 }
4567
4568 324 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4569 {
4570 324 avio_wb32(pb, 0x20); /* size */
4571 324 ffio_wfourcc(pb, "trex");
4572 324 avio_wb32(pb, 0); /* version & flags */
4573 324 avio_wb32(pb, track->track_id); /* track ID */
4574 324 avio_wb32(pb, 1); /* default sample description index */
4575 324 avio_wb32(pb, 0); /* default sample duration */
4576 324 avio_wb32(pb, 0); /* default sample size */
4577 324 avio_wb32(pb, 0); /* default sample flags */
4578 324 return 0;
4579 }
4580
4581 70 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4582 {
4583 70 int64_t pos = avio_tell(pb);
4584 int i;
4585 70 avio_wb32(pb, 0x0); /* size */
4586 70 ffio_wfourcc(pb, "mvex");
4587
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 70 times.
394 for (i = 0; i < mov->nb_tracks; i++)
4588 324 mov_write_trex_tag(pb, &mov->tracks[i]);
4589 70 return update_size(pb, pos);
4590 }
4591
4592 287 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4593 {
4594 287 int max_track_id = 1, i;
4595 287 int64_t max_track_len = 0;
4596 int version;
4597 int timescale;
4598
4599
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 287 times.
877 for (i = 0; i < mov->nb_tracks; i++) {
4600
3/4
✓ Branch 0 taken 550 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 550 times.
✗ Branch 3 not taken.
590 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4601 1100 int64_t max_track_len_temp = av_rescale_rnd(
4602 550 calc_pts_duration(mov, &mov->tracks[i]),
4603 550 mov->movie_timescale,
4604 550 mov->tracks[i].timescale,
4605 AV_ROUND_UP);
4606
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 269 times.
550 if (max_track_len < max_track_len_temp)
4607 281 max_track_len = max_track_len_temp;
4608
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 267 times.
550 if (max_track_id < mov->tracks[i].track_id)
4609 283 max_track_id = mov->tracks[i].track_id;
4610 }
4611 }
4612 /* If using delay_moov, make sure the output is the same as if no
4613 * samples had been written yet. */
4614
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 227 times.
287 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4615 60 max_track_len = 0;
4616 60 max_track_id = 1;
4617 }
4618
4619 287 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4621
4622 287 ffio_wfourcc(pb, "mvhd");
4623 287 avio_w8(pb, version);
4624 287 avio_wb24(pb, 0); /* flags */
4625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (version == 1) {
4626 ✗ avio_wb64(pb, mov->time);
4627 ✗ avio_wb64(pb, mov->time);
4628 } else {
4629 287 avio_wb32(pb, mov->time); /* creation time */
4630 287 avio_wb32(pb, mov->time); /* modification time */
4631 }
4632
4633 287 timescale = mov->movie_timescale;
4634
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
287 if (mov->mode == MODE_AVIF && !timescale)
4635 ✗ timescale = mov->tracks[0].timescale;
4636
4637 287 avio_wb32(pb, timescale);
4638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4639
4640 287 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4641 287 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4642 287 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4643
4644 /* Matrix structure */
4645 287 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4646
4647 287 avio_wb32(pb, 0); /* reserved (preview time) */
4648 287 avio_wb32(pb, 0); /* reserved (preview duration) */
4649 287 avio_wb32(pb, 0); /* reserved (poster time) */
4650 287 avio_wb32(pb, 0); /* reserved (selection time) */
4651 287 avio_wb32(pb, 0); /* reserved (selection duration) */
4652 287 avio_wb32(pb, 0); /* reserved (current time) */
4653 287 avio_wb32(pb, max_track_id + 1); /* Next track id */
4654 287 return 0x6c;
4655 }
4656
4657 127 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4658 AVFormatContext *s)
4659 {
4660 127 avio_wb32(pb, 33); /* size */
4661 127 ffio_wfourcc(pb, "hdlr");
4662 127 avio_wb32(pb, 0);
4663 127 avio_wb32(pb, 0);
4664 127 ffio_wfourcc(pb, "mdir");
4665 127 ffio_wfourcc(pb, "appl");
4666 127 avio_wb32(pb, 0);
4667 127 avio_wb32(pb, 0);
4668 127 avio_w8(pb, 0);
4669 127 return 33;
4670 }
4671
4672 /* helper function to write a data tag with the specified string as data */
4673 76 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4674 {
4675 76 size_t data_len = strlen(data);
4676
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 34 times.
76 if (long_style) {
4677 42 int size = 16 + data_len;
4678 42 avio_wb32(pb, size); /* size */
4679 42 ffio_wfourcc(pb, "data");
4680 42 avio_wb32(pb, 1);
4681 42 avio_wb32(pb, 0);
4682 42 avio_write(pb, data, data_len);
4683 42 return size;
4684 } else {
4685 34 avio_wb16(pb, data_len); /* string length */
4686
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4687 26 lang = ff_mov_iso639_to_lang("und", 1);
4688 34 avio_wb16(pb, lang);
4689 34 avio_write(pb, data, data_len);
4690 34 return data_len + 4;
4691 }
4692 }
4693
4694 75 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4695 const char *value, int lang, int long_style)
4696 {
4697 75 int size = 0;
4698
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
75 if (value && value[0]) {
4699 75 int64_t pos = avio_tell(pb);
4700 75 avio_wb32(pb, 0); /* size */
4701 75 ffio_wfourcc(pb, name);
4702 75 mov_write_string_data_tag(pb, value, lang, long_style);
4703 75 size = update_size(pb, pos);
4704 }
4705 75 return size;
4706 }
4707
4708 1 static int mov_write_freeform_tag(AVIOContext *pb, const char *mean,
4709 const char *name, const char *data)
4710 {
4711
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!data || !data[0])
4712 ✗ return 0;
4713
4714 static const char stub_flags[4] = {0, 0, 0, 0};
4715
4716 1 int64_t entry_pos = avio_tell(pb);
4717 1 avio_wb32(pb, 0); /* size */
4718 1 ffio_wfourcc(pb, "----"); /* freeform */
4719
4720 1 size_t mean_len = strlen(mean);
4721 1 avio_wb32(pb, 12 + mean_len);
4722 1 ffio_wfourcc(pb, "mean");
4723 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4724 1 avio_write(pb, mean, mean_len);
4725
4726 1 size_t name_len = strlen(name);
4727 1 avio_wb32(pb, 12 + name_len);
4728 1 ffio_wfourcc(pb, "name");
4729 1 avio_write(pb, &stub_flags[0], sizeof(stub_flags));
4730 1 avio_write(pb, name, name_len);
4731
4732 1 mov_write_string_data_tag(pb, data, 0, 1);
4733
4734 1 return update_size(pb, entry_pos);
4735 }
4736
4737 4639 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4738 const char *tag, int *lang)
4739 {
4740 int l, len, len2;
4741 4639 AVDictionaryEntry *t, *t2 = NULL;
4742 char tag2[16];
4743
4744 4639 *lang = 0;
4745
4746
2/2
✓ Branch 1 taken 4575 times.
✓ Branch 2 taken 64 times.
4639 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4747 4575 return NULL;
4748
4749 64 len = strlen(t->key);
4750 64 snprintf(tag2, sizeof(tag2), "%s-", tag);
4751
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 56 times.
64 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4752 8 len2 = strlen(t2->key);
4753
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (len2 == len + 4 && !strcmp(t->value, t2->value)
4754
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4755 8 *lang = l;
4756 8 return t;
4757 }
4758 }
4759 56 return t;
4760 }
4761
4762 4512 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4763 const char *name, const char *tag,
4764 int long_style)
4765 {
4766 int lang;
4767 4512 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4768
2/2
✓ Branch 0 taken 4448 times.
✓ Branch 1 taken 64 times.
4512 if (!t)
4769 4448 return 0;
4770 64 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4771 }
4772
4773 127 static int mov_write_custom_metadata(AVFormatContext *s, AVIOContext *pb,
4774 const char *mean, const char *name,
4775 const char *tag)
4776 {
4777 127 AVDictionaryEntry *t = av_dict_get(s->metadata, tag, NULL, 0);
4778
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 1 times.
127 if (!t)
4779 126 return 0;
4780 1 return mov_write_freeform_tag(pb, mean, name, t->value);
4781 }
4782
4783 /* iTunes bpm number */
4784 127 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4785 {
4786 127 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 127 times.
127 int size = 0, tmpo = t ? atoi(t->value) : 0;
4788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 127 times.
127 if (tmpo) {
4789 ✗ size = 26;
4790 ✗ avio_wb32(pb, size);
4791 ✗ ffio_wfourcc(pb, "tmpo");
4792 ✗ avio_wb32(pb, size-8); /* size */
4793 ✗ ffio_wfourcc(pb, "data");
4794 ✗ avio_wb32(pb, 0x15); //type specifier
4795 ✗ avio_wb32(pb, 0);
4796 ✗ avio_wb16(pb, tmpo); // data
4797 }
4798 127 return size;
4799 }
4800
4801 /* 3GPP TS 26.244 */
4802 127 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4803 {
4804 int lang;
4805 127 int64_t pos = avio_tell(pb);
4806 double latitude, longitude, altitude;
4807 int32_t latitude_fix, longitude_fix, altitude_fix;
4808 127 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4809 127 const char *ptr, *place = "";
4810 char *end;
4811 static const char *astronomical_body = "earth";
4812
1/2
✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
127 if (!t)
4813 127 return 0;
4814
4815 ✗ ptr = t->value;
4816 ✗ latitude = strtod(ptr, &end);
4817 ✗ if (end == ptr) {
4818 ✗ av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4819 ✗ return 0;
4820 }
4821 ✗ ptr = end;
4822 ✗ longitude = strtod(ptr, &end);
4823 ✗ if (end == ptr) {
4824 ✗ av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4825 ✗ return 0;
4826 }
4827 ✗ ptr = end;
4828 ✗ altitude = strtod(ptr, &end);
4829 /* If no altitude was present, the default 0 should be fine */
4830 ✗ if (*end == '/')
4831 ✗ place = end + 1;
4832
4833 ✗ latitude_fix = (int32_t) ((1 << 16) * latitude);
4834 ✗ longitude_fix = (int32_t) ((1 << 16) * longitude);
4835 ✗ altitude_fix = (int32_t) ((1 << 16) * altitude);
4836
4837 ✗ avio_wb32(pb, 0); /* size */
4838 ✗ ffio_wfourcc(pb, "loci"); /* type */
4839 ✗ avio_wb32(pb, 0); /* version + flags */
4840 ✗ avio_wb16(pb, lang);
4841 ✗ avio_write(pb, place, strlen(place) + 1);
4842 ✗ avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4843 ✗ avio_wb32(pb, longitude_fix);
4844 ✗ avio_wb32(pb, latitude_fix);
4845 ✗ avio_wb32(pb, altitude_fix);
4846 ✗ avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4847 ✗ avio_w8(pb, 0); /* additional notes, null terminated string */
4848
4849 ✗ return update_size(pb, pos);
4850 }
4851
4852 /* iTunes track or disc number */
4853 254 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4854 AVFormatContext *s, int disc)
4855 {
4856
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 127 times.
254 AVDictionaryEntry *t = av_dict_get(s->metadata,
4857 disc ? "disc" : "track",
4858 NULL, 0);
4859
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 250 times.
254 int size = 0, track = t ? atoi(t->value) : 0;
4860
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 250 times.
254 if (track) {
4861 4 int tracks = 0;
4862 4 char *slash = strchr(t->value, '/');
4863
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (slash)
4864 3 tracks = atoi(slash + 1);
4865 4 avio_wb32(pb, 32); /* size */
4866
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4867 4 avio_wb32(pb, 24); /* size */
4868 4 ffio_wfourcc(pb, "data");
4869 4 avio_wb32(pb, 0); // 8 bytes empty
4870 4 avio_wb32(pb, 0);
4871 4 avio_wb16(pb, 0); // empty
4872 4 avio_wb16(pb, track); // track / disc number
4873 4 avio_wb16(pb, tracks); // total track / disc number
4874 4 avio_wb16(pb, 0); // empty
4875 4 size = 32;
4876 }
4877 254 return size;
4878 }
4879
4880 762 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4881 const char *name, const char *tag,
4882 int len)
4883 {
4884 762 AVDictionaryEntry *t = NULL;
4885 uint8_t num;
4886 762 int size = 24 + len;
4887
4888
3/4
✓ Branch 0 taken 254 times.
✓ Branch 1 taken 508 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 254 times.
762 if (len != 1 && len != 4)
4889 ✗ return -1;
4890
4891
2/2
✓ Branch 1 taken 760 times.
✓ Branch 2 taken 2 times.
762 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4892 760 return 0;
4893 2 num = atoi(t->value);
4894
4895 2 avio_wb32(pb, size);
4896 2 ffio_wfourcc(pb, name);
4897 2 avio_wb32(pb, size - 8);
4898 2 ffio_wfourcc(pb, "data");
4899 2 avio_wb32(pb, 0x15);
4900 2 avio_wb32(pb, 0);
4901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4902 2 else avio_w8 (pb, num);
4903
4904 2 return size;
4905 }
4906
4907 127 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4908 {
4909 127 MOVMuxContext *mov = s->priv_data;
4910 127 int64_t pos = 0;
4911
4912
2/2
✓ Branch 0 taken 389 times.
✓ Branch 1 taken 127 times.
516 for (int i = 0; i < mov->nb_streams; i++) {
4913 389 MOVTrack *trk = &mov->tracks[i];
4914
4915
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 387 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
389 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4916 387 continue;
4917
4918
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4919 1 pos = avio_tell(pb);
4920 1 avio_wb32(pb, 0);
4921 1 ffio_wfourcc(pb, "covr");
4922 }
4923 2 avio_wb32(pb, 16 + trk->cover_image->size);
4924 2 ffio_wfourcc(pb, "data");
4925 2 avio_wb32(pb, trk->tag);
4926 2 avio_wb32(pb , 0);
4927 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4928 }
4929
4930
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 126 times.
127 return pos ? update_size(pb, pos) : 0;
4931 }
4932
4933 /* iTunes meta data list */
4934 127 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4935 AVFormatContext *s)
4936 {
4937 127 int64_t pos = avio_tell(pb);
4938 127 avio_wb32(pb, 0); /* size */
4939 127 ffio_wfourcc(pb, "ilst");
4940 127 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4941 127 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4942 127 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4943 127 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4944 127 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4945 127 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4946
1/2
✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
127 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4947
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 116 times.
127 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4948 11 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4949 }
4950 127 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4951 127 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4952 127 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4953 127 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4954 127 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4955 127 mov_write_string_metadata(s, pb, "desc", "description",1);
4956 127 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4957 127 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4958 127 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4959 127 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4960 127 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4961 127 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4962 127 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4963 127 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4964 127 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4965 127 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4966 127 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4967 127 mov_write_covr(pb, s);
4968 127 mov_write_trkn_tag(pb, mov, s, 0); // track number
4969 127 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4970 127 mov_write_tmpo_tag(pb, s);
4971 127 mov_write_custom_metadata(s, pb, "com.apple.iTunes", "DISCSUBTITLE", "disc_subtitle");
4972 127 return update_size(pb, pos);
4973 }
4974
4975 ✗ static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4976 AVFormatContext *s)
4977 {
4978 ✗ avio_wb32(pb, 33); /* size */
4979 ✗ ffio_wfourcc(pb, "hdlr");
4980 ✗ avio_wb32(pb, 0);
4981 ✗ avio_wb32(pb, 0);
4982 ✗ ffio_wfourcc(pb, "mdta");
4983 ✗ avio_wb32(pb, 0);
4984 ✗ avio_wb32(pb, 0);
4985 ✗ avio_wb32(pb, 0);
4986 ✗ avio_w8(pb, 0);
4987 ✗ return 33;
4988 }
4989
4990 ✗ static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4991 AVFormatContext *s)
4992 {
4993 ✗ const AVDictionaryEntry *t = NULL;
4994 ✗ int64_t pos = avio_tell(pb);
4995 int64_t curpos, entry_pos;
4996 ✗ int count = 0;
4997
4998 ✗ avio_wb32(pb, 0); /* size */
4999 ✗ ffio_wfourcc(pb, "keys");
5000 ✗ avio_wb32(pb, 0);
5001 ✗ entry_pos = avio_tell(pb);
5002 ✗ avio_wb32(pb, 0); /* entry count */
5003
5004 ✗ while (t = av_dict_iterate(s->metadata, t)) {
5005 ✗ size_t key_len = strlen(t->key);
5006 ✗ avio_wb32(pb, key_len + 8);
5007 ✗ ffio_wfourcc(pb, "mdta");
5008 ✗ avio_write(pb, t->key, key_len);
5009 ✗ count += 1;
5010 }
5011 ✗ curpos = avio_tell(pb);
5012 ✗ avio_seek(pb, entry_pos, SEEK_SET);
5013 ✗ avio_wb32(pb, count); // rewrite entry count
5014 ✗ avio_seek(pb, curpos, SEEK_SET);
5015
5016 ✗ return update_size(pb, pos);
5017 }
5018
5019 ✗ static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
5020 AVFormatContext *s)
5021 {
5022 ✗ const AVDictionaryEntry *t = NULL;
5023 ✗ int64_t pos = avio_tell(pb);
5024 ✗ int count = 1; /* keys are 1-index based */
5025
5026 ✗ avio_wb32(pb, 0); /* size */
5027 ✗ ffio_wfourcc(pb, "ilst");
5028
5029 ✗ while (t = av_dict_iterate(s->metadata, t)) {
5030 ✗ int64_t entry_pos = avio_tell(pb);
5031 ✗ avio_wb32(pb, 0); /* size */
5032 ✗ avio_wb32(pb, count); /* key */
5033 ✗ mov_write_string_data_tag(pb, t->value, 0, 1);
5034 ✗ update_size(pb, entry_pos);
5035 ✗ count += 1;
5036 }
5037 ✗ return update_size(pb, pos);
5038 }
5039
5040 /* meta data tags */
5041 127 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
5042 AVFormatContext *s)
5043 {
5044 127 int size = 0;
5045 127 int64_t pos = avio_tell(pb);
5046 127 avio_wb32(pb, 0); /* size */
5047 127 ffio_wfourcc(pb, "meta");
5048 127 avio_wb32(pb, 0);
5049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 127 times.
127 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
5050 ✗ mov_write_mdta_hdlr_tag(pb, mov, s);
5051 ✗ mov_write_mdta_keys_tag(pb, mov, s);
5052 ✗ mov_write_mdta_ilst_tag(pb, mov, s);
5053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 127 times.
127 } else if (mov->mode == MODE_AVIF) {
5054 ✗ mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
5055 // We always write the primary item id as 1 since only one track is
5056 // supported for AVIF.
5057 ✗ mov_write_pitm_tag(pb, 1);
5058 ✗ mov_write_iloc_tag(pb, mov, s);
5059 ✗ mov_write_iinf_tag(pb, mov, s);
5060 ✗ if (mov->nb_streams > 1)
5061 ✗ mov_write_iref_tag(pb, mov, s);
5062 ✗ mov_write_iprp_tag(pb, mov, s);
5063 } else {
5064 /* iTunes metadata tag */
5065 127 mov_write_itunes_hdlr_tag(pb, mov, s);
5066 127 mov_write_ilst_tag(pb, mov, s);
5067 }
5068 127 size = update_size(pb, pos);
5069 127 return size;
5070 }
5071
5072 159 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
5073 const char *name, const char *key)
5074 {
5075 int len;
5076 AVDictionaryEntry *t;
5077
5078
1/2
✓ Branch 1 taken 159 times.
✗ Branch 2 not taken.
159 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
5079 159 return 0;
5080
5081 ✗ len = strlen(t->value);
5082 ✗ if (len > 0) {
5083 ✗ int size = len + 8;
5084 ✗ avio_wb32(pb, size);
5085 ✗ ffio_wfourcc(pb, name);
5086 ✗ avio_write(pb, t->value, len);
5087 ✗ return size;
5088 }
5089 ✗ return 0;
5090 }
5091
5092 ✗ static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
5093 {
5094 int val;
5095 ✗ while (*b) {
5096 ✗ GET_UTF8(val, *b++, return -1;)
5097 ✗ avio_wb16(pb, val);
5098 }
5099 ✗ avio_wb16(pb, 0x00);
5100 ✗ return 0;
5101 }
5102
5103 ✗ static uint16_t language_code(const char *str)
5104 {
5105 ✗ return (((str[0] - 0x60) & 0x1F) << 10) +
5106 ✗ (((str[1] - 0x60) & 0x1F) << 5) +
5107 ✗ (( str[2] - 0x60) & 0x1F);
5108 }
5109
5110 ✗ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
5111 const char *tag, const char *str)
5112 {
5113 ✗ int64_t pos = avio_tell(pb);
5114 ✗ AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
5115 ✗ if (!t || !utf8len(t->value))
5116 ✗ return 0;
5117 ✗ avio_wb32(pb, 0); /* size */
5118 ✗ ffio_wfourcc(pb, tag); /* type */
5119 ✗ avio_wb32(pb, 0); /* version + flags */
5120 ✗ if (!strcmp(tag, "yrrc"))
5121 ✗ avio_wb16(pb, atoi(t->value));
5122 else {
5123 ✗ avio_wb16(pb, language_code("eng")); /* language */
5124 ✗ avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
5125 ✗ if (!strcmp(tag, "albm") &&
5126 ✗ (t = av_dict_get(s->metadata, "track", NULL, 0)))
5127 ✗ avio_w8(pb, atoi(t->value));
5128 }
5129 ✗ return update_size(pb, pos);
5130 }
5131
5132 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
5133 {
5134 1 int64_t pos = avio_tell(pb);
5135 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
5136
5137 1 avio_wb32(pb, 0); // size
5138 1 ffio_wfourcc(pb, "chpl");
5139 1 avio_wb32(pb, 0x01000000); // version + flags
5140 1 avio_wb32(pb, 0); // unknown
5141 1 avio_w8(pb, nb_chapters);
5142
5143
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
5144 4 AVChapter *c = s->chapters[i];
5145 AVDictionaryEntry *t;
5146 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
5147
5148
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
5149
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
5150 4 avio_w8(pb, len);
5151 4 avio_write(pb, t->value, len);
5152 } else
5153 ✗ avio_w8(pb, 0);
5154 }
5155 1 return update_size(pb, pos);
5156 }
5157
5158 286 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
5159 AVFormatContext *s)
5160 {
5161 AVIOContext *pb_buf;
5162 int ret, size;
5163 uint8_t *buf;
5164
5165 286 ret = avio_open_dyn_buf(&pb_buf);
5166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286 times.
286 if (ret < 0)
5167 ✗ return ret;
5168
5169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286 times.
286 if (mov->mode & MODE_3GP) {
5170 ✗ mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
5171 ✗ mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
5172 ✗ mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
5173 ✗ mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
5174 ✗ mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
5175 ✗ mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
5176 ✗ mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
5177 ✗ mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
5178 ✗ mov_write_loci_tag(s, pb_buf);
5179
3/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 127 times.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
286 } else if (mov->mode == MODE_MOV && !(mov->flags & FF_MOV_FLAG_USE_MDTA)) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
5180 159 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
5181 159 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
5182 159 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
5183 159 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
5184 159 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
5185 159 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
5186 // currently ignored by mov.c
5187 159 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
5188 // add support for libquicktime, this atom is also actually read by mov.c
5189 159 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
5190 159 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
5191 159 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
5192 159 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
5193 159 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
5194 159 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
5195 159 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
5196 159 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
5197 } else {
5198 /* iTunes meta data */
5199 127 mov_write_meta_tag(pb_buf, mov, s);
5200 127 mov_write_loci_tag(s, pb_buf);
5201 }
5202
5203
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 285 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
286 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
5204 1 mov_write_chpl_tag(pb_buf, s);
5205
5206
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 131 times.
286 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
5207 155 avio_wb32(pb, size + 8);
5208 155 ffio_wfourcc(pb, "udta");
5209 155 avio_write(pb, buf, size);
5210 }
5211 286 ffio_free_dyn_buf(&pb_buf);
5212
5213 286 return 0;
5214 }
5215
5216 ✗ static void mov_write_psp_udta_tag(AVIOContext *pb,
5217 const char *str, const char *lang, int type)
5218 {
5219 ✗ int len = utf8len(str) + 1;
5220 ✗ if (len <= 0)
5221 ✗ return;
5222 ✗ avio_wb16(pb, len * 2 + 10); /* size */
5223 ✗ avio_wb32(pb, type); /* type */
5224 ✗ avio_wb16(pb, language_code(lang)); /* language */
5225 ✗ avio_wb16(pb, 0x01); /* ? */
5226 ✗ ascii_to_wc(pb, str);
5227 }
5228
5229 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
5230 {
5231 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
5232 int64_t pos, pos2;
5233
5234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
5235 ✗ pos = avio_tell(pb);
5236 ✗ avio_wb32(pb, 0); /* size placeholder*/
5237 ✗ ffio_wfourcc(pb, "uuid");
5238 ✗ ffio_wfourcc(pb, "USMT");
5239 ✗ avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5240 ✗ avio_wb32(pb, 0xbb88695c);
5241 ✗ avio_wb32(pb, 0xfac9c740);
5242
5243 ✗ pos2 = avio_tell(pb);
5244 ✗ avio_wb32(pb, 0); /* size placeholder*/
5245 ✗ ffio_wfourcc(pb, "MTDT");
5246 ✗ avio_wb16(pb, 4);
5247
5248 // ?
5249 ✗ avio_wb16(pb, 0x0C); /* size */
5250 ✗ avio_wb32(pb, 0x0B); /* type */
5251 ✗ avio_wb16(pb, language_code("und")); /* language */
5252 ✗ avio_wb16(pb, 0x0); /* ? */
5253 ✗ avio_wb16(pb, 0x021C); /* data */
5254
5255 ✗ if (!(s->flags & AVFMT_FLAG_BITEXACT))
5256 ✗ mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
5257 ✗ mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
5258 ✗ mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
5259
5260 ✗ update_size(pb, pos2);
5261 ✗ return update_size(pb, pos);
5262 }
5263
5264 1 return 0;
5265 }
5266
5267 577 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
5268 {
5269 AVEncryptionInitInfo *info;
5270 577 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
5271 577 st->codecpar->nb_coded_side_data,
5272 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
5273
1/2
✓ Branch 0 taken 577 times.
✗ Branch 1 not taken.
577 if (!sd)
5274 577 return 0;
5275
5276 ✗ info = av_encryption_init_info_get_side_data(sd->data, sd->size);
5277 ✗ for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
5278 int64_t pos;
5279
5280 ✗ if (!copy->data_size && !copy->num_key_ids)
5281 ✗ continue;
5282
5283 ✗ pos = avio_tell(pb);
5284 ✗ avio_wb32(pb, 0); /* size placeholder */
5285 ✗ ffio_wfourcc(pb, "pssh");
5286 ✗ avio_w8(pb, 1); /* version */
5287 ✗ avio_wb24(pb, 0);
5288 ✗ for (int i = 0; i < copy->system_id_size; i++)
5289 ✗ avio_w8(pb, copy->system_id[i]);
5290 ✗ avio_wb32(pb, copy->num_key_ids);
5291 ✗ for (int i = 0; i < copy->num_key_ids; i++)
5292 ✗ for (int j = 0; j < copy->key_id_size; j++)
5293 ✗ avio_w8(pb, copy->key_ids[i][j]);
5294 ✗ avio_wb32(pb, copy->data_size);
5295 ✗ avio_write(pb, copy->data, copy->data_size);
5296 ✗ update_size(pb, pos);
5297 }
5298
5299 ✗ av_encryption_init_info_free(info);
5300
5301 ✗ return 0;
5302 }
5303
5304 550 static void build_chunks(MOVTrack *trk)
5305 {
5306 int i;
5307 550 MOVIentry *chunk = &trk->cluster[0];
5308 550 uint64_t chunkSize = chunk->size;
5309 550 chunk->chunkNum = 1;
5310
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 392 times.
550 if (trk->chunkCount)
5311 158 return;
5312 392 trk->chunkCount = 1;
5313
2/2
✓ Branch 0 taken 20685 times.
✓ Branch 1 taken 392 times.
21077 for (i = 1; i<trk->entry; i++){
5314
2/2
✓ Branch 0 taken 18888 times.
✓ Branch 1 taken 1797 times.
20685 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5315
2/2
✓ Branch 0 taken 18886 times.
✓ Branch 1 taken 2 times.
18888 chunk->stsd_index == trk->cluster[i].stsd_index &&
5316
2/2
✓ Branch 0 taken 18241 times.
✓ Branch 1 taken 645 times.
18886 chunkSize + trk->cluster[i].size < (1<<20)){
5317 18241 chunkSize += trk->cluster[i].size;
5318 18241 chunk->samples_in_chunk += trk->cluster[i].entries;
5319 } else {
5320 2444 trk->cluster[i].chunkNum = chunk->chunkNum+1;
5321 2444 chunk=&trk->cluster[i];
5322 2444 chunkSize = chunk->size;
5323 2444 trk->chunkCount++;
5324 }
5325 }
5326 }
5327
5328 /**
5329 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5330 * the stream ids are used as track ids.
5331 *
5332 * This assumes mov->tracks and s->streams are in the same order and
5333 * there are no gaps in either of them (so mov->tracks[n] refers to
5334 * s->streams[n]).
5335 *
5336 * As an exception, there can be more entries in
5337 * s->streams than in mov->tracks, in which case new track ids are
5338 * generated (starting after the largest found stream id).
5339 */
5340 287 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5341 {
5342 int i;
5343
5344
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 253 times.
287 if (mov->track_ids_ok)
5345 34 return 0;
5346
5347
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->use_stream_ids_as_track_ids) {
5348 1 int next_generated_track_id = 0;
5349
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5350 2 AVStream *st = mov->tracks[i].st;
5351
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5352 2 next_generated_track_id = st->id;
5353 }
5354
5355
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5356
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5357 ✗ continue;
5358
5359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->tracks[i].track_id = i >= mov->nb_streams ? ++next_generated_track_id : mov->tracks[i].st->id;
5360 }
5361 } else {
5362 252 int last_track_id = 0;
5363
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 252 times.
674 for (i = 0; i < mov->nb_tracks; i++) {
5364
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 386 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 34 times.
422 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5365 2 continue;
5366
5367 420 last_track_id =
5368 420 mov->tracks[i].track_id = (mov->tracks[i].st
5369 417 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5370
2/2
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 3 times.
420 : FFMAX(i, last_track_id)) + 1;
5371 }
5372 }
5373
5374 253 mov->track_ids_ok = 1;
5375
5376 253 return 0;
5377 }
5378
5379 17 static int mov_find_tref_id(MOVMuxContext *mov, const MovTag *tag, uint32_t id)
5380 {
5381
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 13 times.
20 for (int i = 0; i < tag->nb_id; i++) {
5382
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (tag->id[i] == id)
5383 4 return 1;
5384 }
5385 13 return 0;
5386 }
5387
5388 17 static int mov_add_tref_id(MOVMuxContext *mov, MovTag *tag, uint32_t id)
5389 {
5390 17 int ret = mov_find_tref_id(mov, tag, id);
5391
5392
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 4 times.
17 if (!ret) {
5393 13 uint32_t *tmp = av_realloc_array(tag->id, tag->nb_id + 1, sizeof(*tag->id));
5394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tmp)
5395 ✗ return AVERROR(ENOMEM);
5396 13 tag->id = tmp;
5397 13 tag->id[tag->nb_id++] = id;
5398 }
5399
5400 17 return 0;
5401 }
5402
5403 17 static MovTag *mov_find_tref_tag(MOVMuxContext *mov, const MOVTrack *trk, uint32_t name)
5404 {
5405
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 11 times.
17 for (int i = 0; i < trk->nb_tref_tags; i++) {
5406 6 MovTag *entry = &trk->tref_tags[i];
5407
5408
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (entry->name == name)
5409 6 return entry;
5410 }
5411 11 return NULL;
5412 }
5413
5414 17 static MovTag *mov_add_tref_tag(MOVMuxContext *mov, MOVTrack *trk, uint32_t name)
5415 {
5416 17 MovTag *tag = mov_find_tref_tag(mov, trk, name);
5417
5418
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 if (!tag) {
5419 11 MovTag *tmp = av_realloc_array(trk->tref_tags, trk->nb_tref_tags + 1,
5420 sizeof(*trk->tref_tags));
5421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!tmp)
5422 ✗ return NULL;
5423 11 trk->tref_tags = tmp;
5424 11 tag = &trk->tref_tags[trk->nb_tref_tags++];
5425 11 *tag = (MovTag){ .name = name };
5426 }
5427
5428 17 return tag;
5429 }
5430
5431 287 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5432 AVFormatContext *s)
5433 {
5434 int i;
5435 287 int64_t pos = avio_tell(pb);
5436 287 avio_wb32(pb, 0); /* size placeholder*/
5437 287 ffio_wfourcc(pb, "moov");
5438
5439 287 mov_setup_track_ids(mov, s);
5440
5441
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 287 times.
877 for (i = 0; i < mov->nb_tracks; i++) {
5442
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 550 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 38 times.
590 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5443 2 continue;
5444
5445 588 mov->tracks[i].time = mov->time;
5446
5447
2/2
✓ Branch 0 taken 550 times.
✓ Branch 1 taken 38 times.
588 if (mov->tracks[i].entry)
5448 550 build_chunks(&mov->tracks[i]);
5449 }
5450
5451
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 286 times.
287 if (mov->chapter_track)
5452
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5453 1 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[i], MKTAG('c','h','a','p'));
5454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
5455 ✗ return AVERROR(ENOMEM);
5456
5457 1 int ret = mov_add_tref_id(mov, tag, mov->tracks[mov->chapter_track].track_id);
5458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
5459 ✗ return ret;
5460 }
5461
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 287 times.
877 for (i = 0; i < mov->nb_tracks; i++) {
5462 590 MOVTrack *track = &mov->tracks[i];
5463
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 588 times.
590 if (track->tag == MKTAG('r','t','p',' ')) {
5464 2 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('h','i','n','t'));
5465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
5466 ✗ return AVERROR(ENOMEM);
5467
5468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(track->nb_src_track);
5469 2 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
5471 ✗ return ret;
5472
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 587 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
589 } else if (track->tag == MKTAG('l','v','c','1') && track->nb_src_track) {
5473 1 MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('s','b','a','s'));
5474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
5475 ✗ return AVERROR(ENOMEM);
5476
5477 1 int ret = mov_add_tref_id(mov, tag, mov->tracks[*track->src_track].track_id);
5478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
5479 ✗ return ret;
5480 } else {
5481
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 256 times.
587 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5482 331 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5483 331 track->st->codecpar->nb_coded_side_data,
5484 AV_PKT_DATA_FALLBACK_TRACK );
5485
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
331 if (sd && sd->size == sizeof(int)) {
5486 ✗ int *fallback = (int *)sd->data;
5487 ✗ if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5488 ✗ MovTag *tag = mov_add_tref_tag(mov, track, MKTAG('f','a','l','l'));
5489 ✗ if (!tag)
5490 ✗ return AVERROR(ENOMEM);
5491
5492 ✗ int ret = mov_add_tref_id(mov, tag, mov->tracks[*fallback].track_id);
5493 ✗ if (ret < 0)
5494 ✗ return ret;
5495 }
5496 }
5497 }
5498
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 587 times.
600 for (int j = 0; j < track->nb_src_track; j++) {
5499 13 int src_trk = track->src_track[j];
5500 13 MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[src_trk], track->tag);
5501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!tag)
5502 ✗ return AVERROR(ENOMEM);
5503 13 int ret = mov_add_tref_id(mov, tag, track->track_id);
5504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (ret < 0)
5505 ✗ return ret;
5506 }
5507
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 561 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
587 if (mov->nb_meta_tmcd && track->nb_src_track) {
5508 /* Derive the duration from the first source track, matching
5509 * the convention used by get_pts_range() and the rtp/lvc1
5510 * branches above. The source may use a different timescale. */
5511 10 int src_trk = track->src_track[0];
5512 10 track->track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5513 10 track->timescale,
5514 10 mov->tracks[src_trk].timescale);
5515 }
5516 }
5517 }
5518
5519 287 mov_write_mvhd_tag(pb, mov);
5520
4/6
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 128 times.
287 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5521 ✗ mov_write_iods_tag(pb, mov);
5522
2/2
✓ Branch 0 taken 590 times.
✓ Branch 1 taken 287 times.
877 for (i = 0; i < mov->nb_tracks; i++) {
5523
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 550 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 38 times.
590 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5525
2/2
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 13 times.
588 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (ret < 0)
5527 ✗ return ret;
5528 }
5529 }
5530 /* Don't write mvex for hybrid_fragmented during mov_write_trailer
5531 * (mov->moov_written != 0)
5532 */
5533
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 215 times.
287 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
5534
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
72 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED && mov->moov_written))
5535 70 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5536
5537
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 286 times.
287 if (mov->mode == MODE_PSP)
5538 1 mov_write_uuidusmt_tag(pb, s);
5539
1/2
✓ Branch 0 taken 286 times.
✗ Branch 1 not taken.
286 else if (mov->mode != MODE_AVIF)
5540 286 mov_write_udta_tag(pb, mov, s);
5541
2/2
✓ Branch 0 taken 577 times.
✓ Branch 1 taken 287 times.
864 for (i = 0; i < mov->nb_streams; i++)
5542 577 mov_write_pssh_tag(pb, mov->tracks[i].st);
5543
5544 287 return update_size(pb, pos);
5545 }
5546
5547 ✗ static void param_write_int(AVIOContext *pb, const char *name, int value)
5548 {
5549 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5550 ✗ }
5551
5552 ✗ static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5553 {
5554 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5555 ✗ }
5556
5557 ✗ static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5558 {
5559 char buf[150];
5560 ✗ len = FFMIN(sizeof(buf) / 2 - 1, len);
5561 ✗ ff_data_to_hex(buf, value, len, 0);
5562 ✗ avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5563 ✗ }
5564
5565 ✗ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5566 {
5567 ✗ int64_t pos = avio_tell(pb);
5568 int i;
5569
5570 static const AVUUID uuid = {
5571 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5572 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5573 };
5574
5575 ✗ avio_wb32(pb, 0);
5576 ✗ ffio_wfourcc(pb, "uuid");
5577 ✗ avio_write(pb, uuid, AV_UUID_LEN);
5578 ✗ avio_wb32(pb, 0);
5579
5580 ✗ avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5581 ✗ avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5582 ✗ avio_printf(pb, "<head>\n");
5583 ✗ if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5584 ✗ avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5585 LIBAVFORMAT_IDENT);
5586 ✗ avio_printf(pb, "</head>\n");
5587 ✗ avio_printf(pb, "<body>\n");
5588 ✗ avio_printf(pb, "<switch>\n");
5589
5590 ✗ mov_setup_track_ids(mov, s);
5591
5592 ✗ for (i = 0; i < mov->nb_tracks; i++) {
5593 ✗ MOVTrack *track = &mov->tracks[i];
5594 struct mpeg4_bit_rate_values bit_rates =
5595 ✗ calculate_mpeg4_bit_rates(track);
5596 const char *type;
5597 ✗ int track_id = track->track_id;
5598 ✗ char track_name_buf[32] = { 0 };
5599
5600 ✗ AVStream *st = track->st;
5601 ✗ AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5602
5603 ✗ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5604 ✗ type = "video";
5605 ✗ } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5606 ✗ type = "audio";
5607 } else {
5608 ✗ continue;
5609 }
5610
5611 ✗ avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5612 bit_rates.avg_bit_rate);
5613 ✗ param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5614 ✗ param_write_int(pb, "trackID", track_id);
5615 ✗ param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5616
5617 /* Build track name piece by piece: */
5618 /* 1. track type */
5619 ✗ av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5620 /* 2. track language, if available */
5621 ✗ if (lang)
5622 ✗ av_strlcatf(track_name_buf, sizeof(track_name_buf),
5623 "_%s", lang->value);
5624 /* 3. special type suffix */
5625 /* "_cc" = closed captions, "_ad" = audio_description */
5626 ✗ if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5627 ✗ av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5628 ✗ else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5629 ✗ av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5630
5631 ✗ param_write_string(pb, "trackName", track_name_buf);
5632
5633 ✗ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5634 ✗ if (track->par->codec_id == AV_CODEC_ID_H264) {
5635 uint8_t *ptr;
5636 ✗ int size = track->extradata_size[track->last_stsd_index];
5637 ✗ if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
5638 &size)) {
5639 ✗ param_write_hex(pb, "CodecPrivateData",
5640 ✗ ptr ? ptr : track->extradata[track->last_stsd_index],
5641 size);
5642 ✗ av_free(ptr);
5643 }
5644 ✗ param_write_string(pb, "FourCC", "H264");
5645 ✗ } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5646 ✗ param_write_string(pb, "FourCC", "WVC1");
5647 ✗ param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5648 ✗ track->extradata_size[track->last_stsd_index]);
5649 }
5650 ✗ param_write_int(pb, "MaxWidth", track->par->width);
5651 ✗ param_write_int(pb, "MaxHeight", track->par->height);
5652 ✗ param_write_int(pb, "DisplayWidth", track->par->width);
5653 ✗ param_write_int(pb, "DisplayHeight", track->par->height);
5654 } else {
5655 ✗ if (track->par->codec_id == AV_CODEC_ID_AAC) {
5656 ✗ switch (track->par->profile) {
5657 ✗ case AV_PROFILE_AAC_HE_V2:
5658 ✗ param_write_string(pb, "FourCC", "AACP");
5659 ✗ break;
5660 ✗ case AV_PROFILE_AAC_HE:
5661 ✗ param_write_string(pb, "FourCC", "AACH");
5662 ✗ break;
5663 ✗ default:
5664 ✗ param_write_string(pb, "FourCC", "AACL");
5665 }
5666 ✗ } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5667 ✗ param_write_string(pb, "FourCC", "WMAP");
5668 }
5669 ✗ param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
5670 ✗ track->extradata_size[track->last_stsd_index]);
5671 ✗ param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5672 ✗ track->par->codec_id));
5673 ✗ param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5674 ✗ param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5675 ✗ 0 : track->par->sample_rate);
5676 ✗ param_write_int(pb, "BitsPerSample", 16);
5677 ✗ param_write_int(pb, "PacketSize", track->par->block_align ?
5678 ✗ track->par->block_align : 4);
5679 }
5680 ✗ avio_printf(pb, "</%s>\n", type);
5681 }
5682 ✗ avio_printf(pb, "</switch>\n");
5683 ✗ avio_printf(pb, "</body>\n");
5684 ✗ avio_printf(pb, "</smil>\n");
5685
5686 ✗ return update_size(pb, pos);
5687 }
5688
5689 246 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5690 {
5691 246 avio_wb32(pb, 16);
5692 246 ffio_wfourcc(pb, "mfhd");
5693 246 avio_wb32(pb, 0);
5694 246 avio_wb32(pb, mov->fragments);
5695 246 return 0;
5696 }
5697
5698 19594 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5699 {
5700
2/2
✓ Branch 0 taken 13660 times.
✓ Branch 1 taken 5934 times.
19594 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5701 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5702 }
5703
5704 762 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5705 MOVTrack *track, int64_t moof_offset)
5706 {
5707 762 int64_t pos = avio_tell(pb);
5708 762 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5709 MOV_TFHD_BASE_DATA_OFFSET;
5710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
762 if (!track->entry) {
5711 ✗ flags |= MOV_TFHD_DURATION_IS_EMPTY;
5712 } else {
5713 762 flags |= MOV_TFHD_DEFAULT_FLAGS;
5714 }
5715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
762 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5716 ✗ flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5717
2/2
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 214 times.
762 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5718 548 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5719 548 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5720 }
5721 /* CMAF requires all values to be explicit in tfhd atoms */
5722
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 702 times.
762 if (mov->flags & FF_MOV_FLAG_CMAF)
5723 60 flags |= MOV_TFHD_STSD_ID;
5724
5725 /* Don't set a default sample size, the silverlight player refuses
5726 * to play files with that set. Don't set a default sample duration,
5727 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5728 * file format says it MUST NOT be set. */
5729
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 680 times.
762 if (track->mode == MODE_ISM)
5730 82 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5731 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5732
5733 762 avio_wb32(pb, 0); /* size placeholder */
5734 762 ffio_wfourcc(pb, "tfhd");
5735 762 avio_w8(pb, 0); /* version */
5736 762 avio_wb24(pb, flags);
5737
5738 762 avio_wb32(pb, track->track_id); /* track-id */
5739
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 630 times.
762 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5740 132 avio_wb64(pb, moof_offset);
5741
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 702 times.
762 if (flags & MOV_TFHD_STSD_ID) {
5742 60 avio_wb32(pb, 1);
5743 }
5744
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 82 times.
762 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5745 680 track->default_duration = get_cluster_duration(track, 0);
5746 680 avio_wb32(pb, track->default_duration);
5747 }
5748
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 82 times.
762 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5749
1/2
✓ Branch 0 taken 680 times.
✗ Branch 1 not taken.
680 track->default_size = track->entry ? track->cluster[0].size : 1;
5750 680 avio_wb32(pb, track->default_size);
5751 } else
5752 82 track->default_size = -1;
5753
5754
1/2
✓ Branch 0 taken 762 times.
✗ Branch 1 not taken.
762 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5755 /* Set the default flags based on the second sample, if available.
5756 * If the first sample is different, that can be signaled via a separate field. */
5757
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 72 times.
762 if (track->entry > 1)
5758 690 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5759 else
5760 72 track->default_sample_flags =
5761 72 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5762
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 56 times.
72 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5763 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5764 762 avio_wb32(pb, track->default_sample_flags);
5765 }
5766
5767 762 return update_size(pb, pos);
5768 }
5769
5770 764 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5771 MOVTrack *track, int moof_size,
5772 int first, int end)
5773 {
5774 764 int64_t pos = avio_tell(pb);
5775 764 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5776 int i;
5777
5778
2/2
✓ Branch 0 taken 18360 times.
✓ Branch 1 taken 764 times.
19124 for (i = first; i < end; i++) {
5779
2/2
✓ Branch 1 taken 1854 times.
✓ Branch 2 taken 16506 times.
18360 if (get_cluster_duration(track, i) != track->default_duration)
5780 1854 flags |= MOV_TRUN_SAMPLE_DURATION;
5781
2/2
✓ Branch 0 taken 2972 times.
✓ Branch 1 taken 15388 times.
18360 if (track->cluster[i].size != track->default_size)
5782 2972 flags |= MOV_TRUN_SAMPLE_SIZE;
5783
4/4
✓ Branch 0 taken 17596 times.
✓ Branch 1 taken 764 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 17586 times.
18360 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5784 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5785 }
5786
3/4
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 756 times.
✗ Branch 3 not taken.
764 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5787
2/2
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 576 times.
756 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5788 180 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5789
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 664 times.
764 if (track->flags & MOV_TRACK_CTTS)
5790 100 flags |= MOV_TRUN_SAMPLE_CTS;
5791
5792 764 avio_wb32(pb, 0); /* size placeholder */
5793 764 ffio_wfourcc(pb, "trun");
5794
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 606 times.
764 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5795 158 avio_w8(pb, 1); /* version */
5796 else
5797 606 avio_w8(pb, 0); /* version */
5798 764 avio_wb24(pb, flags);
5799
5800 764 avio_wb32(pb, end - first); /* sample count */
5801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 764 times.
764 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5802 ✗ !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5803 ✗ !mov->first_trun)
5804 ✗ avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5805 else
5806 764 avio_wb32(pb, moof_size + 8 + track->data_offset +
5807 764 track->cluster[first].pos); /* data offset */
5808
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 584 times.
764 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5809 180 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5810
5811
2/2
✓ Branch 0 taken 18360 times.
✓ Branch 1 taken 764 times.
19124 for (i = first; i < end; i++) {
5812
2/2
✓ Branch 0 taken 2050 times.
✓ Branch 1 taken 16310 times.
18360 if (flags & MOV_TRUN_SAMPLE_DURATION)
5813 2050 avio_wb32(pb, get_cluster_duration(track, i));
5814
2/2
✓ Branch 0 taken 3656 times.
✓ Branch 1 taken 14704 times.
18360 if (flags & MOV_TRUN_SAMPLE_SIZE)
5815 3656 avio_wb32(pb, track->cluster[i].size);
5816
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 17988 times.
18360 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5817 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5818
2/2
✓ Branch 0 taken 3162 times.
✓ Branch 1 taken 15198 times.
18360 if (flags & MOV_TRUN_SAMPLE_CTS)
5819 3162 avio_wb32(pb, track->cluster[i].cts);
5820 }
5821
5822 764 mov->first_trun = 0;
5823 764 return update_size(pb, pos);
5824 }
5825
5826 82 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5827 {
5828 82 int64_t pos = avio_tell(pb);
5829 static const uint8_t uuid[] = {
5830 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5831 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5832 };
5833
5834 82 avio_wb32(pb, 0); /* size placeholder */
5835 82 ffio_wfourcc(pb, "uuid");
5836 82 avio_write(pb, uuid, AV_UUID_LEN);
5837 82 avio_w8(pb, 1);
5838 82 avio_wb24(pb, 0);
5839 82 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5840 82 avio_wb64(pb, track->end_pts -
5841 82 (track->cluster[0].dts + track->cluster[0].cts));
5842
5843 82 return update_size(pb, pos);
5844 }
5845
5846 ✗ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5847 MOVTrack *track, int entry)
5848 {
5849 ✗ int n = track->nb_frag_info - 1 - entry, i;
5850 ✗ int size = 8 + 16 + 4 + 1 + 16*n;
5851 static const uint8_t uuid[] = {
5852 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5853 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5854 };
5855
5856 ✗ if (entry < 0)
5857 ✗ return 0;
5858
5859 ✗ avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5860 ✗ avio_wb32(pb, size);
5861 ✗ ffio_wfourcc(pb, "uuid");
5862 ✗ avio_write(pb, uuid, AV_UUID_LEN);
5863 ✗ avio_w8(pb, 1);
5864 ✗ avio_wb24(pb, 0);
5865 ✗ avio_w8(pb, n);
5866 ✗ for (i = 0; i < n; i++) {
5867 ✗ int index = entry + 1 + i;
5868 ✗ avio_wb64(pb, track->frag_info[index].time);
5869 ✗ avio_wb64(pb, track->frag_info[index].duration);
5870 }
5871 ✗ if (n < mov->ism_lookahead) {
5872 ✗ int free_size = 16 * (mov->ism_lookahead - n);
5873 ✗ avio_wb32(pb, free_size);
5874 ✗ ffio_wfourcc(pb, "free");
5875 ✗ ffio_fill(pb, 0, free_size - 8);
5876 }
5877
5878 ✗ return 0;
5879 }
5880
5881 380 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5882 MOVTrack *track)
5883 {
5884 380 int64_t pos = avio_tell(pb);
5885 int i;
5886
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
380 for (i = 0; i < mov->ism_lookahead; i++) {
5887 /* Update the tfrf tag for the last ism_lookahead fragments,
5888 * nb_frag_info - 1 is the next fragment to be written. */
5889 ✗ mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5890 }
5891 380 avio_seek(pb, pos, SEEK_SET);
5892 380 return 0;
5893 }
5894
5895 122 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5896 int size)
5897 {
5898 int i;
5899
2/2
✓ Branch 0 taken 423 times.
✓ Branch 1 taken 122 times.
545 for (i = 0; i < mov->nb_tracks; i++) {
5900 423 MOVTrack *track = &mov->tracks[i];
5901 MOVFragmentInfo *info;
5902
6/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 344 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 380 times.
423 if ((tracks >= 0 && i != tracks) || !track->entry)
5903 43 continue;
5904 380 track->nb_frag_info++;
5905
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 207 times.
380 if (track->nb_frag_info >= track->frag_info_capacity) {
5906 173 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5907
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if (av_reallocp_array(&track->frag_info,
5908 new_capacity,
5909 sizeof(*track->frag_info)))
5910 ✗ return AVERROR(ENOMEM);
5911 173 track->frag_info_capacity = new_capacity;
5912 }
5913 380 info = &track->frag_info[track->nb_frag_info - 1];
5914 380 info->offset = avio_tell(pb);
5915 380 info->size = size;
5916 // Try to recreate the original pts for the first packet
5917 // from the fields we have stored
5918 380 info->time = track->cluster[0].dts + track->cluster[0].cts;
5919 380 info->duration = track->end_pts -
5920 380 (track->cluster[0].dts + track->cluster[0].cts);
5921 // If the pts is less than zero, we will have trimmed
5922 // away parts of the media track using an edit list,
5923 // and the corresponding start presentation time is zero.
5924
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 372 times.
380 if (info->time < 0) {
5925 8 info->duration += info->time;
5926 8 info->time = 0;
5927 }
5928 380 info->tfrf_offset = 0;
5929 380 mov_write_tfrf_tags(pb, mov, track);
5930 }
5931 122 return 0;
5932 }
5933
5934 ✗ static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5935 {
5936 int i;
5937 ✗ for (i = 0; i < mov->nb_tracks; i++) {
5938 ✗ MOVTrack *track = &mov->tracks[i];
5939 ✗ if ((tracks >= 0 && i != tracks) || !track->entry)
5940 ✗ continue;
5941 ✗ if (track->nb_frag_info > max) {
5942 ✗ memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5943 ✗ track->nb_frag_info = max;
5944 }
5945 }
5946 ✗ }
5947
5948 680 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5949 {
5950 680 int64_t pos = avio_tell(pb);
5951
5952 680 avio_wb32(pb, 0); /* size */
5953 680 ffio_wfourcc(pb, "tfdt");
5954 680 avio_w8(pb, 1); /* version */
5955 680 avio_wb24(pb, 0);
5956 680 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5957 680 return update_size(pb, pos);
5958 }
5959
5960 762 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5961 MOVTrack *track, int64_t moof_offset,
5962 int moof_size)
5963 {
5964 762 int64_t pos = avio_tell(pb);
5965 762 int i, start = 0;
5966 762 avio_wb32(pb, 0); /* size placeholder */
5967 762 ffio_wfourcc(pb, "traf");
5968
5969 762 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5970
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 82 times.
762 if (mov->mode != MODE_ISM)
5971 680 mov_write_tfdt_tag(pb, track);
5972
2/2
✓ Branch 0 taken 17598 times.
✓ Branch 1 taken 762 times.
18360 for (i = 1; i < track->entry; i++) {
5973
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17596 times.
17598 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5974 2 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5975 2 start = i;
5976 }
5977 }
5978 762 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5979
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 680 times.
762 if (mov->mode == MODE_ISM) {
5980 82 mov_write_tfxd_tag(pb, track);
5981
5982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->ism_lookahead) {
5983 ✗ int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5984
5985 ✗ if (track->nb_frag_info > 0) {
5986 ✗ MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5987 ✗ if (!info->tfrf_offset)
5988 ✗ info->tfrf_offset = avio_tell(pb);
5989 }
5990 ✗ avio_wb32(pb, 8 + size);
5991 ✗ ffio_wfourcc(pb, "free");
5992 ✗ ffio_fill(pb, 0, size);
5993 }
5994 }
5995
5996
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
762 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5997 ✗ ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5998
5999 762 return update_size(pb, pos);
6000 }
6001
6002 246 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
6003 int tracks, int moof_size)
6004 {
6005 246 int64_t pos = avio_tell(pb);
6006 int i;
6007
6008 246 avio_wb32(pb, 0); /* size placeholder */
6009 246 ffio_wfourcc(pb, "moof");
6010 246 mov->first_trun = 1;
6011
6012 246 mov_write_mfhd_tag(pb, mov);
6013
2/2
✓ Branch 0 taken 848 times.
✓ Branch 1 taken 246 times.
1094 for (i = 0; i < mov->nb_tracks; i++) {
6014 848 MOVTrack *track = &mov->tracks[i];
6015
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 690 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 82 times.
848 if (tracks >= 0 && i != tracks)
6016 76 continue;
6017
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 762 times.
772 if (!track->entry)
6018 10 continue;
6019
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
762 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
6020 ✗ mov_write_pssh_tag(pb, track->st);
6021 762 mov_write_traf_tag(pb, mov, track, pos, moof_size);
6022 }
6023
6024 246 return update_size(pb, pos);
6025 }
6026
6027 478 static int mov_write_sidx_tag(AVIOContext *pb,
6028 MOVTrack *track, int ref_size, int total_sidx_size)
6029 {
6030 478 int64_t pos = avio_tell(pb), offset_pos, end_pos;
6031 int64_t presentation_time, duration, offset;
6032 unsigned starts_with_SAP;
6033 int i, entries;
6034
6035
1/2
✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
478 if (track->entry) {
6036 478 entries = 1;
6037 478 presentation_time = track->cluster[0].dts + track->cluster[0].cts;
6038 478 duration = track->end_pts -
6039 478 (track->cluster[0].dts + track->cluster[0].cts);
6040 478 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6041
6042 // pts<0 should be cut away using edts
6043
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 472 times.
478 if (presentation_time < 0) {
6044 6 duration += presentation_time;
6045 6 presentation_time = 0;
6046 }
6047 } else {
6048 ✗ entries = track->nb_frag_info;
6049 ✗ if (entries <= 0)
6050 ✗ return 0;
6051 ✗ presentation_time = track->frag_info[0].time;
6052 }
6053
6054 478 avio_wb32(pb, 0); /* size */
6055 478 ffio_wfourcc(pb, "sidx");
6056 478 avio_w8(pb, 1); /* version */
6057 478 avio_wb24(pb, 0);
6058 478 avio_wb32(pb, track->track_id); /* reference_ID */
6059 478 avio_wb32(pb, track->timescale); /* timescale */
6060 478 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
6061 478 offset_pos = avio_tell(pb);
6062 478 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
6063 478 avio_wb16(pb, 0); /* reserved */
6064
6065 478 avio_wb16(pb, entries); /* reference_count */
6066
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 478 times.
956 for (i = 0; i < entries; i++) {
6067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
478 if (!track->entry) {
6068 ✗ if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
6069 ✗ av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
6070 }
6071 ✗ duration = track->frag_info[i].duration;
6072 ✗ ref_size = track->frag_info[i].size;
6073 ✗ starts_with_SAP = 1;
6074 }
6075 478 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
6076 478 avio_wb32(pb, duration); /* subsegment_duration */
6077 478 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
6078 }
6079
6080 478 end_pos = avio_tell(pb);
6081 478 offset = pos + total_sidx_size - end_pos;
6082 478 avio_seek(pb, offset_pos, SEEK_SET);
6083 478 avio_wb64(pb, offset);
6084 478 avio_seek(pb, end_pos, SEEK_SET);
6085 478 return update_size(pb, pos);
6086 }
6087
6088 26 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
6089 int tracks, int ref_size)
6090 {
6091 int i, round, ret;
6092 AVIOContext *avio_buf;
6093 26 int total_size = 0;
6094
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 26 times.
78 for (round = 0; round < 2; round++) {
6095 // First run one round to calculate the total size of all
6096 // sidx atoms.
6097 // This would be much simpler if we'd only write one sidx
6098 // atom, for the first track in the moof.
6099
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (round == 0) {
6100
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6101 ✗ return ret;
6102 } else {
6103 26 avio_buf = pb;
6104 }
6105
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 52 times.
530 for (i = 0; i < mov->nb_tracks; i++) {
6106 478 MOVTrack *track = &mov->tracks[i];
6107
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
478 if (tracks >= 0 && i != tracks)
6108 ✗ continue;
6109 // When writing a sidx for the full file, entry is 0, but
6110 // we want to include all tracks. ref_size is 0 in this case,
6111 // since we read it from frag_info instead.
6112
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
478 if (!track->entry && ref_size > 0)
6113 ✗ continue;
6114 478 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
6115 total_size);
6116 }
6117
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (round == 0) {
6118 26 total_size = ffio_close_null_buf(avio_buf);
6119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (total_size < 0)
6120 ✗ return total_size;
6121 }
6122 }
6123 26 return 0;
6124 }
6125
6126 ✗ static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
6127 {
6128 ✗ int64_t pos = avio_tell(pb), pts_us, ntp_ts;
6129 MOVTrack *first_track;
6130 ✗ int flags = 24;
6131
6132 /* PRFT should be associated with at most one track. So, choosing only the
6133 * first track. */
6134 ✗ if (tracks > 0)
6135 ✗ return 0;
6136 ✗ first_track = &(mov->tracks[0]);
6137
6138 ✗ if (!first_track->entry) {
6139 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
6140 ✗ return 0;
6141 }
6142
6143 ✗ if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
6144 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
6145 ✗ return 0;
6146 }
6147
6148 ✗ if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
6149 ✗ if (first_track->cluster[0].prft.wallclock) {
6150 /* Round the NTP time to whole milliseconds. */
6151 ✗ ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
6152 NTP_OFFSET_US);
6153 ✗ flags = first_track->cluster[0].prft.flags;
6154 } else
6155 ✗ ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
6156 ✗ } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
6157 ✗ pts_us = av_rescale_q(first_track->cluster[0].pts,
6158 ✗ first_track->st->time_base, AV_TIME_BASE_Q);
6159 ✗ ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
6160 } else {
6161 ✗ av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
6162 ✗ mov->write_prft);
6163 ✗ return 0;
6164 }
6165
6166 ✗ avio_wb32(pb, 0); // Size place holder
6167 ✗ ffio_wfourcc(pb, "prft"); // Type
6168 ✗ avio_w8(pb, 1); // Version
6169 ✗ avio_wb24(pb, flags); // Flags
6170 ✗ avio_wb32(pb, first_track->track_id); // reference track ID
6171 ✗ avio_wb64(pb, ntp_ts); // NTP time stamp
6172 ✗ avio_wb64(pb, first_track->cluster[0].pts); //media time
6173 ✗ return update_size(pb, pos);
6174 }
6175
6176 123 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
6177 int64_t mdat_size)
6178 {
6179 AVIOContext *avio_buf;
6180 int ret, moof_size;
6181
6182
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
123 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
6183 ✗ return ret;
6184 123 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
6185 123 moof_size = ffio_close_null_buf(avio_buf);
6186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 if (moof_size < 0)
6187 ✗ return moof_size;
6188
6189
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 96 times.
123 if (mov->flags & FF_MOV_FLAG_DASH &&
6190
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 times.
27 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
6191 26 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
6192
6193
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
123 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
6194 ✗ mov_write_prft_tag(pb, mov, tracks);
6195
6196
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
6197
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 122 times.
123 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
6198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->ism_lookahead) {
6199
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
122 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
6200 ✗ return ret;
6201
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
6202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
6203 ✗ mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
6204 }
6205 }
6206
6207 123 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
6208 }
6209
6210 169 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
6211 {
6212 169 int64_t pos = avio_tell(pb);
6213 int i;
6214
6215 169 avio_wb32(pb, 0); /* size placeholder */
6216 169 ffio_wfourcc(pb, "tfra");
6217 169 avio_w8(pb, 1); /* version */
6218 169 avio_wb24(pb, 0);
6219
6220 169 avio_wb32(pb, track->track_id);
6221 169 avio_wb32(pb, 0); /* length of traf/trun/sample num */
6222 169 avio_wb32(pb, track->nb_frag_info);
6223
2/2
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 169 times.
543 for (i = 0; i < track->nb_frag_info; i++) {
6224 374 avio_wb64(pb, track->frag_info[i].time);
6225 374 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
6226 374 avio_w8(pb, 1); /* traf number */
6227 374 avio_w8(pb, 1); /* trun number */
6228 374 avio_w8(pb, 1); /* sample number */
6229 }
6230
6231 169 return update_size(pb, pos);
6232 }
6233
6234 41 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
6235 {
6236 AVIOContext *mfra_pb;
6237 int i, ret, sz;
6238 uint8_t *buf;
6239
6240 41 ret = avio_open_dyn_buf(&mfra_pb);
6241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (ret < 0)
6242 ✗ return ret;
6243
6244 41 avio_wb32(mfra_pb, 0); /* size placeholder */
6245 41 ffio_wfourcc(mfra_pb, "mfra");
6246 /* An empty mfra atom is enough to indicate to the publishing point that
6247 * the stream has ended. */
6248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (mov->flags & FF_MOV_FLAG_ISML)
6249 ✗ goto done_mfra;
6250
6251
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 41 times.
214 for (i = 0; i < mov->nb_tracks; i++) {
6252 173 MOVTrack *track = &mov->tracks[i];
6253
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 4 times.
173 if (track->nb_frag_info)
6254 169 mov_write_tfra_tag(mfra_pb, track);
6255 }
6256
6257 41 avio_wb32(mfra_pb, 16);
6258 41 ffio_wfourcc(mfra_pb, "mfro");
6259 41 avio_wb32(mfra_pb, 0); /* version + flags */
6260 41 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
6261
6262 41 done_mfra:
6263
6264 41 sz = update_size(mfra_pb, 0);
6265 41 ret = avio_get_dyn_buf(mfra_pb, &buf);
6266 41 avio_write(pb, buf, ret);
6267 41 ffio_free_dyn_buf(&mfra_pb);
6268
6269 41 return sz;
6270 }
6271
6272 209 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
6273 {
6274 209 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
6275
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 59 times.
209 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
6276
6277 209 mov->mdat_pos = avio_tell(pb);
6278 209 avio_wb32(pb, 0); /* size placeholder*/
6279 209 ffio_wfourcc(pb, "mdat");
6280 209 return 0;
6281 }
6282
6283 510 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
6284 int has_h264, int has_video, int write_minor)
6285 {
6286 510 MOVMuxContext *mov = s->priv_data;
6287 510 int minor = 0x200;
6288
6289
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
510 if (mov->major_brand && strlen(mov->major_brand) >= 4)
6290 ✗ ffio_wfourcc(pb, mov->major_brand);
6291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 else if (mov->mode == MODE_3GP) {
6292 ✗ ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
6293 ✗ minor = has_h264 ? 0x100 : 0x200;
6294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 } else if (mov->mode == MODE_AVIF) {
6295 ✗ ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
6296 ✗ minor = 0;
6297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 } else if (mov->mode & MODE_3G2) {
6298 ✗ ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
6299 ✗ minor = has_h264 ? 0x20000 : 0x10000;
6300
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 508 times.
510 } else if (mov->mode == MODE_PSP)
6301 2 ffio_wfourcc(pb, "MSNV");
6302
4/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 114 times.
508 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
6303
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 70 times.
78 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6304 8 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
6305
4/4
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 150 times.
500 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6306 34 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
6307
3/4
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 150 times.
466 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6308 ✗ ffio_wfourcc(pb, "iso4");
6309
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 316 times.
466 else if (mov->mode == MODE_MP4)
6310 150 ffio_wfourcc(pb, "isom");
6311
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 314 times.
316 else if (mov->mode == MODE_IPOD)
6312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
6313
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 304 times.
314 else if (mov->mode == MODE_ISM)
6314 10 ffio_wfourcc(pb, "isml");
6315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 304 times.
304 else if (mov->mode == MODE_F4V)
6316 ✗ ffio_wfourcc(pb, "f4v ");
6317 else
6318 304 ffio_wfourcc(pb, "qt ");
6319
6320
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 255 times.
510 if (write_minor)
6321 255 avio_wb32(pb, minor);
6322 510 }
6323
6324 255 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
6325 {
6326 255 MOVMuxContext *mov = s->priv_data;
6327 255 int64_t pos = avio_tell(pb);
6328 255 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
6329 255 int has_iamf = 0;
6330
6331 #if CONFIG_IAMFENC
6332
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 250 times.
256 for (int i = 0; i < s->nb_stream_groups; i++) {
6333 6 const AVStreamGroup *stg = s->stream_groups[i];
6334
6335
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
6336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
6337 5 has_iamf = 1;
6338 5 break;
6339 }
6340 }
6341 #endif
6342
2/2
✓ Branch 0 taken 419 times.
✓ Branch 1 taken 255 times.
674 for (int i = 0; i < mov->nb_streams; i++) {
6343 419 AVStream *st = mov->tracks[i].st;
6344
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 417 times.
419 if (is_cover_image(st))
6345 2 continue;
6346
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 211 times.
417 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6347 206 has_video = 1;
6348
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 378 times.
417 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
6349 39 has_h264 = 1;
6350
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 415 times.
417 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
6351 2 has_av1 = 1;
6352
2/2
✓ Branch 0 taken 411 times.
✓ Branch 1 taken 6 times.
417 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
6353
2/2
✓ Branch 0 taken 407 times.
✓ Branch 1 taken 4 times.
411 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
6354
3/4
✓ Branch 0 taken 407 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 405 times.
814 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
6355 407 av_packet_side_data_get(st->codecpar->coded_side_data,
6356 407 st->codecpar->nb_coded_side_data,
6357 AV_PKT_DATA_DOVI_CONF))
6358 12 has_dolby = 1;
6359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 417 times.
417 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
6360 ✗ has_id3 = 1;
6361 }
6362
6363 255 avio_wb32(pb, 0); /* size */
6364 255 ffio_wfourcc(pb, "ftyp");
6365
6366 // Write major brand
6367 255 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
6368 // Write the major brand as the first compatible brand as well
6369 255 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
6370
6371 // Write compatible brands, ensuring that we don't write the major brand as a
6372 // compatible brand a second time.
6373
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 250 times.
255 if (mov->mode == MODE_ISM) {
6374 5 ffio_wfourcc(pb, "piff");
6375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 250 times.
250 } else if (mov->mode == MODE_AVIF) {
6376 const AVPixFmtDescriptor *pix_fmt_desc =
6377 ✗ av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
6378 ✗ const int depth = pix_fmt_desc->comp[0].depth;
6379 ✗ if (mov->is_animated_avif) {
6380 // For animated AVIF, major brand is "avis". Add "avif" as a
6381 // compatible brand.
6382 ✗ ffio_wfourcc(pb, "avif");
6383 ✗ ffio_wfourcc(pb, "msf1");
6384 ✗ ffio_wfourcc(pb, "iso8");
6385 }
6386 ✗ ffio_wfourcc(pb, "mif1");
6387 ✗ ffio_wfourcc(pb, "miaf");
6388 ✗ if (depth == 8 || depth == 10) {
6389 // MA1B and MA1A brands are based on AV1 profile. Short hand for
6390 // computing that is based on chroma subsampling type. 420 chroma
6391 // subsampling is MA1B. 444 chroma subsampling is MA1A.
6392 ✗ if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
6393 // 444 chroma subsampling.
6394 ✗ ffio_wfourcc(pb, "MA1A");
6395 } else {
6396 // 420 chroma subsampling.
6397 ✗ ffio_wfourcc(pb, "MA1B");
6398 }
6399 }
6400
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 152 times.
250 } else if (mov->mode != MODE_MOV) {
6401 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
6402 // brand, if not already the major brand. This is compatible with users that
6403 // don't understand tfdt.
6404
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 2 times.
98 if (mov->mode == MODE_MP4) {
6405
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94 times.
96 if (mov->flags & FF_MOV_FLAG_CMAF)
6406 2 ffio_wfourcc(pb, "cmfc");
6407
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 4 times.
96 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
6408 35 ffio_wfourcc(pb, "iso6");
6409
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94 times.
96 if (has_av1)
6410 2 ffio_wfourcc(pb, "av01");
6411
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 85 times.
96 if (has_dolby)
6412 11 ffio_wfourcc(pb, "dby1");
6413
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 91 times.
96 if (has_iamf)
6414 5 ffio_wfourcc(pb, "iamf");
6415 } else {
6416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6417 ✗ ffio_wfourcc(pb, "iso6");
6418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6419 ✗ ffio_wfourcc(pb, "iso5");
6420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6421 ✗ ffio_wfourcc(pb, "iso4");
6422 }
6423 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6424
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 19 times.
98 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6425 // write isom for mp4 only if it it's not the major brand already.
6426
4/4
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 75 times.
79 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6427 4 ffio_wfourcc(pb, "isom");
6428 79 ffio_wfourcc(pb, "iso2");
6429
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 54 times.
79 if (has_h264)
6430 25 ffio_wfourcc(pb, "avc1");
6431 }
6432 }
6433
6434
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 159 times.
255 if (mov->mode == MODE_MP4)
6435 96 ffio_wfourcc(pb, "mp41");
6436
6437
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
255 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6438 ✗ ffio_wfourcc(pb, "dash");
6439
6440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
255 if (has_id3)
6441 ✗ ffio_wfourcc(pb, "aid3");
6442
6443 255 return update_size(pb, pos);
6444 }
6445
6446 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6447 {
6448 1 AVStream *video_st = s->streams[0];
6449 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6450 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6451 1 int audio_rate = audio_par->sample_rate;
6452 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6453
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (video_st->avg_frame_rate.num * 0x10000LL) / video_st->avg_frame_rate.den :
6454 0;
6455 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6456 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6457
6458
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (frame_rate < 0 || frame_rate > INT32_MAX) {
6459 ✗ av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6460 ✗ return AVERROR(EINVAL);
6461 }
6462
6463 1 avio_wb32(pb, 0x94); /* size */
6464 1 ffio_wfourcc(pb, "uuid");
6465 1 ffio_wfourcc(pb, "PROF");
6466
6467 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6468 1 avio_wb32(pb, 0xbb88695c);
6469 1 avio_wb32(pb, 0xfac9c740);
6470
6471 1 avio_wb32(pb, 0x0); /* ? */
6472 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6473
6474 1 avio_wb32(pb, 0x14); /* size */
6475 1 ffio_wfourcc(pb, "FPRF");
6476 1 avio_wb32(pb, 0x0); /* ? */
6477 1 avio_wb32(pb, 0x0); /* ? */
6478 1 avio_wb32(pb, 0x0); /* ? */
6479
6480 1 avio_wb32(pb, 0x2c); /* size */
6481 1 ffio_wfourcc(pb, "APRF"); /* audio */
6482 1 avio_wb32(pb, 0x0);
6483 1 avio_wb32(pb, 0x2); /* TrackID */
6484 1 ffio_wfourcc(pb, "mp4a");
6485 1 avio_wb32(pb, 0x20f);
6486 1 avio_wb32(pb, 0x0);
6487 1 avio_wb32(pb, audio_kbitrate);
6488 1 avio_wb32(pb, audio_kbitrate);
6489 1 avio_wb32(pb, audio_rate);
6490 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6491
6492 1 avio_wb32(pb, 0x34); /* size */
6493 1 ffio_wfourcc(pb, "VPRF"); /* video */
6494 1 avio_wb32(pb, 0x0);
6495 1 avio_wb32(pb, 0x1); /* TrackID */
6496
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6497 1 ffio_wfourcc(pb, "avc1");
6498 1 avio_wb16(pb, 0x014D);
6499 1 avio_wb16(pb, 0x0015);
6500 } else {
6501 ✗ ffio_wfourcc(pb, "mp4v");
6502 ✗ avio_wb16(pb, 0x0000);
6503 ✗ avio_wb16(pb, 0x0103);
6504 }
6505 1 avio_wb32(pb, 0x0);
6506 1 avio_wb32(pb, video_kbitrate);
6507 1 avio_wb32(pb, video_kbitrate);
6508 1 avio_wb32(pb, frame_rate);
6509 1 avio_wb32(pb, frame_rate);
6510 1 avio_wb16(pb, video_par->width);
6511 1 avio_wb16(pb, video_par->height);
6512 1 avio_wb32(pb, 0x010001); /* ? */
6513
6514 1 return 0;
6515 }
6516
6517 255 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6518 {
6519 255 MOVMuxContext *mov = s->priv_data;
6520 int i;
6521
6522 255 mov_write_ftyp_tag(pb,s);
6523
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 254 times.
255 if (mov->mode == MODE_PSP) {
6524 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6525
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6526 2 AVStream *st = mov->tracks[i].st;
6527
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6528 ✗ continue;
6529
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6530 1 video_streams_nb++;
6531
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6532 1 audio_streams_nb++;
6533 else
6534 ✗ other_streams_nb++;
6535 }
6536
6537
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if (video_streams_nb != 1 || audio_streams_nb != 1 || other_streams_nb) {
6538 ✗ av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6539 ✗ return AVERROR(EINVAL);
6540 }
6541 1 return mov_write_uuidprof_tag(pb, s);
6542 }
6543 254 return 0;
6544 }
6545
6546 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6547 {
6548 8 uint32_t c = -1;
6549 8 int i, closed_gop = 0;
6550
6551
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6552 368 c = (c << 8) + pkt->data[i];
6553
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6554 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6555
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6556 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6557
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8 if (!temp_ref || closed_gop) // I picture is not reordered
6558 8 *flags = MOV_SYNC_SAMPLE;
6559 else
6560 ✗ *flags = MOV_PARTIAL_SYNC_SAMPLE;
6561 8 break;
6562 }
6563 }
6564 8 return 0;
6565 }
6566
6567 ✗ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6568 {
6569 ✗ const uint8_t *start, *next, *end = pkt->data + pkt->size;
6570 ✗ int seq = 0, entry = 0;
6571 ✗ int key = pkt->flags & AV_PKT_FLAG_KEY;
6572 ✗ start = find_next_marker(pkt->data, end);
6573 ✗ for (next = start; next < end; start = next) {
6574 ✗ next = find_next_marker(start + 4, end);
6575 ✗ switch (AV_RB32(start)) {
6576 ✗ case VC1_CODE_SEQHDR:
6577 ✗ seq = 1;
6578 ✗ break;
6579 ✗ case VC1_CODE_ENTRYPOINT:
6580 ✗ entry = 1;
6581 ✗ break;
6582 ✗ case VC1_CODE_SLICE:
6583 ✗ trk->vc1_info.slices = 1;
6584 ✗ break;
6585 }
6586 }
6587 ✗ if (!trk->entry && trk->vc1_info.first_packet_seen)
6588 ✗ trk->vc1_info.first_frag_written = 1;
6589 ✗ if (!trk->entry && !trk->vc1_info.first_frag_written) {
6590 /* First packet in first fragment */
6591 ✗ trk->vc1_info.first_packet_seq = seq;
6592 ✗ trk->vc1_info.first_packet_entry = entry;
6593 ✗ trk->vc1_info.first_packet_seen = 1;
6594 ✗ } else if ((seq && !trk->vc1_info.packet_seq) ||
6595 ✗ (entry && !trk->vc1_info.packet_entry)) {
6596 int i;
6597 ✗ for (i = 0; i < trk->entry; i++)
6598 ✗ trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6599 ✗ trk->has_keyframes = 0;
6600 ✗ if (seq)
6601 ✗ trk->vc1_info.packet_seq = 1;
6602 ✗ if (entry)
6603 ✗ trk->vc1_info.packet_entry = 1;
6604 ✗ if (!trk->vc1_info.first_frag_written) {
6605 /* First fragment */
6606 ✗ if ((!seq || trk->vc1_info.first_packet_seq) &&
6607 ✗ (!entry || trk->vc1_info.first_packet_entry)) {
6608 /* First packet had the same headers as this one, readd the
6609 * sync sample flag. */
6610 ✗ trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6611 ✗ trk->has_keyframes = 1;
6612 }
6613 }
6614 }
6615 ✗ if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6616 ✗ key = seq && entry;
6617 ✗ else if (trk->vc1_info.packet_seq)
6618 ✗ key = seq;
6619 ✗ else if (trk->vc1_info.packet_entry)
6620 ✗ key = entry;
6621 ✗ if (key) {
6622 ✗ trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6623 ✗ trk->has_keyframes++;
6624 }
6625 ✗ }
6626
6627 ✗ static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6628 {
6629 int length;
6630
6631 ✗ if (pkt->size < 8)
6632 ✗ return;
6633
6634 ✗ length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6635 ✗ if (length < 8 || length > pkt->size)
6636 ✗ return;
6637
6638 ✗ if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6639 ✗ trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6640 ✗ trk->has_keyframes++;
6641 }
6642
6643 ✗ return;
6644 }
6645
6646 89 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6647 {
6648 89 MOVMuxContext *mov = s->priv_data;
6649 int ret, buf_size;
6650 uint8_t *buf;
6651 int i, offset;
6652
6653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if (!track->mdat_buf)
6654 ✗ return 0;
6655
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (!mov->mdat_buf) {
6656
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6657 ✗ return ret;
6658 }
6659 89 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6660
6661 89 offset = avio_tell(mov->mdat_buf);
6662 89 avio_write(mov->mdat_buf, buf, buf_size);
6663 89 ffio_reset_dyn_buf(track->mdat_buf);
6664
6665
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 89 times.
177 for (i = track->entries_flushed; i < track->entry; i++)
6666 88 track->cluster[i].pos += offset;
6667 89 track->entries_flushed = track->entry;
6668 89 return 0;
6669 }
6670
6671 28 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6672 {
6673 28 MOVMuxContext *mov = s->priv_data;
6674 28 AVPacket *squashed_packet = mov->pkt;
6675 28 int ret = AVERROR_BUG;
6676
6677
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 switch (track->st->codecpar->codec_id) {
6678 28 case AV_CODEC_ID_TTML: {
6679 28 int had_packets = !!track->squashed_packet_queue.head;
6680
6681
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = ff_mov_generate_squashed_ttml_packet(s, track, squashed_packet)) < 0) {
6682 ✗ goto finish_squash;
6683 }
6684
6685 // We have generated a padding packet (no actual input packets in
6686 // queue) and its duration is zero. Skipping writing it.
6687
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
28 if (!had_packets && squashed_packet->duration == 0) {
6688 ✗ goto finish_squash;
6689 }
6690
6691 28 track->end_reliable = 1;
6692 28 break;
6693 }
6694 ✗ default:
6695 ✗ ret = AVERROR(EINVAL);
6696 ✗ goto finish_squash;
6697 }
6698
6699 28 squashed_packet->stream_index = track->st->index;
6700
6701 28 ret = mov_write_single_packet(s, squashed_packet);
6702
6703 28 finish_squash:
6704 28 av_packet_unref(squashed_packet);
6705
6706 28 return ret;
6707 }
6708
6709 410 static int mov_write_squashed_packets(AVFormatContext *s)
6710 {
6711 410 MOVMuxContext *mov = s->priv_data;
6712
6713
2/2
✓ Branch 0 taken 1083 times.
✓ Branch 1 taken 410 times.
1493 for (int i = 0; i < mov->nb_streams; i++) {
6714 1083 MOVTrack *track = &mov->tracks[i];
6715 1083 int ret = AVERROR_BUG;
6716
6717
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1053 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
1083 if (track->squash_fragment_samples_to_one && !track->entry) {
6718
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6719 ✗ av_log(s, AV_LOG_ERROR,
6720 "Failed to write squashed packet for %s stream with "
6721 "index %d and track id %d. Error: %s\n",
6722 ✗ avcodec_get_name(track->st->codecpar->codec_id),
6723 ✗ track->st->index, track->track_id,
6724 ✗ av_err2str(ret));
6725 ✗ return ret;
6726 }
6727 }
6728 }
6729
6730 410 return 0;
6731 }
6732
6733 391 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6734 int64_t ref_pos)
6735 {
6736 int i;
6737
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 389 times.
391 if (!track->entry)
6738 2 return 0;
6739
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 381 times.
389 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6740
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8 times.
132 for (i = 0; i < track->entry; i++)
6741 124 track->cluster[i].pos += ref_pos + track->data_offset;
6742
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (track->cluster_written == 0) {
6743 // First flush. Chunking for this fragment may already have been
6744 // done, either if we didn't use empty_moov, or if we did use
6745 // delay_moov. In either case, reset chunking here.
6746
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 for (i = 0; i < track->entry; i++) {
6747 63 track->cluster[i].chunkNum = 0;
6748 63 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6749 }
6750 }
6751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (av_reallocp_array(&track->cluster_written,
6752 8 track->entry_written + track->entry,
6753 sizeof(*track->cluster)))
6754 ✗ return AVERROR(ENOMEM);
6755 8 memcpy(&track->cluster_written[track->entry_written],
6756 8 track->cluster, track->entry * sizeof(*track->cluster));
6757 8 track->entry_written += track->entry;
6758 }
6759 389 track->entry = 0;
6760 389 track->entries_flushed = 0;
6761 389 track->end_reliable = 0;
6762 389 return 0;
6763 }
6764
6765 157 static int mov_flush_fragment(AVFormatContext *s, int force)
6766 {
6767 157 MOVMuxContext *mov = s->priv_data;
6768 157 int i, first_track = -1;
6769 157 int64_t mdat_size = 0, mdat_start = 0;
6770 int ret;
6771 157 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6772
6773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
157 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6774 ✗ return 0;
6775
6776 // Check if we have any tracks that require squashing.
6777 // In that case, we'll have to write the packet here.
6778
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 157 times.
157 if ((ret = mov_write_squashed_packets(s)) < 0)
6779 ✗ return ret;
6780
6781 // Try to fill in the duration of the last packet in each stream
6782 // from queued packets in the interleave queues. If the flushing
6783 // of fragments was triggered automatically by an AVPacket, we
6784 // already have reliable info for the end of that track, but other
6785 // tracks may need to be filled in.
6786
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 157 times.
825 for (i = 0; i < mov->nb_streams; i++) {
6787 668 MOVTrack *track = &mov->tracks[i];
6788
2/2
✓ Branch 0 taken 577 times.
✓ Branch 1 taken 91 times.
668 if (!track->end_reliable) {
6789 577 const AVPacket *pkt = ff_interleaved_peek(s, i);
6790
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 571 times.
577 if (pkt) {
6791 int64_t offset, dts, pts;
6792 6 ff_get_muxer_ts_offset(s, i, &offset);
6793 6 pts = pkt->pts + offset;
6794 6 dts = pkt->dts + offset;
6795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6796 ✗ dts += track->dts_shift;
6797 6 track->track_duration = dts - track->start_dts;
6798
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6799 6 track->end_pts = pts;
6800 else
6801 ✗ track->end_pts = dts;
6802
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
6803 6 track->elst_end_pts = track->end_pts;
6804 }
6805 }
6806 }
6807
6808
2/2
✓ Branch 0 taken 674 times.
✓ Branch 1 taken 157 times.
831 for (i = 0; i < mov->nb_tracks; i++) {
6809 674 MOVTrack *track = &mov->tracks[i];
6810
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 487 times.
674 if (track->entry <= 1)
6811 187 continue;
6812 // Sample durations are calculated as the diff of dts values,
6813 // but for the last sample in a fragment, we don't know the dts
6814 // of the first sample in the next fragment, so we have to rely
6815 // on what was set as duration in the AVPacket. Not all callers
6816 // set this though, so we might want to replace it with an
6817 // estimate if it currently is zero.
6818
2/2
✓ Branch 1 taken 485 times.
✓ Branch 2 taken 2 times.
487 if (get_cluster_duration(track, track->entry - 1) != 0)
6819 485 continue;
6820 // Use the duration (i.e. dts diff) of the second last sample for
6821 // the last one. This is a wild guess (and fatal if it turns out
6822 // to be too long), but probably the best we can do - having a zero
6823 // duration is bad as well.
6824 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6825 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6826
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6827 2 av_log(s, AV_LOG_WARNING,
6828 "Estimating the duration of the last packet in a "
6829 "fragment, consider setting the duration field in "
6830 "AVPacket instead.\n");
6831 2 mov->missing_duration_warned = 1;
6832 }
6833 }
6834
6835
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 127 times.
157 if (!mov->moov_written) {
6836 30 int64_t pos = avio_tell(s->pb);
6837 uint8_t *buf;
6838 int buf_size, moov_size;
6839
6840
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 23 times.
174 for (i = 0; i < mov->nb_tracks; i++)
6841
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 144 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
151 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6842 7 break;
6843 /* Don't write the initial moov unless all tracks have data */
6844
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
30 if (i < mov->nb_tracks && !force)
6845 4 return 0;
6846
6847 26 moov_size = get_moov_size(s);
6848
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 26 times.
172 for (i = 0; i < mov->nb_tracks; i++)
6849 146 mov->tracks[i].data_offset = pos + moov_size + 8;
6850
6851 26 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6852
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 5 times.
26 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV &&
6853
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 !(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
6854 21 mov_write_identification(s->pb, s);
6855
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6856 ✗ return ret;
6857
6858
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 5 times.
26 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6860 ✗ mov->reserved_header_pos = avio_tell(s->pb);
6861 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6862 21 mov->moov_written = 1;
6863 21 return 0;
6864 }
6865
6866
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (mov->mdat_buf) {
6867 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6868 4 avio_wb32(s->pb, buf_size + 8);
6869 4 ffio_wfourcc(s->pb, "mdat");
6870 4 avio_write(s->pb, buf, buf_size);
6871 4 ffio_reset_dyn_buf(mov->mdat_buf);
6872 }
6873
6874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6875 ✗ mov->reserved_header_pos = avio_tell(s->pb);
6876
6877 5 mov->moov_written = 1;
6878 5 mov->mdat_size = 0;
6879
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (i = 0; i < mov->nb_tracks; i++)
6880 10 mov_finish_fragment(mov, &mov->tracks[i], 0);
6881 5 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6882 5 return 0;
6883 }
6884
6885
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 125 times.
127 if (mov->frag_interleave) {
6886
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
6887 4 MOVTrack *track = &mov->tracks[i];
6888 int ret;
6889
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6890 ✗ return ret;
6891 }
6892
6893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!mov->mdat_buf)
6894 ✗ return 0;
6895 2 mdat_size = avio_tell(mov->mdat_buf);
6896 }
6897
6898
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 127 times.
649 for (i = 0; i < mov->nb_tracks; i++) {
6899 522 MOVTrack *track = &mov->tracks[i];
6900
4/4
✓ Branch 0 taken 477 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 473 times.
522 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6901 49 track->data_offset = 0;
6902 else
6903 473 track->data_offset = mdat_size;
6904
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 410 times.
522 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6905 112 has_video = 1;
6906
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (first_video_track) {
6907
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 16 times.
112 if (track->entry)
6908 96 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6909 112 first_video_track = 0;
6910 }
6911 }
6912
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 381 times.
522 if (!track->entry)
6913 141 continue;
6914
1/2
✓ Branch 0 taken 381 times.
✗ Branch 1 not taken.
381 if (track->mdat_buf)
6915 381 mdat_size += avio_tell(track->mdat_buf);
6916
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 275 times.
381 if (first_track < 0)
6917 106 first_track = i;
6918 }
6919
6920
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 106 times.
127 if (!mdat_size)
6921 21 return 0;
6922
6923
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 4 times.
106 avio_write_marker(s->pb,
6924 106 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6925
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 9 times.
106 (has_video ? starts_with_key : mov->tracks[first_track].cluster[0].flags & MOV_SYNC_SAMPLE) ? AVIO_DATA_MARKER_SYNC_POINT : AVIO_DATA_MARKER_BOUNDARY_POINT);
6926
6927
2/2
✓ Branch 0 taken 389 times.
✓ Branch 1 taken 106 times.
495 for (i = first_track; i < mov->nb_tracks; i++) {
6928 389 MOVTrack *track = &mov->tracks[i];
6929 389 int buf_size, write_moof = 1, moof_tracks = -1;
6930 uint8_t *buf;
6931
6932
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 381 times.
389 if (!track->entry)
6933 8 continue;
6934
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 340 times.
381 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6935 41 mdat_size = avio_tell(track->mdat_buf);
6936 41 moof_tracks = i;
6937 } else {
6938 340 write_moof = i == first_track;
6939 }
6940
6941
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 258 times.
381 if (write_moof) {
6942 123 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6943
6944 123 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6945 123 mov->fragments++;
6946
6947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 if (track->cenc.aes_ctr)
6948 ✗ ff_mov_cenc_flush(&track->cenc);
6949
6950 123 avio_wb32(s->pb, mdat_size + 8);
6951 123 ffio_wfourcc(s->pb, "mdat");
6952 123 mdat_start = avio_tell(s->pb);
6953 }
6954
6955 381 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6956
2/2
✓ Branch 0 taken 378 times.
✓ Branch 1 taken 3 times.
381 if (!mov->frag_interleave) {
6957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 378 times.
378 if (!track->mdat_buf)
6958 ✗ continue;
6959 378 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6960 378 avio_write(s->pb, buf, buf_size);
6961 378 ffio_reset_dyn_buf(track->mdat_buf);
6962 } else {
6963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!mov->mdat_buf)
6964 ✗ continue;
6965 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6966 3 avio_write(s->pb, buf, buf_size);
6967 3 ffio_reset_dyn_buf(mov->mdat_buf);
6968 }
6969 }
6970
6971 106 mov->mdat_size = 0;
6972
6973 106 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6974 106 return 0;
6975 }
6976
6977 100 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6978 {
6979 100 MOVMuxContext *mov = s->priv_data;
6980 100 int had_moov = mov->moov_written;
6981 100 int ret = mov_flush_fragment(s, force);
6982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (ret < 0)
6983 ✗ return ret;
6984 // If using delay_moov, the first flush only wrote the moov,
6985 // not the actual moof+mdat pair, thus flush once again.
6986
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
100 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6987 10 ret = mov_flush_fragment(s, force);
6988 100 return ret;
6989 }
6990
6991 53555 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6992 {
6993 int64_t ref;
6994 uint64_t duration;
6995
6996
2/2
✓ Branch 0 taken 52346 times.
✓ Branch 1 taken 1209 times.
53555 if (trk->entry) {
6997 52346 ref = trk->cluster[trk->entry - 1].dts;
6998
2/2
✓ Branch 0 taken 393 times.
✓ Branch 1 taken 816 times.
1209 } else if ( trk->start_dts != AV_NOPTS_VALUE
6999
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 8 times.
393 && !trk->frag_discont) {
7000 385 ref = trk->start_dts + trk->track_duration;
7001 } else
7002 824 ref = pkt->dts; // Skip tests for the first packet
7003
7004
2/2
✓ Branch 0 taken 4055 times.
✓ Branch 1 taken 49500 times.
53555 if (trk->dts_shift != AV_NOPTS_VALUE) {
7005 /* With negative CTS offsets we have set an offset to the DTS,
7006 * reverse this for the check. */
7007 4055 ref -= trk->dts_shift;
7008 }
7009
7010 53555 duration = pkt->dts - ref;
7011
2/4
✓ Branch 0 taken 53555 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53555 times.
53555 if (pkt->dts < ref || duration >= INT_MAX) {
7012 ✗ av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
7013 duration, pkt->dts, pkt->stream_index);
7014
7015 ✗ pkt->dts = ref + 1;
7016 ✗ pkt->pts = AV_NOPTS_VALUE;
7017 }
7018
7019
2/4
✓ Branch 0 taken 53555 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53555 times.
53555 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
7020 ✗ av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
7021 ✗ return AVERROR(EINVAL);
7022 }
7023 53555 return 0;
7024 }
7025
7026 7 int ff_mov_set_fragment_end_hint(AVFormatContext *s, int stream_index,
7027 const AVPacket *pkt, AVRational src_time_base)
7028 {
7029 7 MOVMuxContext *mov = s->priv_data;
7030 AVStream *st;
7031 MOVTrack *track;
7032 int64_t offset, dts, pts, candidate_duration;
7033
7034
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
7035
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 stream_index < 0 || stream_index >= s->nb_streams ||
7036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 pkt->dts == AV_NOPTS_VALUE)
7037 ✗ return 0;
7038
7039 7 st = s->streams[stream_index];
7040 7 track = st->priv_data;
7041
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (!track->entry || track->start_dts == AV_NOPTS_VALUE)
7042 ✗ return 0;
7043
7044
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if (ff_get_muxer_ts_offset(s, stream_index, &offset) < 0)
7045 ✗ return 0;
7046
7047 7 dts = av_rescale_q(pkt->dts, src_time_base, st->time_base) + offset;
7048 14 pts = pkt->pts == AV_NOPTS_VALUE
7049 ? AV_NOPTS_VALUE
7050
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 : av_rescale_q(pkt->pts, src_time_base, st->time_base) + offset;
7051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (track->dts_shift != AV_NOPTS_VALUE)
7052 ✗ dts += track->dts_shift;
7053
7054 7 candidate_duration = dts - track->start_dts;
7055
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (dts <= track->cluster[track->entry - 1].dts ||
7056
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 candidate_duration < 0 || candidate_duration >= track->track_duration)
7057 7 return 0;
7058
7059 ✗ track->track_duration = candidate_duration;
7060 ✗ track->end_pts = pts != AV_NOPTS_VALUE ? pts : dts;
7061 ✗ if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7062 ✗ track->elst_end_pts = track->end_pts;
7063 ✗ track->end_reliable = 1;
7064
7065 ✗ return 1;
7066 }
7067
7068 26796 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7069 {
7070 26796 MOVMuxContext *mov = s->priv_data;
7071 26796 AVIOContext *pb = s->pb;
7072 MOVTrack *trk;
7073 AVCodecParameters *par;
7074 AVProducerReferenceTime *prft;
7075 26796 unsigned int samples_in_chunk = 0;
7076 int64_t duration;
7077 26796 int size = pkt->size, ret = 0, offset = 0;
7078 size_t prft_size;
7079 26796 uint8_t *reformatted_data = NULL;
7080
7081
2/2
✓ Branch 0 taken 26750 times.
✓ Branch 1 taken 46 times.
26796 if (pkt->stream_index < s->nb_streams)
7082 26750 trk = s->streams[pkt->stream_index]->priv_data;
7083 else // Timecode or chapter
7084 46 trk = &mov->tracks[pkt->stream_index];
7085 26796 par = trk->par;
7086
7087 26796 ret = check_pkt(s, trk, pkt);
7088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26796 times.
26796 if (ret < 0)
7089 ✗ return ret;
7090
7091
2/2
✓ Branch 0 taken 26175 times.
✓ Branch 1 taken 621 times.
26796 if (pkt->pts != AV_NOPTS_VALUE &&
7092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26175 times.
26175 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
7093 ✗ av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
7094 ✗ return AVERROR_PATCHWELCOME;
7095 }
7096
7097
3/4
✓ Branch 0 taken 17378 times.
✓ Branch 1 taken 9418 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17378 times.
26796 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
7098 int ret;
7099
4/4
✓ Branch 0 taken 3576 times.
✓ Branch 1 taken 5842 times.
✓ Branch 2 taken 3338 times.
✓ Branch 3 taken 238 times.
9418 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
7100
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 9092 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
9180 if (mov->frag_interleave && mov->fragments > 0) {
7101
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 3 times.
88 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
7102
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
85 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
7103 ✗ return ret;
7104 }
7105 }
7106
7107
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 9006 times.
9180 if (!trk->mdat_buf) {
7108
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
7109 ✗ return ret;
7110 }
7111 9180 pb = trk->mdat_buf;
7112 } else {
7113
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
7114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
7115 ✗ return ret;
7116 }
7117 238 pb = mov->mdat_buf;
7118 }
7119 }
7120
7121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26796 times.
26796 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
7122 /* We must find out how many AMR blocks there are in one packet */
7123 static const uint16_t packed_size[16] =
7124 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
7125 ✗ int len = 0;
7126
7127 ✗ while (len < size && samples_in_chunk < 100) {
7128 ✗ len += packed_size[(pkt->data[len] >> 3) & 0x0F];
7129 ✗ samples_in_chunk++;
7130 }
7131 ✗ if (samples_in_chunk > 1) {
7132 ✗ av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
7133 ✗ return -1;
7134 }
7135
1/2
✓ Branch 0 taken 26796 times.
✗ Branch 1 not taken.
26796 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
7136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26796 times.
26796 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
7137 ✗ samples_in_chunk = trk->par->frame_size;
7138
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 25382 times.
26796 } else if (trk->sample_size)
7139 1414 samples_in_chunk = size / trk->sample_size;
7140 else
7141 25382 samples_in_chunk = 1;
7142
7143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26796 times.
26796 if (samples_in_chunk < 1) {
7144 ✗ av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
7145 ✗ return AVERROR_PATCHWELCOME;
7146 }
7147
7148 /* copy extradata if it exists */
7149
3/4
✓ Branch 0 taken 10213 times.
✓ Branch 1 taken 16583 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10213 times.
26796 if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
7150 ✗ !TAG_IS_AVCI(trk->tag) &&
7151 ✗ (par->codec_id != AV_CODEC_ID_DNXHD)) {
7152 ✗ trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
7153 ✗ if (!trk->extradata[0]) {
7154 ✗ ret = AVERROR(ENOMEM);
7155 ✗ goto err;
7156 }
7157 ✗ trk->extradata_size[0] = par->extradata_size;
7158 }
7159
7160
2/2
✓ Branch 0 taken 26681 times.
✓ Branch 1 taken 115 times.
26796 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
7161
2/2
✓ Branch 0 taken 24037 times.
✓ Branch 1 taken 2644 times.
26681 par->codec_id == AV_CODEC_ID_H264 ||
7162
2/2
✓ Branch 0 taken 23665 times.
✓ Branch 1 taken 372 times.
24037 par->codec_id == AV_CODEC_ID_HEVC ||
7163
2/2
✓ Branch 0 taken 23655 times.
✓ Branch 1 taken 10 times.
23665 par->codec_id == AV_CODEC_ID_VVC ||
7164
1/2
✓ Branch 0 taken 23655 times.
✗ Branch 1 not taken.
23655 par->codec_id == AV_CODEC_ID_VP9 ||
7165
2/2
✓ Branch 0 taken 23355 times.
✓ Branch 1 taken 300 times.
23655 par->codec_id == AV_CODEC_ID_EVC ||
7166
2/2
✓ Branch 0 taken 23325 times.
✓ Branch 1 taken 30 times.
23355 par->codec_id == AV_CODEC_ID_LCEVC ||
7167
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23325 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3447 times.
26796 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
7168
14/28
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 24 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 24 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 24 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 24 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 24 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 24 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 24 times.
✗ Branch 27 not taken.
24 !TAG_IS_AVCI(trk->tag)) {
7169 /* copy frame to create needed atoms */
7170 24 trk->extradata_size[0] = size;
7171 24 trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
7172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->extradata[0]) {
7173 ✗ ret = AVERROR(ENOMEM);
7174 ✗ goto err;
7175 }
7176 24 memcpy(trk->extradata[0], pkt->data, size);
7177 24 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7178 }
7179
7180 26796 const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
7181
4/6
✓ Branch 0 taken 26796 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 26793 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
26796 if (pkt->size && sd && sd->size > 0) {
7182 int i;
7183
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < trk->stsd_count; i++) {
7184
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
7185 1 break;
7186 }
7187
7188
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (i < trk->stsd_count)
7189 1 trk->last_stsd_index = i;
7190
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (trk->stsd_count <= INT_MAX - 1) {
7191 2 int new_count = trk->stsd_count + 1;
7192 2 uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
7193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata)
7194 ✗ return AVERROR(ENOMEM);
7195 2 trk->extradata = extradata;
7196
7197 2 int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
7198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!extradata_size)
7199 ✗ return AVERROR(ENOMEM);
7200 2 trk->extradata_size = extradata_size;
7201
7202 2 trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
7203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->extradata[trk->stsd_count])
7204 ✗ return AVERROR(ENOMEM);
7205
7206 2 trk->extradata_size[trk->stsd_count] = sd->size;
7207 2 trk->last_stsd_index = trk->stsd_count;
7208 2 trk->stsd_count = new_count;
7209 } else
7210 ✗ return AVERROR(ENOMEM);
7211 }
7212
7213
3/4
✓ Branch 0 taken 9008 times.
✓ Branch 1 taken 17788 times.
✓ Branch 2 taken 9008 times.
✗ Branch 3 not taken.
26796 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
7214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9008 times.
9008 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
7215 ✗ if (!trk->st->nb_frames) {
7216 ✗ av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
7217 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
7218 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
7219 ✗ return -1;
7220 }
7221 ✗ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
7222 }
7223
3/4
✓ Branch 0 taken 2644 times.
✓ Branch 1 taken 24152 times.
✓ Branch 2 taken 2644 times.
✗ Branch 3 not taken.
26796 if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
7224
16/30
✓ Branch 0 taken 545 times.
✓ Branch 1 taken 2099 times.
✓ Branch 2 taken 545 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 545 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 545 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 545 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 545 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 545 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 545 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 545 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 545 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 545 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 545 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 545 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 545 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 545 times.
✗ Branch 29 not taken.
2644 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
7225 /* from x264 or from bytestream H.264 */
7226 /* NAL reformatting needed */
7227
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 545 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
545 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7228 ✗ ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
7229 &size);
7230 ✗ if (ret < 0)
7231 ✗ return ret;
7232 ✗ avio_write(pb, reformatted_data, size);
7233 } else {
7234
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 528 times.
545 if (trk->cenc.aes_ctr) {
7235 17 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (size < 0) {
7237 ✗ ret = size;
7238 ✗ goto err;
7239 }
7240 } else {
7241 528 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7242 }
7243 }
7244
3/4
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 25879 times.
✓ Branch 2 taken 372 times.
✗ Branch 3 not taken.
26251 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7245
3/4
✓ Branch 0 taken 372 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 355 times.
✓ Branch 3 taken 17 times.
727 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7246 /* extradata is Annex B, assume the bitstream is too and convert it */
7247 355 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
7248
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
355 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7249 ✗ ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
7250 &size, filter_ps, NULL);
7251 ✗ if (ret < 0)
7252 ✗ return ret;
7253 ✗ avio_write(pb, reformatted_data, size);
7254 } else {
7255
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 354 times.
355 if (trk->cenc.aes_ctr) {
7256 1 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (size < 0) {
7258 ✗ ret = size;
7259 ✗ goto err;
7260 }
7261 } else {
7262 354 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
7263 }
7264 }
7265
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 25886 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
25896 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
7266
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
7267 /* extradata is Annex B, assume the bitstream is too and convert it */
7268
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7269 ✗ ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
7270 &size, 0, NULL);
7271 ✗ if (ret < 0)
7272 ✗ return ret;
7273 ✗ avio_write(pb, reformatted_data, size);
7274 } else {
7275 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
7276 }
7277
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 25856 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
25886 } else if (par->codec_id == AV_CODEC_ID_LCEVC && trk->extradata_size[trk->last_stsd_index] > 0 &&
7278
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 *(uint8_t *)trk->extradata[trk->last_stsd_index] != 1) {
7279 /* extradata is Annex B, assume the bitstream is too and convert it */
7280
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
30 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7281 ✗ ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size);
7282 ✗ if (ret < 0)
7283 ✗ return ret;
7284 ✗ avio_write(pb, reformatted_data, size);
7285 } else {
7286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (trk->cenc.aes_ctr) {
7287 ✗ size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
7288 ✗ if (size < 0) {
7289 ✗ ret = size;
7290 ✗ goto err;
7291 }
7292 } else {
7293 30 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
7294 }
7295 }
7296
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 25828 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 24 times.
25856 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
7297
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
7298 ✗ ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
7299 &size, &offset);
7300 ✗ if (ret < 0)
7301 ✗ return ret;
7302 ✗ avio_write(pb, reformatted_data, size);
7303 } else {
7304 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
7305
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 if (trk->mode == MODE_AVIF && !mov->avif_extent_length[pkt->stream_index]) {
7306 ✗ mov->avif_extent_length[pkt->stream_index] = size;
7307 }
7308 }
7309
7310
2/2
✓ Branch 0 taken 25229 times.
✓ Branch 1 taken 623 times.
25852 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
7311
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 24115 times.
25229 par->codec_id == AV_CODEC_ID_EAC3) {
7312 1737 size = handle_eac3(mov, pkt, trk);
7313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1737 times.
1737 if (size < 0)
7314 ✗ return size;
7315
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1736 times.
1737 else if (!size)
7316 1 goto end;
7317 1736 avio_write(pb, pkt->data, size);
7318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24115 times.
24115 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
7319 ✗ size = 8;
7320
7321 ✗ for (int i = 0; i < pkt->size; i += 3) {
7322 ✗ if (pkt->data[i] == 0xFC) {
7323 ✗ size += 2;
7324 }
7325 }
7326 ✗ avio_wb32(pb, size);
7327 ✗ ffio_wfourcc(pb, "cdat");
7328 ✗ for (int i = 0; i < pkt->size; i += 3) {
7329 ✗ if (pkt->data[i] == 0xFC) {
7330 ✗ avio_w8(pb, pkt->data[i + 1]);
7331 ✗ avio_w8(pb, pkt->data[i + 2]);
7332 }
7333 }
7334
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24112 times.
24115 } else if (par->codec_id == AV_CODEC_ID_APV) {
7335 3 ff_isom_parse_apvc(trk->apv, pkt, s);
7336 3 avio_wb32(s->pb, pkt->size);
7337 3 size += 4;
7338
7339 3 avio_write(s->pb, pkt->data, pkt->size);
7340 } else {
7341
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 24079 times.
24112 if (trk->cenc.aes_ctr) {
7342 33 uint8_t *extradata = trk->extradata[trk->last_stsd_index];
7343 33 int extradata_size = trk->extradata_size[trk->last_stsd_index];
7344
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
38 if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
7345 5 int nal_size_length = (extradata[4] & 0x3) + 1;
7346 5 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7347
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
32 } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
7348 4 int nal_size_length = (extradata[21] & 0x3) + 1;
7349 4 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
7350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 } else if(par->codec_id == AV_CODEC_ID_VVC) {
7351 ✗ ret = AVERROR_PATCHWELCOME;
7352
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if(par->codec_id == AV_CODEC_ID_AV1) {
7353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 av_assert0(size == pkt->size);
7354 24 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
7355
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (ret > 0) {
7356 24 size = ret;
7357 24 ret = 0;
7358 }
7359 } else {
7360 ✗ ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
7361 }
7362
7363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
7364 ✗ goto err;
7365 }
7366 } else {
7367 24079 avio_write(pb, pkt->data, size);
7368 }
7369 }
7370
7371
2/2
✓ Branch 0 taken 419 times.
✓ Branch 1 taken 26376 times.
26795 if (trk->entry >= trk->cluster_capacity) {
7372 419 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
7373 419 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
7374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 419 times.
419 if (!cluster) {
7375 ✗ ret = AVERROR(ENOMEM);
7376 ✗ goto err;
7377 }
7378 419 trk->cluster = cluster;
7379 419 trk->cluster_capacity = new_capacity;
7380 }
7381
7382 26795 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
7383 26795 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
7384 26795 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
7385 26795 trk->cluster[trk->entry].chunkNum = 0;
7386 26795 trk->cluster[trk->entry].size = size;
7387 26795 trk->cluster[trk->entry].entries = samples_in_chunk;
7388 26795 trk->cluster[trk->entry].dts = pkt->dts;
7389 26795 trk->cluster[trk->entry].pts = pkt->pts;
7390
2/2
✓ Branch 0 taken 26767 times.
✓ Branch 1 taken 28 times.
26795 if (!trk->squash_fragment_samples_to_one &&
7391
4/4
✓ Branch 0 taken 605 times.
✓ Branch 1 taken 26162 times.
✓ Branch 2 taken 204 times.
✓ Branch 3 taken 401 times.
26767 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
7392
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 4 times.
204 if (!trk->frag_discont) {
7393 /* First packet of a new fragment. We already wrote the duration
7394 * of the last packet of the previous fragment based on track_duration,
7395 * which might not exactly match our dts. Therefore adjust the dts
7396 * of this packet to be what the previous packets duration implies. */
7397 200 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
7398 /* We also may have written the pts and the corresponding duration
7399 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
7400 * the next fragment. This means the cts of the first sample must
7401 * be the same in all fragments, unless end_pts was updated by
7402 * the packet causing the fragment to be written. */
7403
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 84 times.
200 if ((mov->flags & FF_MOV_FLAG_DASH &&
7404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
116 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
7405
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 62 times.
84 mov->mode == MODE_ISM)
7406 138 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
7407 } else {
7408 /* New fragment, but discontinuous from previous fragments.
7409 * Pretend the duration sum of the earlier fragments is
7410 * pkt->dts - trk->start_dts. */
7411 4 trk->end_pts = trk->elst_end_pts = AV_NOPTS_VALUE;
7412 4 trk->frag_discont = 0;
7413 }
7414 }
7415
7416
6/6
✓ Branch 0 taken 633 times.
✓ Branch 1 taken 26162 times.
✓ Branch 2 taken 405 times.
✓ Branch 3 taken 228 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 367 times.
26795 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
7417
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 15 times.
38 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
7418 /* Not using edit lists and shifting the first track to start from zero.
7419 * If the other streams start from a later timestamp, we won't be able
7420 * to signal the difference in starting time without an edit list.
7421 * Thus move the timestamp for this first sample to 0, increasing
7422 * its duration instead. */
7423 23 trk->cluster[trk->entry].dts = trk->start_dts = 0;
7424 }
7425
2/2
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 26413 times.
26795 if (trk->start_dts == AV_NOPTS_VALUE) {
7426 382 trk->start_dts = pkt->dts;
7427
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 376 times.
382 if (trk->frag_discont) {
7428
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
7429 /* Pretend the whole stream started at pts=0, with earlier fragments
7430 * already written. If the stream started at pts=0, the duration sum
7431 * of earlier fragments would have been pkt->pts. */
7432 4 trk->start_dts = pkt->dts - pkt->pts;
7433 } else {
7434 /* Pretend the whole stream started at dts=0, with earlier fragments
7435 * already written, with a duration summing up to pkt->dts. */
7436 2 trk->start_dts = 0;
7437 }
7438 6 trk->frag_discont = 0;
7439
4/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 320 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 54 times.
376 } else if (pkt->dts && mov->moov_written)
7440 2 av_log(s, AV_LOG_WARNING,
7441 "Track %d starts with a nonzero dts %"PRId64", while the moov "
7442 "already has been written. Set the delay_moov flag to handle "
7443 "this case.\n",
7444 pkt->stream_index, pkt->dts);
7445 }
7446
7447 26795 sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
7448
5/6
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 26751 times.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 1 times.
26838 if (sd && sd->size >= 10 && trk->par->frame_size) {
7449
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 23 times.
43 duration = FFMAX(av_rescale_q(trk->par->frame_size, (AVRational){ 1, trk->par->sample_rate },
7450 trk->st->time_base), pkt->duration);
7451
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 if (mov->use_editlist)
7452 43 pkt->duration = duration;
7453 43 duration -= av_rescale_q(AV_RL32(sd->data + 4), (AVRational){ 1, trk->par->sample_rate },
7454 43 trk->st->time_base);
7455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 if (duration < 0)
7456 ✗ return AVERROR_INVALIDDATA;
7457 } else
7458 26752 duration = pkt->duration;
7459
7460 26795 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
7461 26795 trk->last_sample_is_subtitle_end = 0;
7462
7463
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 26174 times.
26795 if (pkt->pts == AV_NOPTS_VALUE) {
7464 621 av_log(s, AV_LOG_WARNING, "pts has no value\n");
7465 621 pkt->pts = pkt->dts;
7466 }
7467
2/2
✓ Branch 0 taken 1449 times.
✓ Branch 1 taken 25346 times.
26795 if (pkt->dts != pkt->pts)
7468 1449 trk->flags |= MOV_TRACK_CTTS;
7469 26795 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
7470 26795 trk->cluster[trk->entry].flags = 0;
7471
6/6
✓ Branch 0 taken 26390 times.
✓ Branch 1 taken 405 times.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 26316 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 69 times.
26795 if (trk->start_cts == AV_NOPTS_VALUE || (pkt->dts <= 0 && trk->start_cts > pkt->pts - pkt->dts))
7472 410 trk->start_cts = pkt->pts - pkt->dts;
7473
2/2
✓ Branch 0 taken 409 times.
✓ Branch 1 taken 26386 times.
26795 if (trk->end_pts == AV_NOPTS_VALUE)
7474 409 trk->end_pts = trk->cluster[trk->entry].dts +
7475 409 trk->cluster[trk->entry].cts + duration;
7476 else
7477 26386 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
7478 trk->cluster[trk->entry].cts +
7479 duration);
7480
2/2
✓ Branch 0 taken 26792 times.
✓ Branch 1 taken 3 times.
26795 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7481 26792 trk->elst_end_pts = trk->end_pts;
7482
7483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26795 times.
26795 if (par->codec_id == AV_CODEC_ID_VC1) {
7484 ✗ mov_parse_vc1_frame(pkt, trk);
7485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26795 times.
26795 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
7486 ✗ mov_parse_truehd_frame(pkt, trk);
7487
2/2
✓ Branch 0 taken 20677 times.
✓ Branch 1 taken 6118 times.
26795 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
7488
4/4
✓ Branch 0 taken 6267 times.
✓ Branch 1 taken 14410 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6258 times.
20677 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
7489
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
7490 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
7491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
7492 ✗ trk->flags |= MOV_TRACK_STPS;
7493 } else {
7494 20669 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
7495 }
7496
1/2
✓ Branch 0 taken 20677 times.
✗ Branch 1 not taken.
20677 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
7497 20677 trk->has_keyframes++;
7498 }
7499
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 26788 times.
26795 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
7500 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
7501 7 trk->has_disposable++;
7502 }
7503
7504 26795 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
7505
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26795 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26795 if (prft && prft_size == sizeof(AVProducerReferenceTime))
7506 ✗ memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
7507 else
7508 26795 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
7509
7510 26795 trk->entry++;
7511 26795 trk->sample_count += samples_in_chunk;
7512 26795 mov->mdat_size += size;
7513
7514
3/4
✓ Branch 0 taken 26713 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
26795 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
7515 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
7516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
7517 : NULL, size);
7518
7519 26796 end:
7520 26796 err:
7521
7522
1/2
✓ Branch 0 taken 26796 times.
✗ Branch 1 not taken.
26796 if (pkt->data != reformatted_data)
7523 26796 av_free(reformatted_data);
7524 26796 return ret;
7525 }
7526
7527 26759 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
7528 {
7529 26759 MOVMuxContext *mov = s->priv_data;
7530 26759 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
7531 26759 AVCodecParameters *par = trk->par;
7532 26759 int64_t frag_duration = 0;
7533 26759 int size = pkt->size;
7534
7535 26759 int ret = check_pkt(s, trk, pkt);
7536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26759 times.
26759 if (ret < 0)
7537 ✗ return ret;
7538
7539
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 26754 times.
26759 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
7540
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
7541 10 mov->tracks[i].frag_discont = 1;
7542 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7543 }
7544
7545
2/2
✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 24747 times.
26759 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7546
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1997 times.
2012 if (trk->dts_shift == AV_NOPTS_VALUE)
7547 15 trk->dts_shift = pkt->pts - pkt->dts;
7548 2012 pkt->dts += trk->dts_shift;
7549 }
7550
7551
1/2
✓ Branch 0 taken 26759 times.
✗ Branch 1 not taken.
26759 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7552
2/2
✓ Branch 0 taken 17749 times.
✓ Branch 1 taken 9010 times.
26759 trk->par->codec_id == AV_CODEC_ID_AAC ||
7553
2/2
✓ Branch 0 taken 17721 times.
✓ Branch 1 taken 28 times.
17749 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7554
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 17661 times.
17721 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7555 size_t side_size;
7556 9098 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7557 /* Overwrite extradata only on flush packets or when no extradata was available during init */
7558
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9092 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
9098 if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
7559 6 void *newextra = av_malloc(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7561 ✗ return AVERROR(ENOMEM);
7562 6 memset((uint8_t*)newextra + side_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7563 6 memcpy(newextra, side, side_size);
7564 6 av_free(trk->extradata[trk->last_stsd_index]);
7565 6 trk->extradata[trk->last_stsd_index] = newextra;
7566 6 trk->extradata_size[trk->last_stsd_index] = side_size;
7567 }
7568 }
7569
7570
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26750 times.
26759 if (!pkt->size) {
7571
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
9 if (trk->start_dts == AV_NOPTS_VALUE && trk->frag_discont) {
7572 4 trk->start_dts = pkt->dts;
7573
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7574 4 trk->start_cts = pkt->pts - pkt->dts;
7575 else
7576 ✗ trk->start_cts = 0;
7577 }
7578
7579 9 return 0; /* Discard 0 sized packets */
7580 }
7581
7582
4/4
✓ Branch 0 taken 26179 times.
✓ Branch 1 taken 571 times.
✓ Branch 2 taken 26155 times.
✓ Branch 3 taken 24 times.
26750 if (trk->entry && pkt->stream_index < mov->nb_streams)
7583 26155 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7584 26155 s->streams[pkt->stream_index]->time_base,
7585 26155 AV_TIME_BASE_Q);
7586
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 26489 times.
26750 if ((mov->max_fragment_duration &&
7587
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
261 frag_duration >= mov->max_fragment_duration) ||
7588
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26746 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26746 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7589
2/2
✓ Branch 0 taken 4895 times.
✓ Branch 1 taken 21851 times.
26746 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7590
2/2
✓ Branch 0 taken 2321 times.
✓ Branch 1 taken 2574 times.
4895 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7591
4/4
✓ Branch 0 taken 2293 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 2242 times.
✓ Branch 3 taken 51 times.
2321 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7592
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26694 times.
26695 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7593
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (frag_duration >= mov->min_fragment_duration) {
7594
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 1 times.
56 if (trk->entry) {
7595 // Set the duration of this track to line up with the next
7596 // sample in this track. This avoids relying on AVPacket
7597 // duration, but only helps for this particular track, not
7598 // for the other ones that are flushed at the same time.
7599 //
7600 // If we have trk->entry == 0, no fragment will be written
7601 // for this track, and we can't adjust the track end here.
7602 55 trk->track_duration = pkt->dts - trk->start_dts;
7603
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (pkt->pts != AV_NOPTS_VALUE)
7604 55 trk->end_pts = pkt->pts;
7605 else
7606 ✗ trk->end_pts = pkt->dts;
7607
1/2
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
55 if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
7608 55 trk->elst_end_pts = trk->end_pts;
7609 55 trk->end_reliable = 1;
7610 }
7611 56 mov_auto_flush_fragment(s, 0);
7612 }
7613 }
7614
7615 26750 return ff_mov_write_packet(s, pkt);
7616 }
7617
7618 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7619 int stream_index,
7620 int64_t dts) {
7621 3 MOVMuxContext *mov = s->priv_data;
7622 3 AVPacket *end = mov->pkt;
7623 3 uint8_t data[2] = {0};
7624 int ret;
7625
7626 3 end->size = sizeof(data);
7627 3 end->data = data;
7628 3 end->pts = dts;
7629 3 end->dts = dts;
7630 3 end->duration = 0;
7631 3 end->stream_index = stream_index;
7632
7633 3 ret = mov_write_single_packet(s, end);
7634 3 av_packet_unref(end);
7635
7636 3 return ret;
7637 }
7638
7639 #if CONFIG_IAMFENC
7640 300 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7641 {
7642 uint8_t *data;
7643 int ret;
7644
7645
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 240 times.
300 if (pkt->stream_index == trk->first_iamf_idx) {
7646 60 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (ret < 0)
7648 ✗ return ret;
7649 }
7650
7651 300 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7652 300 s->streams[pkt->stream_index]->id, pkt);
7653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (ret < 0)
7654 ✗ return ret;
7655
7656
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (pkt->stream_index != trk->last_iamf_idx)
7657 240 return AVERROR(EAGAIN);
7658
7659 60 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7660 60 trk->iamf_buf = NULL;
7661
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
60 if (!ret) {
7662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7663 // Either all or none of the packets for a single
7664 // IA Sample may be empty.
7665 ✗ av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7666 "stream #%d\n", pkt->stream_index);
7667 ✗ ret = AVERROR_INVALIDDATA;
7668 }
7669 5 av_free(data);
7670 5 return ret;
7671 }
7672
7673 55 av_buffer_unref(&pkt->buf);
7674 55 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (!pkt->buf) {
7676 ✗ av_free(data);
7677 ✗ return AVERROR(ENOMEM);
7678 }
7679 55 pkt->data = data;
7680 55 pkt->size = ret;
7681 55 pkt->stream_index = trk->first_iamf_idx;
7682
7683 55 return avio_open_dyn_buf(&trk->iamf_buf);
7684 }
7685 #endif
7686
7687 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7688 {
7689 2 int64_t pos = avio_tell(pb);
7690 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7691 2 const char *value = "";
7692
7693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7694
7695 2 avio_write_marker(pb,
7696 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7697 AVIO_DATA_MARKER_BOUNDARY_POINT);
7698
7699 2 avio_wb32(pb, 0); /* size */
7700 2 ffio_wfourcc(pb, "emsg");
7701 2 avio_w8(pb, 1); /* version */
7702 2 avio_wb24(pb, 0);
7703 2 avio_wb32(pb, st->time_base.den); /* timescale */
7704 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7705 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7706 2 avio_wb32(pb, 0); /* id */
7707 /* null terminated UTF8 strings */
7708 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7709 2 avio_write(pb, value, strlen(value) + 1);
7710 2 avio_write(pb, pkt->data, pkt->size);
7711
7712 2 return update_size(pb, pos);
7713 }
7714
7715 27167 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7716 {
7717 27167 MOVMuxContext *mov = s->priv_data;
7718 MOVTrack *trk;
7719
7720
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 27120 times.
27167 if (!pkt) {
7721 47 mov_flush_fragment(s, 1);
7722 47 return 1;
7723 }
7724
7725
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 27118 times.
27120 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7726 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7727 2 return 0;
7728 }
7729
7730 27118 trk = s->streams[pkt->stream_index]->priv_data;
7731
7732 #if CONFIG_IAMFENC
7733
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 26818 times.
27118 if (trk->iamf) {
7734 300 int ret = mov_build_iamf_packet(s, trk, pkt);
7735
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 if (ret < 0) {
7736
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if (ret == AVERROR(EAGAIN))
7737 240 return 0;
7738 ✗ av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7739 ✗ "for stream #%d\n", trk->st->index);
7740 ✗ return ret;
7741 }
7742 }
7743 #endif
7744
7745
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 26876 times.
26878 if (is_cover_image(trk->st)) {
7746 int ret;
7747
7748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7749 ✗ if (trk->st->nb_frames == 1)
7750 ✗ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7751 ✗ " ignoring.\n", pkt->stream_index);
7752 ✗ return 0;
7753 }
7754
7755
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7756 ✗ return ret;
7757
7758 2 return 0;
7759 } else {
7760 int i;
7761
7762
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 26867 times.
26876 if (!pkt->size)
7763 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7764
7765 /*
7766 * Subtitles require special handling.
7767 *
7768 * 1) For full compliance, every track must have a sample at
7769 * dts == 0, which is rarely true for subtitles. So, as soon
7770 * as we see any packet with dts > 0, write an empty subtitle
7771 * at dts == 0 for any subtitle track with no samples in it.
7772 *
7773 * 2) For each subtitle track, check if the current packet's
7774 * dts is past the duration of the last subtitle sample. If
7775 * so, we now need to write an end sample for that subtitle.
7776 *
7777 * This must be done conditionally to allow for subtitles that
7778 * immediately replace each other, in which case an end sample
7779 * is not needed, and is, in fact, actively harmful.
7780 *
7781 * 3) See mov_write_trailer for how the final end sample is
7782 * handled.
7783 */
7784
2/2
✓ Branch 0 taken 320121 times.
✓ Branch 1 taken 26867 times.
346988 for (i = 0; i < mov->nb_tracks; i++) {
7785 320121 MOVTrack *trk = &mov->tracks[i];
7786 int ret;
7787
7788
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 320118 times.
320121 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7789
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7790
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 (trk->entry == 0 || !trk->last_sample_is_subtitle_end)) {
7791 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7793 2 trk->last_sample_is_subtitle_end = 1;
7794 }
7795 }
7796
7797
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 26719 times.
26867 if (trk->squash_fragment_samples_to_one) {
7798 /*
7799 * If the track has to have its samples squashed into one sample,
7800 * we just take it into the track's queue.
7801 * This will then be utilized as the samples get written in either
7802 * mov_flush_fragment or when the mux is finalized in
7803 * mov_write_trailer.
7804 */
7805 148 int ret = AVERROR_BUG;
7806
7807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (pkt->pts == AV_NOPTS_VALUE) {
7808 ✗ av_log(s, AV_LOG_ERROR,
7809 "Packets without a valid presentation timestamp are "
7810 "not supported with packet squashing!\n");
7811 ✗ return AVERROR(EINVAL);
7812 }
7813
7814 /* The following will reset pkt and is only allowed to be used
7815 * because we return immediately. afterwards. */
7816
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
148 if ((ret = ff_packet_list_put(&trk->squashed_packet_queue,
7817 pkt, NULL, 0)) < 0) {
7818 ✗ return ret;
7819 }
7820
7821 148 return 0;
7822 }
7823
7824
7825
4/4
✓ Branch 0 taken 7939 times.
✓ Branch 1 taken 18780 times.
✓ Branch 2 taken 3917 times.
✓ Branch 3 taken 4022 times.
26719 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7826 3917 AVPacket *opkt = pkt;
7827 int reshuffle_ret, ret;
7828
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3892 times.
3917 if (trk->is_unaligned_qt_rgb) {
7829
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 int64_t bpc = trk->par->bits_per_coded_sample != 15 ? trk->par->bits_per_coded_sample : 16;
7830 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7831 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7833 ✗ return reshuffle_ret;
7834 } else
7835 3892 reshuffle_ret = 0;
7836
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3679 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3917 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7837 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7839 ✗ goto fail;
7840
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7841 5 trk->pal_done++;
7842
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 3087 times.
3912 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7843
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7845 ✗ ret = av_packet_make_writable(pkt);
7846 ✗ if (ret < 0)
7847 ✗ goto fail;
7848 ✗ for (i = 0; i < pkt->size; i++)
7849 ✗ pkt->data[i] = ~pkt->data[i];
7850 }
7851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3917 times.
3917 if (reshuffle_ret) {
7852 ✗ ret = mov_write_single_packet(s, pkt);
7853 ✗ fail:
7854 ✗ if (reshuffle_ret)
7855 ✗ av_packet_free(&pkt);
7856 ✗ return ret;
7857 }
7858 }
7859
7860 26719 return mov_write_single_packet(s, pkt);
7861 }
7862 }
7863
7864 // QuickTime chapters involve an additional text track with the chapter names
7865 // as samples, and a tref pointing from the other tracks to the chapter one.
7866 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7867 {
7868 static const uint8_t stub_header[] = {
7869 // TextSampleEntry
7870 0x00, 0x00, 0x00, 0x01, // displayFlags
7871 0x00, 0x00, // horizontal + vertical justification
7872 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7873 // BoxRecord
7874 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7875 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7876 // StyleRecord
7877 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7878 0x00, 0x01, // fontID
7879 0x00, 0x00, // fontStyleFlags + fontSize
7880 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7881 // FontTableBox
7882 0x00, 0x00, 0x00, 0x0D, // box size
7883 'f', 't', 'a', 'b', // box atom name
7884 0x00, 0x01, // entry count
7885 // FontRecord
7886 0x00, 0x01, // font ID
7887 0x00, // font name length
7888 };
7889 1 MOVMuxContext *mov = s->priv_data;
7890 1 MOVTrack *track = &mov->tracks[tracknum];
7891 1 AVPacket *pkt = mov->pkt;
7892 int i, len;
7893 int ret;
7894
7895 1 track->mode = mov->mode;
7896 1 track->tag = MKTAG('t','e','x','t');
7897 1 track->timescale = mov->movie_timescale;
7898 1 track->par = avcodec_parameters_alloc();
7899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7900 ✗ return AVERROR(ENOMEM);
7901 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7902 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7904 ✗ return ret;
7905 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7906
7907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->extradata == NULL) {
7908 ✗ track->stsd_count = 1;
7909 ✗ track->extradata = av_calloc(1, sizeof(*track->extradata));
7910 ✗ track->extradata_size = av_calloc(1, sizeof(*track->extradata_size));
7911 ✗ if (!track->extradata || !track->extradata_size)
7912 ✗ return AVERROR(ENOMEM);
7913 }
7914
7915 1 track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
7916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->extradata[0])
7917 ✗ return AVERROR(ENOMEM);
7918 1 track->extradata_size[0] = sizeof(stub_header);
7919
7920 1 pkt->stream_index = tracknum;
7921 1 pkt->flags = AV_PKT_FLAG_KEY;
7922
7923
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7924 4 AVChapter *c = s->chapters[i];
7925 AVDictionaryEntry *t;
7926
7927 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7928 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7929 4 pkt->duration = end - pkt->dts;
7930
7931
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7932 static const char encd[12] = {
7933 0x00, 0x00, 0x00, 0x0C,
7934 'e', 'n', 'c', 'd',
7935 0x00, 0x00, 0x01, 0x00 };
7936 4 len = strlen(t->value);
7937 4 pkt->size = len + 2 + 12;
7938 4 pkt->data = av_malloc(pkt->size);
7939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7940 ✗ av_packet_unref(pkt);
7941 ✗ return AVERROR(ENOMEM);
7942 }
7943 4 AV_WB16(pkt->data, len);
7944 4 memcpy(pkt->data + 2, t->value, len);
7945 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7946 4 ff_mov_write_packet(s, pkt);
7947 4 av_freep(&pkt->data);
7948 }
7949 }
7950
7951 1 av_packet_unref(mov->pkt);
7952
7953 1 return 0;
7954 }
7955
7956
7957 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7958 {
7959 int ret;
7960
7961 /* compute the frame number */
7962 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7963 13 return ret;
7964 }
7965
7966 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7967 {
7968 6 MOVMuxContext *mov = s->priv_data;
7969 6 MOVTrack *track = &mov->tracks[index];
7970 6 AVStream *src_st = mov->tracks[src_index].st;
7971 uint8_t data[4];
7972 6 AVPacket *pkt = mov->pkt;
7973 6 AVRational rate = src_st->avg_frame_rate;
7974 int ret;
7975
7976 /* tmcd track based on video stream */
7977 6 track->mode = mov->mode;
7978 6 track->tag = MKTAG('t','m','c','d');
7979 6 track->src_track = av_malloc(sizeof(*track->src_track));
7980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->src_track)
7981 ✗ return AVERROR(ENOMEM);
7982 6 *track->src_track = src_index;
7983 6 track->nb_src_track = 1;
7984
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7985 3 track->timescale = tc.fps * 1000;
7986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (tc.rate.den == 1001)
7987 ✗ track->timescale = tc.rate.num;
7988 else
7989 3 track->timescale = tc.fps;
7990
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7991 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7992
7993 /* set st to src_st for metadata access*/
7994 6 track->st = src_st;
7995
7996 /* encode context: tmcd data stream */
7997 6 track->par = avcodec_parameters_alloc();
7998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7999 ✗ return AVERROR(ENOMEM);
8000 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
8001 6 track->par->codec_tag = track->tag;
8002 6 track->st->avg_frame_rate = rate;
8003
8004 /* the tmcd track just contains one packet with the frame number */
8005 6 pkt->data = data;
8006 6 pkt->stream_index = index;
8007 6 pkt->flags = AV_PKT_FLAG_KEY;
8008 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){ 1, track->timescale });
8009 6 pkt->size = 4;
8010 6 AV_WB32(pkt->data, tc.start);
8011 6 ret = ff_mov_write_packet(s, pkt);
8012 6 av_packet_unref(pkt);
8013 6 return ret;
8014 }
8015
8016 /*
8017 * st->disposition controls the "enabled" flag in the tkhd tag.
8018 * QuickTime will not play a track if it is not enabled. So make sure
8019 * that one track of each type (audio, video, subtitle) is enabled.
8020 *
8021 * Subtitles are special. For audio and video, setting "enabled" also
8022 * makes the track "default" (i.e. it is rendered when played). For
8023 * subtitles, an "enabled" subtitle is not rendered by default, but
8024 * if no subtitle is enabled, the subtitle menu in QuickTime will be
8025 * empty!
8026 */
8027 253 static void enable_tracks(AVFormatContext *s)
8028 {
8029 253 MOVMuxContext *mov = s->priv_data;
8030 int i;
8031 int enabled[AVMEDIA_TYPE_NB];
8032 int first[AVMEDIA_TYPE_NB];
8033
8034
2/2
✓ Branch 0 taken 1265 times.
✓ Branch 1 taken 253 times.
1518 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8035 1265 enabled[i] = 0;
8036 1265 first[i] = -1;
8037 }
8038
8039
2/2
✓ Branch 0 taken 415 times.
✓ Branch 1 taken 253 times.
668 for (i = 0; i < mov->nb_streams; i++) {
8040 415 AVStream *st = mov->tracks[i].st;
8041
8042
1/2
✓ Branch 0 taken 415 times.
✗ Branch 1 not taken.
415 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
8043
3/4
✓ Branch 0 taken 415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 413 times.
830 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
8044 415 is_cover_image(st))
8045 2 continue;
8046
8047
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 115 times.
413 if (first[st->codecpar->codec_type] < 0)
8048 298 first[st->codecpar->codec_type] = i;
8049
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 375 times.
413 if (st->disposition & AV_DISPOSITION_DEFAULT) {
8050 38 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
8051 38 enabled[st->codecpar->codec_type]++;
8052 }
8053 }
8054
8055
2/2
✓ Branch 0 taken 1265 times.
✓ Branch 1 taken 253 times.
1518 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
8056
2/2
✓ Branch 0 taken 759 times.
✓ Branch 1 taken 506 times.
1265 switch (i) {
8057 759 case AVMEDIA_TYPE_VIDEO:
8058 case AVMEDIA_TYPE_AUDIO:
8059 case AVMEDIA_TYPE_SUBTITLE:
8060
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 758 times.
759 if (enabled[i] > 1)
8061 1 mov->per_stream_grouping = 1;
8062
4/4
✓ Branch 0 taken 726 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 463 times.
759 if (!enabled[i] && first[i] >= 0)
8063 263 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
8064 759 break;
8065 }
8066 }
8067 253 }
8068
8069 253 static void mov_free(AVFormatContext *s)
8070 {
8071 253 MOVMuxContext *mov = s->priv_data;
8072
8073
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 253 times.
689 for (int i = 0; i < s->nb_streams; i++)
8074 436 s->streams[i]->priv_data = NULL;
8075
8076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (!mov->tracks)
8077 ✗ return;
8078
8079
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->chapter_track) {
8080 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
8081 }
8082
8083
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 253 times.
677 for (int i = 0; i < mov->nb_tracks; i++) {
8084 424 MOVTrack *const track = &mov->tracks[i];
8085
8086
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 422 times.
424 if (track->tag == MKTAG('r','t','p',' '))
8087 2 ff_mov_close_hinting(track);
8088
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 413 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
422 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
8089 6 av_freep(&track->par);
8090 424 av_freep(&track->cluster);
8091 424 av_freep(&track->cluster_written);
8092 424 av_freep(&track->frag_info);
8093 424 av_packet_free(&track->cover_image);
8094
8095
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 414 times.
424 if (track->eac3_priv) {
8096 10 struct eac3_info *info = track->eac3_priv;
8097 10 av_packet_free(&info->pkt);
8098 10 av_freep(&track->eac3_priv);
8099 }
8100
2/2
✓ Branch 0 taken 426 times.
✓ Branch 1 taken 424 times.
850 for (int j = 0; j < track->stsd_count; j++)
8101 426 av_freep(&track->extradata[j]);
8102 424 av_freep(&track->extradata);
8103 424 av_freep(&track->extradata_size);
8104
8105
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 424 times.
435 for (int i = 0; i < track->nb_tref_tags; i++)
8106 11 av_freep(&track->tref_tags[i].id);
8107 424 av_freep(&track->tref_tags);
8108 424 av_freep(&track->src_track);
8109
8110 424 ff_mov_cenc_free(&track->cenc);
8111 424 ffio_free_dyn_buf(&track->mdat_buf);
8112
8113 #if CONFIG_IAMFENC
8114 424 ffio_free_dyn_buf(&track->iamf_buf);
8115
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 419 times.
424 if (track->iamf)
8116 5 ff_iamf_uninit_context(track->iamf);
8117 424 av_freep(&track->iamf);
8118 #endif
8119 424 ff_isom_close_apvc(&track->apv);
8120
8121 424 ff_packet_list_free(&track->squashed_packet_queue);
8122 }
8123
8124 253 av_freep(&mov->tracks);
8125 253 ffio_free_dyn_buf(&mov->mdat_buf);
8126 }
8127
8128 ✗ static uint32_t rgb_to_yuv(uint32_t rgb)
8129 {
8130 uint8_t r, g, b;
8131 int y, cb, cr;
8132
8133 ✗ r = (rgb >> 16) & 0xFF;
8134 ✗ g = (rgb >> 8) & 0xFF;
8135 ✗ b = (rgb ) & 0xFF;
8136
8137 ✗ y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
8138 ✗ cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
8139 ✗ cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
8140
8141 ✗ return (y << 16) | (cr << 8) | cb;
8142 }
8143
8144 ✗ static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
8145 AVStream *st)
8146 {
8147 ✗ int i, width = 720, height = 480;
8148 ✗ int have_palette = 0, have_size = 0;
8149 uint32_t palette[16];
8150 ✗ char *cur = st->codecpar->extradata;
8151
8152 ✗ while (cur && *cur) {
8153 ✗ if (strncmp("palette:", cur, 8) == 0) {
8154 int i, count;
8155 ✗ count = sscanf(cur + 8,
8156 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8157 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8158 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
8159 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
8160 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
8161 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
8162 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
8163 &palette[12], &palette[13], &palette[14], &palette[15]);
8164
8165 ✗ for (i = 0; i < count; i++) {
8166 ✗ palette[i] = rgb_to_yuv(palette[i]);
8167 }
8168 ✗ have_palette = 1;
8169 ✗ } else if (!strncmp("size:", cur, 5)) {
8170 ✗ sscanf(cur + 5, "%dx%d", &width, &height);
8171 ✗ have_size = 1;
8172 }
8173 ✗ if (have_palette && have_size)
8174 ✗ break;
8175 ✗ cur += strcspn(cur, "\n\r");
8176 ✗ cur += strspn(cur, "\n\r");
8177 }
8178 ✗ if (have_palette) {
8179 ✗ track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
8180 ✗ if (!track->extradata[track->last_stsd_index])
8181 ✗ return AVERROR(ENOMEM);
8182 ✗ for (i = 0; i < 16; i++) {
8183 ✗ AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
8184 }
8185 ✗ memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8186 ✗ track->extradata_size[track->last_stsd_index] = 16 * 4;
8187 }
8188 ✗ st->codecpar->width = width;
8189 ✗ st->codecpar->height = track->height = height;
8190
8191 ✗ return 0;
8192 }
8193
8194 #if CONFIG_IAMFENC
8195 253 static int mov_init_iamf_track(AVFormatContext *s)
8196 {
8197 253 MOVMuxContext *mov = s->priv_data;
8198 MOVTrack *track;
8199 IAMFContext *iamf;
8200 253 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
8201 253 int nb_audio_elements = 0, nb_mix_presentations = 0;
8202 int ret;
8203
8204
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 253 times.
264 for (int i = 0; i < s->nb_stream_groups; i++) {
8205 11 const AVStreamGroup *stg = s->stream_groups[i];
8206
8207
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8208 5 nb_audio_elements++;
8209
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
8210 5 nb_mix_presentations++;
8211 }
8212
8213
3/4
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
253 if (!nb_audio_elements && !nb_mix_presentations)
8214 248 return 0;
8215
8216
3/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 if (nb_audio_elements < 1 || nb_audio_elements > 2 || nb_mix_presentations < 1) {
8217 ✗ av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
8218 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
8219 ✗ return AVERROR(EINVAL);
8220 }
8221
8222 5 iamf = av_mallocz(sizeof(*iamf));
8223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
8224 ✗ return AVERROR(ENOMEM);
8225
8226
8227
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8228 10 const AVStreamGroup *stg = s->stream_groups[i];
8229
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
8230 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
8231
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_entries; j++) {
8232 25 first_iamf_idx = FFMIN(stg->entries[j]->stream->index, first_iamf_idx);
8233 25 last_iamf_idx = FFMAX(stg->entries[j]->stream->index, last_iamf_idx);
8234 }
8235
8236 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
8237 5 break;
8238 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
8239 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
8240 5 break;
8241 ✗ default:
8242 ✗ av_assert0(0);
8243 }
8244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
8245 ✗ ff_iamf_uninit_context(iamf);
8246 ✗ av_free(iamf);
8247 ✗ return ret;
8248 }
8249 }
8250
8251 5 track = &mov->tracks[first_iamf_idx];
8252 5 track->iamf = iamf;
8253 5 track->first_iamf_idx = first_iamf_idx;
8254 5 track->last_iamf_idx = last_iamf_idx;
8255 5 track->tag = MKTAG('i','a','m','f');
8256
8257
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
8258 10 AVStreamGroup *stg = s->stream_groups[i];
8259
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8260 5 continue;
8261
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_entries; j++)
8262 25 stg->entries[j]->stream->priv_data = track;
8263 }
8264
8265 5 ret = avio_open_dyn_buf(&track->iamf_buf);
8266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
8267 ✗ return ret;
8268
8269 5 return 0;
8270 }
8271 #endif
8272
8273 253 static int mov_init(AVFormatContext *s)
8274 {
8275 253 MOVMuxContext *mov = s->priv_data;
8276 253 int has_iamf = 0;
8277 int i, ret;
8278
8279 253 mov->fc = s;
8280 253 mov->pkt = ffformatcontext(s)->pkt;
8281
8282 /* Default mode == MP4 */
8283 253 mov->mode = MODE_MP4;
8284
8285 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
8286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
8287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
8288
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 102 times.
253 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
8289
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 101 times.
102 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
8290
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 100 times.
101 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
8291
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 95 times.
100 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
8292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
8293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
8294 #undef IS_MODE
8295
8296
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 232 times.
253 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
8297 21 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
8298
8299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (mov->mode == MODE_AVIF)
8300 ✗ mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
8301
8302 /* Set the FRAGMENT flag if any of the fragmentation methods are
8303 * enabled. */
8304
3/4
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 251 times.
✗ Branch 3 not taken.
253 if (mov->max_fragment_duration || mov->max_fragment_size ||
8305
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 215 times.
251 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
8306 FF_MOV_FLAG_FRAG_KEYFRAME |
8307 FF_MOV_FLAG_FRAG_CUSTOM |
8308 FF_MOV_FLAG_FRAG_EVERY_FRAME))
8309 38 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8310
8311
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 251 times.
253 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED &&
8312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->flags & FF_MOV_FLAG_FASTSTART) {
8313 ✗ av_log(s, AV_LOG_ERROR, "Setting both hybrid_fragmented and faststart is not supported.\n");
8314 ✗ return AVERROR(EINVAL);
8315 }
8316
8317 /* Set other implicit flags immediately */
8318
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 251 times.
253 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8319 2 mov->flags |= FF_MOV_FLAG_FRAGMENT;
8320
8321
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 248 times.
253 if (mov->mode == MODE_ISM)
8322 5 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
8323 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8324
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 238 times.
253 if (mov->flags & FF_MOV_FLAG_DASH)
8325 15 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8326 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
8327
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 251 times.
253 if (mov->flags & FF_MOV_FLAG_CMAF)
8328 2 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
8329 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8330
8331
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 214 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 4 times.
253 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
8332 35 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
8333 35 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
8334 }
8335
8336
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
253 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
8337 ✗ av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
8338 ✗ mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
8339 }
8340
8341
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 250 times.
253 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8342 3 mov->reserved_moov_size = -1;
8343 }
8344
8345
2/2
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 7 times.
253 if (mov->use_editlist < 0) {
8346 246 mov->use_editlist = 1;
8347
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 209 times.
246 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8348
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 19 times.
37 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8349 // If we can avoid needing an edit list by shifting the
8350 // tracks, prefer that over (trying to) write edit lists
8351 // in fragmented output.
8352
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
8353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
8354 17 mov->use_editlist = 0;
8355 }
8356 }
8357
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 214 times.
253 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8358
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17 times.
39 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
8359 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
8360
8361
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
253 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist)
8362 ✗ mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
8363
8364
4/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 230 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 1 times.
253 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
8365
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
22 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
8366 14 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
8367
8368 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
8369 * if the latter is set that's enough and omit_tfhd_offset doesn't
8370 * add anything extra on top of that. */
8371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
8372 ✗ mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
8373 ✗ mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
8374
8375
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->frag_interleave &&
8376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
8377 ✗ av_log(s, AV_LOG_ERROR,
8378 "Sample interleaving in fragments is mutually exclusive with "
8379 "omit_tfhd_offset and separate_moof\n");
8380 ✗ return AVERROR(EINVAL);
8381 }
8382
8383 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
8384 * is enabled, we don't support non-seekable output at all. */
8385
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 224 times.
253 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
8386
2/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
8387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 mov->mode == MODE_AVIF)) {
8388 ✗ av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
8389 ✗ return AVERROR(EINVAL);
8390 }
8391
8392 /* AVIF output must have at most two video streams (one for YUV and one for
8393 * alpha). */
8394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (mov->mode == MODE_AVIF) {
8395 ✗ if (s->nb_streams > 2) {
8396 ✗ av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
8397 ✗ return AVERROR(EINVAL);
8398 }
8399 ✗ if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8400 ✗ (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
8401 ✗ av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
8402 ✗ return AVERROR(EINVAL);
8403 }
8404 ✗ if (!av_pix_fmt_desc_get(s->streams[0]->codecpar->format)) {
8405 ✗ av_log(s, AV_LOG_ERROR, "AVIF output requires a known pixel format\n");
8406 ✗ return AVERROR(EINVAL);
8407 }
8408 ✗ if (s->nb_streams > 1) {
8409 const AVPixFmtDescriptor *pixdesc =
8410 ✗ av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
8411 ✗ if (!pixdesc || pixdesc->nb_components != 1) {
8412 ✗ av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
8413 ✗ return AVERROR(EINVAL);
8414 }
8415 }
8416 ✗ s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
8417 }
8418
8419
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 253 times.
264 for (i = 0; i < s->nb_stream_groups; i++) {
8420 11 AVStreamGroup *stg = s->stream_groups[i];
8421
8422
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 11 times.
63 for (int j = 0; j < stg->nb_entries; j++) {
8423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (stg->entries[j]->type != AV_STREAM_GROUP_ENTRY_STREAM) {
8424 ✗ av_log(s, AV_LOG_ERROR, "Unsupported Stream Group entry #%d "
8425 "in Stream Group id %"PRId64"\n",
8426 i, stg->id);
8427 ✗ return AVERROR(EINVAL);
8428 }
8429 }
8430
8431
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (stg->type == AV_STREAM_GROUP_PARAMS_LCEVC) {
8432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stg->nb_entries != 2) {
8433 ✗ av_log(s, AV_LOG_ERROR, "Exactly two Streams are supported for Stream Groups of type LCEVC\n");
8434 ✗ return AVERROR(EINVAL);
8435 }
8436 1 AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (lcevc->el_index > 1)
8438 ✗ return AVERROR(EINVAL);
8439 1 AVStream *st = stg->entries[lcevc->el_index]->stream;
8440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) {
8441 ✗ av_log(s, AV_LOG_ERROR, "Stream #%u is not an LCEVC stream\n", lcevc->el_index);
8442 ✗ return AVERROR(EINVAL);
8443 }
8444 }
8445
8446 #if CONFIG_IAMFENC
8447
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
8448 6 continue;
8449
8450
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_entries; j++) {
8451 25 AVStream *st = stg->entries[j]->stream;
8452
8453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
8454 ✗ av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
8455 "IAMF Audio Element\n", j);
8456 ✗ return AVERROR(EINVAL);
8457 }
8458 25 st->priv_data = st;
8459 }
8460 5 has_iamf = 1;
8461
8462
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
8463 5 mov->nb_tracks++;
8464 #endif
8465 }
8466
8467
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 253 times.
689 for (i = 0; i < s->nb_streams; i++) {
8468 436 AVStream *st = s->streams[i];
8469
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 411 times.
436 if (st->priv_data)
8470 25 continue;
8471 // Don't produce a track in the output file for timed ID3 streams.
8472
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 410 times.
411 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
8473 // Leave priv_data set to NULL for these AVStreams that don't
8474 // have a corresponding track.
8475 1 continue;
8476 }
8477 410 st->priv_data = st;
8478 410 mov->nb_tracks++;
8479 }
8480
8481 253 mov->nb_streams = mov->nb_tracks;
8482
8483
4/4
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 246 times.
253 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8484 1 mov->chapter_track = mov->nb_tracks++;
8485
8486
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8487
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
8488
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
8489 2 mov->nb_tracks++;
8490 }
8491
8492
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 if (mov->write_btrt < 0) {
8493 253 mov->write_btrt = mov->mode == MODE_MP4;
8494 }
8495
8496
6/6
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 151 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 95 times.
253 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
8497
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 || mov->write_tmcd == 1) {
8498 249 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
8499 NULL, 0);
8500
8501 /* +1 tmcd track for each video stream with a timecode */
8502
2/2
✓ Branch 0 taken 429 times.
✓ Branch 1 taken 249 times.
678 for (i = 0; i < s->nb_streams; i++) {
8503 429 AVStream *st = s->streams[i];
8504 429 AVDictionaryEntry *t = global_tcr;
8505
4/4
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 226 times.
✓ Branch 2 taken 197 times.
✓ Branch 3 taken 6 times.
429 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
8506
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 196 times.
197 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
8507 AVTimecode tc;
8508 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
8509
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
8510 7 mov->nb_meta_tmcd++;
8511 }
8512 }
8513
8514 /* check if there is already a tmcd track to remux */
8515
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 242 times.
249 if (mov->nb_meta_tmcd) {
8516
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
8517 13 AVStream *st = s->streams[i];
8518
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
8519 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
8520 "so timecode metadata are now ignored\n");
8521 3 mov->nb_meta_tmcd = 0;
8522 }
8523 }
8524 }
8525
8526 249 mov->nb_tracks += mov->nb_meta_tmcd;
8527 }
8528
8529 // Reserve an extra stream for chapters for the case where chapters
8530 // are written in the trailer
8531 253 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
8532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (!mov->tracks)
8533 ✗ return AVERROR(ENOMEM);
8534
8535
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 253 times.
677 for (i = 0; i < mov->nb_tracks; i++) {
8536 424 MOVTrack *track = &mov->tracks[i];
8537
8538 424 track->stsd_count = 1;
8539 424 track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
8540 424 track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
8541
2/4
✓ Branch 0 taken 424 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 424 times.
424 if (!track->extradata || !track->extradata_size)
8542 ✗ return AVERROR(ENOMEM);
8543 }
8544
8545
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
253 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
8546
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
8547 5 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
8548
8549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
8550 ✗ av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
8551 mov->encryption_key_len, AES_CTR_KEY_SIZE);
8552 ✗ return AVERROR(EINVAL);
8553 }
8554
8555
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mov->encryption_kid_len != CENC_KID_SIZE) {
8556 ✗ av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
8557 mov->encryption_kid_len, CENC_KID_SIZE);
8558 ✗ return AVERROR(EINVAL);
8559 }
8560 } else {
8561 ✗ av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
8562 mov->encryption_scheme_str);
8563 ✗ return AVERROR(EINVAL);
8564 }
8565 }
8566
8567 #if CONFIG_IAMFENC
8568 253 ret = mov_init_iamf_track(s);
8569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (ret < 0)
8570 ✗ return ret;
8571 #endif
8572
8573
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 253 times.
689 for (int j = 0, i = 0; j < s->nb_streams; j++) {
8574 436 AVStream *st = s->streams[j];
8575
8576
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 410 times.
436 if (st != st->priv_data) {
8577
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
8578 5 i += has_iamf--;
8579 26 continue;
8580 }
8581 410 st->priv_data = &mov->tracks[i++];
8582 }
8583
8584 253 AVRational movie_timescale = (AVRational) { 0, 1 };
8585
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 253 times.
689 for (i = 0; i < s->nb_streams; i++) {
8586 436 AVStream *st= s->streams[i];
8587 436 MOVTrack *track = st->priv_data;
8588
8589
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 435 times.
436 if (!track)
8590 1 continue;
8591
8592
2/2
✓ Branch 0 taken 415 times.
✓ Branch 1 taken 20 times.
435 if (!track->st) {
8593 415 track->st = st;
8594 415 track->par = st->codecpar;
8595 }
8596
8597 435 movie_timescale = av_gcd_q(movie_timescale, st->time_base, INT_MAX, (AVRational){1,0});
8598 }
8599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (!movie_timescale.den)
8600 ✗ movie_timescale = MOV_TIMESCALE_Q;
8601
8602
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 if (!mov->movie_timescale)
8603 253 mov->movie_timescale = FFMAX(movie_timescale.den, MOV_TIMESCALE);
8604
8605
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 253 times.
689 for (i = 0; i < s->nb_streams; i++) {
8606 436 AVStream *st= s->streams[i];
8607 436 MOVTrack *track = st->priv_data;
8608 436 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
8609
8610
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 435 times.
436 if (!track)
8611 1 continue;
8612
8613
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 404 times.
435 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
8614
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 277 times.
435 if (track->language < 0)
8615 158 track->language = 32767; // Unspecified Macintosh language code
8616 435 track->mode = mov->mode;
8617
2/2
✓ Branch 0 taken 410 times.
✓ Branch 1 taken 25 times.
435 if (!track->tag)
8618 410 track->tag = mov_find_codec_tag(s, track);
8619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 435 times.
435 if (!track->tag) {
8620 ✗ av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
8621 "codec not currently supported in container\n",
8622 ✗ avcodec_get_name(st->codecpar->codec_id), i);
8623 ✗ return AVERROR(EINVAL);
8624 }
8625 /* If hinting of this track is enabled by a later hint track,
8626 * this is updated. */
8627 435 track->hint_track = -1;
8628 435 track->start_dts = AV_NOPTS_VALUE;
8629 435 track->start_cts = AV_NOPTS_VALUE;
8630 435 track->end_pts = AV_NOPTS_VALUE;
8631 435 track->dts_shift = AV_NOPTS_VALUE;
8632
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 229 times.
435 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8633
2/4
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
✗ Branch 3 not taken.
206 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
8634
2/4
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
✗ Branch 3 not taken.
206 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
8635
2/4
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 206 times.
206 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
8636 ✗ if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
8637 ✗ av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
8638 ✗ return AVERROR(EINVAL);
8639 }
8640 ✗ track->height = track->tag >> 24 == 'n' ? 486 : 576;
8641 }
8642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
206 if (mov->video_track_timescale) {
8643 ✗ track->timescale = mov->video_track_timescale;
8644 ✗ if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8645 ✗ av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8646 } else {
8647 206 track->timescale = st->time_base.den;
8648
2/2
✓ Branch 0 taken 1608 times.
✓ Branch 1 taken 206 times.
1814 while(track->timescale < 10000)
8649 1608 track->timescale *= 2;
8650 }
8651
2/4
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 206 times.
206 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
8652 ✗ av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8653 ✗ return AVERROR(EINVAL);
8654 }
8655
4/4
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 131 times.
206 if (track->mode == MODE_MOV && track->timescale > 100000)
8656 5 av_log(s, AV_LOG_WARNING,
8657 "WARNING codec timebase is very high. If duration is too long,\n"
8658 "file may not be playable by quicktime. Specify a shorter timebase\n"
8659 "or choose different container.\n");
8660
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 70 times.
206 if (track->mode == MODE_MOV &&
8661
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 119 times.
136 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8662
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8663 1 enum AVPixelFormat pix_fmt = track->par->format;
8664
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)
8665 ✗ pix_fmt = AV_PIX_FMT_MONOWHITE;
8666 1 track->is_unaligned_qt_rgb =
8667 ✗ pix_fmt == AV_PIX_FMT_RGB24 ||
8668 ✗ pix_fmt == AV_PIX_FMT_BGR24 ||
8669 ✗ pix_fmt == AV_PIX_FMT_PAL8 ||
8670 ✗ pix_fmt == AV_PIX_FMT_GRAY8 ||
8671
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 ||
8672 pix_fmt == AV_PIX_FMT_MONOBLACK;
8673 }
8674
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
206 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8675 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8676 ✗ return AVERROR(EINVAL);
8677
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 204 times.
206 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8678
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) {
8679 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8680 ✗ return AVERROR(EINVAL);
8681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
206 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8682 /* altref frames handling is not defined in the spec as of version v1.0,
8683 * so just forbid muxing VP8 streams altogether until a new version does */
8684 ✗ av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8685 ✗ return AVERROR_PATCHWELCOME;
8686
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 205 times.
206 } else if (track->par->codec_id == AV_CODEC_ID_APV) {
8687 1 ret = ff_isom_init_apvc(&track->apv, s);
8688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
8689 ✗ return ret;
8690 }
8691
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 204 times.
206 if (is_cover_image(st)) {
8692 2 track->cover_image = av_packet_alloc();
8693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8694 ✗ return AVERROR(ENOMEM);
8695 }
8696
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 9 times.
229 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8697 220 track->timescale = st->codecpar->sample_rate;
8698
4/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 186 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 26 times.
220 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8699 8 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8700 8 track->audio_vbr = 1;
8701
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8702
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8704 ✗ if (!st->codecpar->block_align) {
8705 ✗ av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8706 ✗ return AVERROR(EINVAL);
8707 }
8708 ✗ track->sample_size = st->codecpar->block_align;
8709
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 26 times.
212 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8710 186 track->audio_vbr = 1;
8711 }else{
8712 26 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8713 26 st->codecpar->ch_layout.nb_channels;
8714 }
8715
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8717 ✗ track->audio_vbr = 1;
8718 }
8719
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 31 times.
220 if (track->mode != MODE_MOV &&
8720
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
189 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8721 ✗ if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8722 ✗ av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8723 ✗ i, track->par->sample_rate);
8724 ✗ return AVERROR(EINVAL);
8725 } else {
8726 ✗ av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8727 ✗ i, track->par->sample_rate);
8728 }
8729 }
8730
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 25 times.
220 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8731
1/2
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
195 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 track->par->codec_id == AV_CODEC_ID_OPUS) {
8733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8734 ✗ av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8735 ✗ return AVERROR(EINVAL);
8736 }
8737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8738 ✗ s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8739 ✗ av_log(s, AV_LOG_ERROR,
8740 "%s in MP4 support is experimental, add "
8741 "'-strict %d' if you want to use it.\n",
8742 ✗ avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8743 ✗ return AVERROR_EXPERIMENTAL;
8744 }
8745 }
8746
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8747 5 track->timescale = st->time_base.den;
8748
8749
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8750 /* 14496-30 requires us to use a single sample per fragment
8751 for TTML, for which we define a per-track flag.
8752
8753 We set the flag in case we are receiving TTML paragraphs
8754 from the input, in other words in case we are not doing
8755 stream copy. */
8756 4 track->squash_fragment_samples_to_one =
8757 4 ff_is_ttml_stream_paragraph_based(track->par);
8758
8759
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->mode != MODE_ISM &&
8760
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8762 ✗ av_log(s, AV_LOG_ERROR,
8763 "ISMV style TTML support with the 'dfxp' tag in "
8764 "non-ISMV formats is not officially supported. Add "
8765 "'-strict unofficial' if you want to use it.\n");
8766 ✗ return AVERROR_EXPERIMENTAL;
8767 }
8768 }
8769
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8770 4 track->timescale = st->time_base.den;
8771
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (track->tag == MKTAG('t','m','c','d') &&
8772
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->extradata_size >= 8)
8773 3 track->timecode_flags = AV_RB32(st->codecpar->extradata + 4);
8774 } else {
8775 ✗ track->timescale = mov->movie_timescale;
8776 }
8777
1/2
✓ Branch 0 taken 435 times.
✗ Branch 1 not taken.
435 if (!track->height)
8778 435 track->height = st->codecpar->height;
8779 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8780 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8781 for video tracks, so if user-set, it isn't overwritten */
8782
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 428 times.
435 if (mov->mode == MODE_ISM &&
8783
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8784
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))) {
8785 7 track->timescale = 10000000;
8786 }
8787
8788 435 avpriv_set_pts_info(st, 64, 1, track->timescale);
8789
8790
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 430 times.
435 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8791 5 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8792
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 ||
8793
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),
8794
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret)
8796 ✗ return ret;
8797 }
8798 }
8799
8800
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 253 times.
264 for (i = 0; i < s->nb_stream_groups; i++) {
8801 11 AVStreamGroup *stg = s->stream_groups[i];
8802
8803
2/3
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
11 switch (stg->type) {
8804 1 case AV_STREAM_GROUP_PARAMS_LCEVC: {
8805 1 AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
8806 1 AVStream *st = stg->entries[lcevc->el_index]->stream;
8807 1 MOVTrack *track = st->priv_data;
8808
8809
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 for (int j = 0; j < mov->nb_tracks; j++) {
8810 1 MOVTrack *trk = &mov->tracks[j];
8811
8812
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (trk->st == stg->entries[!lcevc->el_index]->stream) {
8813 1 track->src_track = av_malloc(sizeof(*track->src_track));
8814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->src_track)
8815 ✗ return AVERROR(ENOMEM);
8816 1 *track->src_track = j;
8817 1 track->nb_src_track = 1;
8818 1 break;
8819 }
8820 }
8821
8822 1 track->par->width = lcevc->width;
8823 1 track->par->height = track->height = lcevc->height;
8824 1 break;
8825 }
8826 ✗ case AV_STREAM_GROUP_PARAMS_TREF: {
8827 ✗ const AVStreamGroupTREF *tref = stg->params.tref;
8828 MOVTrack *track;
8829
8830 ✗ if (tref->metadata_index >= stg->nb_entries)
8831 ✗ return AVERROR(EINVAL);
8832
8833 ✗ track = stg->entries[tref->metadata_index]->stream->priv_data;
8834 ✗ for (int j = 0; j < stg->nb_entries; j++) {
8835 ✗ const AVStream *st2 = stg->entries[j]->stream;
8836 ✗ int index = -1;
8837
8838 ✗ if (j == tref->metadata_index)
8839 ✗ continue;
8840
8841 ✗ for (int k = 0; k < mov->nb_tracks; k++) {
8842 ✗ if (mov->tracks[k].st != st2)
8843 ✗ continue;
8844 ✗ index = k;
8845 ✗ break;
8846 }
8847 ✗ if (index < 0)
8848 ✗ return AVERROR(EINVAL);
8849
8850 ✗ int *tmp = av_realloc(track->src_track,
8851 ✗ (track->nb_src_track + 1) * sizeof(*track->src_track));
8852 ✗ if (!tmp)
8853 ✗ return AVERROR(ENOMEM);
8854 ✗ track->src_track = tmp;
8855 ✗ track->src_track[track->nb_src_track++] = index;
8856 }
8857 ✗ break;
8858 }
8859 10 default:
8860 10 break;
8861 }
8862 }
8863
8864 /* fill src_track for tmcd tracks not covered by stream groups or
8865 * created by this muxer, retaining the old behavior of src_track
8866 * being arbitrarily 0. */
8867
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 253 times.
689 for (i = 0; i < s->nb_streams; i++) {
8868 436 AVStream *st = s->streams[i];
8869 436 MOVTrack *track = st->priv_data;
8870
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 433 times.
436 if (st->codecpar->codec_tag != MKTAG('t','m','c','d') ||
8871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 track->nb_src_track)
8872 433 continue;
8873
8874 3 track->src_track = av_malloc(sizeof(*track->src_track));
8875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!track->src_track)
8876 ✗ return AVERROR(ENOMEM);
8877 3 *track->src_track = 0;
8878 3 track->nb_src_track = 1;
8879 }
8880
8881 253 enable_tracks(s);
8882 253 return 0;
8883 }
8884
8885 253 static int mov_write_header(AVFormatContext *s)
8886 {
8887 253 AVIOContext *pb = s->pb;
8888 253 MOVMuxContext *mov = s->priv_data;
8889 253 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8890
8891
4/4
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 246 times.
253 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8892 1 nb_tracks++;
8893
8894
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8895 1 hint_track = nb_tracks;
8896
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8897
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8898 2 nb_tracks++;
8899 }
8900 }
8901
8902
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 247 times.
253 if (mov->nb_meta_tmcd)
8903 6 tmcd_track = nb_tracks;
8904
8905
2/2
✓ Branch 0 taken 415 times.
✓ Branch 1 taken 253 times.
668 for (int i = 0; i < mov->nb_streams; i++) {
8906 415 MOVTrack *track = &mov->tracks[i];
8907 415 AVStream *st = track->st;
8908
8909 /* copy extradata if it exists */
8910
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 264 times.
415 if (st->codecpar->extradata_size) {
8911
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8912 ✗ mov_create_dvd_sub_decoder_specific_info(track, st);
8913
15/30
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 151 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 151 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 151 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 151 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 151 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 151 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 151 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 151 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 151 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 151 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 151 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 151 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 151 times.
✗ Branch 29 not taken.
151 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8914 151 track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
8915 302 track->extradata[track->last_stsd_index] =
8916 151 av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
8917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if (!track->extradata[track->last_stsd_index]) {
8918 ✗ return AVERROR(ENOMEM);
8919 }
8920 151 memcpy(track->extradata[track->last_stsd_index],
8921 151 st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
8922 151 memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
8923 0, AV_INPUT_BUFFER_PADDING_SIZE);
8924 }
8925 }
8926
8927
4/4
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 215 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 114 times.
615 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8928 200 av_channel_layout_compare(&track->par->ch_layout,
8929 200 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8930 301 continue;
8931
8932
2/2
✓ Branch 0 taken 10032 times.
✓ Branch 1 taken 114 times.
10146 for (int j = 0; j < mov->nb_streams; j++) {
8933 10032 AVStream *stj= mov->tracks[j].st;
8934 10032 MOVTrack *trackj= &mov->tracks[j];
8935
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 9918 times.
10032 if (j == i)
8936 114 continue;
8937
8938
2/2
✓ Branch 0 taken 9911 times.
✓ Branch 1 taken 7 times.
9918 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8939
4/4
✓ Branch 0 taken 9907 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 9900 times.
✓ Branch 3 taken 7 times.
19818 (trackj->par->ch_layout.nb_channels != 1 ||
8940 9907 !av_channel_layout_compare(&trackj->par->ch_layout,
8941 9907 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8942 )
8943 9904 track->mono_as_fc = -1;
8944
8945
4/4
✓ Branch 0 taken 9911 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 9900 times.
19829 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8946 9911 av_channel_layout_compare(&trackj->par->ch_layout,
8947 9911 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8948
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
8949 )
8950 7 track->mono_as_fc++;
8951
8952
4/4
✓ Branch 0 taken 9911 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 9900 times.
✓ Branch 3 taken 11 times.
19829 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8953 9911 av_channel_layout_compare(&trackj->par->ch_layout,
8954 9911 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8955
1/2
✓ Branch 0 taken 9900 times.
✗ Branch 1 not taken.
9900 trackj->language != track->language ||
8956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9900 times.
9900 trackj->tag != track->tag
8957 )
8958 18 continue;
8959 9900 track->multichannel_as_mono++;
8960 }
8961 }
8962
8963
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 232 times.
253 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV) ||
8964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)) {
8965
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 232 times.
232 if ((ret = mov_write_identification(pb, s)) < 0)
8966 ✗ return ret;
8967 }
8968
8969
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 250 times.
253 if (mov->reserved_moov_size){
8970 3 mov->reserved_header_pos = avio_tell(pb);
8971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8972 ✗ avio_skip(pb, mov->reserved_moov_size);
8973 }
8974
8975
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 209 times.
253 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8976 /* If no fragmentation options have been set, set a default. */
8977
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 37 times.
44 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8978 FF_MOV_FLAG_FRAG_CUSTOM |
8979 7 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8980
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)
8981 6 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8982
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 42 times.
44 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8983 2 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8984
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8985 2 mov->mdat_pos = avio_tell(pb);
8986 // The free/wide header that later will be converted into an
8987 // mdat, covering the initial moov and all the fragments.
8988 2 avio_wb32(pb, 0);
8989
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8990 // Write an ftyp atom, hidden in a free/wide. This is neither
8991 // exposed while the file is written, as fragmented, nor when the
8992 // file is finalized into non-fragmented form. However, this allows
8993 // accessing a pristine, sequential ftyp+moov init segment, even
8994 // after the file is finalized. It also allows dumping the whole
8995 // contents of the mdat box, to get the fragmented form of the
8996 // file.
8997
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_identification(pb, s)) < 0)
8998 ✗ return ret;
8999 2 update_size(pb, mov->mdat_pos);
9000 }
9001
1/2
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
209 } else if (mov->mode != MODE_AVIF) {
9002
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->flags & FF_MOV_FLAG_FASTSTART)
9003 3 mov->reserved_header_pos = avio_tell(pb);
9004 209 mov_write_mdat_tag(pb, mov);
9005 }
9006
9007 253 ff_parse_creation_time_metadata(s, &mov->time, 1);
9008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (mov->time)
9009 ✗ mov->time += 0x7C25B080; // 1970 based -> 1904 based
9010
9011
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->chapter_track)
9012
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9013 ✗ return ret;
9014
9015
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 252 times.
253 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
9016
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
9017
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
9018
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
9019 ✗ return ret;
9020 2 hint_track++;
9021 }
9022 }
9023 }
9024
9025
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 247 times.
253 if (mov->nb_meta_tmcd) {
9026 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
9027 "timecode", NULL, 0);
9028 /* Initialize the tmcd tracks */
9029
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
9030 8 AVStream *st = mov->tracks[i].st;
9031 8 t = global_tcr;
9032
9033
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
9034 AVTimecode tc;
9035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
9036 ✗ t = av_dict_get(st->metadata, "timecode", NULL, 0);
9037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
9038 ✗ continue;
9039
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
9040 ✗ continue;
9041
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
9042 ✗ return ret;
9043 6 tmcd_track++;
9044 }
9045 }
9046 }
9047
9048 253 avio_flush(pb);
9049
9050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
253 if (mov->flags & FF_MOV_FLAG_ISML)
9051 ✗ mov_write_isml_manifest(pb, mov, s);
9052
9053
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 214 times.
253 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
9054
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
39 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
9055
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9056 ✗ return ret;
9057 18 mov->moov_written = 1;
9058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
9059 ✗ mov->reserved_header_pos = avio_tell(pb);
9060 }
9061
9062 253 return 0;
9063 }
9064
9065 32 static int get_moov_size(AVFormatContext *s)
9066 {
9067 int ret;
9068 AVIOContext *moov_buf;
9069 32 MOVMuxContext *mov = s->priv_data;
9070
9071
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
9072 ✗ return ret;
9073
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
9074 ✗ return ret;
9075 32 return ffio_close_null_buf(moov_buf);
9076 }
9077
9078 ✗ static int get_sidx_size(AVFormatContext *s)
9079 {
9080 int ret;
9081 AVIOContext *buf;
9082 ✗ MOVMuxContext *mov = s->priv_data;
9083
9084 ✗ if ((ret = ffio_open_null_buf(&buf)) < 0)
9085 ✗ return ret;
9086 ✗ mov_write_sidx_tags(buf, mov, -1, 0);
9087 ✗ return ffio_close_null_buf(buf);
9088 }
9089
9090 /*
9091 * This function gets the moov size if moved to the top of the file: the chunk
9092 * offset table can switch between stco (32-bit entries) to co64 (64-bit
9093 * entries) when the moov is moved to the beginning, so the size of the moov
9094 * would change. It also updates the chunk offset tables.
9095 */
9096 3 static int compute_moov_size(AVFormatContext *s)
9097 {
9098 int i, moov_size, moov_size2;
9099 3 MOVMuxContext *mov = s->priv_data;
9100
9101 3 moov_size = get_moov_size(s);
9102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9103 ✗ return moov_size;
9104
9105
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
9106 8 mov->tracks[i].data_offset += moov_size;
9107
9108 3 moov_size2 = get_moov_size(s);
9109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
9110 ✗ return moov_size2;
9111
9112 /* if the size changed, we just switched from stco to co64 and need to
9113 * update the offsets */
9114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
9115 ✗ for (i = 0; i < mov->nb_tracks; i++)
9116 ✗ mov->tracks[i].data_offset += moov_size2 - moov_size;
9117
9118 3 return moov_size2;
9119 }
9120
9121 ✗ static int compute_sidx_size(AVFormatContext *s)
9122 {
9123 int i, sidx_size;
9124 ✗ MOVMuxContext *mov = s->priv_data;
9125
9126 ✗ sidx_size = get_sidx_size(s);
9127 ✗ if (sidx_size < 0)
9128 ✗ return sidx_size;
9129
9130 ✗ for (i = 0; i < mov->nb_tracks; i++)
9131 ✗ mov->tracks[i].data_offset += sidx_size;
9132
9133 ✗ return sidx_size;
9134 }
9135
9136 3 static int shift_data(AVFormatContext *s)
9137 {
9138 int moov_size;
9139 3 MOVMuxContext *mov = s->priv_data;
9140
9141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
9142 ✗ moov_size = compute_sidx_size(s);
9143 else
9144 3 moov_size = compute_moov_size(s);
9145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
9146 ✗ return moov_size;
9147
9148 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
9149 }
9150
9151 211 static void mov_write_mdat_size(AVFormatContext *s)
9152 {
9153 211 MOVMuxContext *mov = s->priv_data;
9154 211 AVIOContext *pb = s->pb;
9155
9156 /* Write size of mdat tag */
9157
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 if (mov->mdat_size + 8 <= UINT32_MAX) {
9158 211 avio_seek(pb, mov->mdat_pos, SEEK_SET);
9159 211 avio_wb32(pb, mov->mdat_size + 8);
9160
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 209 times.
211 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
9161 2 ffio_wfourcc(pb, "mdat"); // overwrite the original free/wide into a mdat
9162 } else {
9163 /* overwrite 'wide' placeholder atom */
9164 ✗ avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
9165 /* special value: real atom size will be 64 bit value after
9166 * tag field */
9167 ✗ avio_wb32(pb, 1);
9168 ✗ ffio_wfourcc(pb, "mdat");
9169 ✗ avio_wb64(pb, mov->mdat_size + 16);
9170 }
9171 211 }
9172
9173 253 static int mov_write_trailer(AVFormatContext *s)
9174 {
9175 253 MOVMuxContext *mov = s->priv_data;
9176 253 AVIOContext *pb = s->pb;
9177 253 int res = 0;
9178 int i;
9179 int64_t moov_pos;
9180
9181 /*
9182 * Before actually writing the trailer, make sure that there are no
9183 * dangling subtitles, that need a terminating sample.
9184 */
9185
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 253 times.
677 for (i = 0; i < mov->nb_tracks; i++) {
9186 424 MOVTrack *trk = &mov->tracks[i];
9187
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 423 times.
424 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
9188
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
9189 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
9190 1 trk->last_sample_is_subtitle_end = 1;
9191 }
9192 }
9193
9194 //Also check for a buffered EAC3 packet
9195
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 253 times.
677 for (i = 0; i < mov->nb_tracks; i++) {
9196 424 MOVTrack *trk = &mov->tracks[i];
9197
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 4 times.
424 if (trk->par->codec_id != AV_CODEC_ID_EAC3)
9198 420 continue;
9199 4 struct eac3_info *info = trk->eac3_priv;
9200
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)
9201 4 continue;
9202
9203 ✗ av_packet_move_ref(mov->pkt, info->pkt);
9204 ✗ info->eof = 1;
9205 ✗ res = mov_write_single_packet(s, mov->pkt);
9206 ✗ if (res < 0)
9207 ✗ return res;
9208
9209 ✗ av_packet_unref(mov->pkt);
9210 }
9211
9212 // Check if we have any tracks that require squashing.
9213 // In that case, we'll have to write the packet here.
9214
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 253 times.
253 if ((res = mov_write_squashed_packets(s)) < 0)
9215 ✗ return res;
9216
9217 // If there were no chapters when the header was written, but there
9218 // are chapters now, write them in the trailer. This only works
9219 // when we are not doing fragments.
9220
4/4
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 208 times.
✓ Branch 3 taken 44 times.
253 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
9221
3/4
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 207 times.
208 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
9222 ✗ mov->chapter_track = mov->nb_tracks++;
9223 ✗ if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
9224 ✗ return res;
9225 }
9226 }
9227
9228
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 209 times.
253 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
9229
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 42 times.
44 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9230
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 209 times.
211 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9231 2 mov_auto_flush_fragment(s, 1);
9232 2 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
9233
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < mov->nb_tracks; i++) {
9234 4 MOVTrack *track = &mov->tracks[i];
9235 4 track->data_offset = 0;
9236 4 av_free(track->cluster);
9237 4 track->cluster = track->cluster_written;
9238 4 track->entry = track->entry_written;
9239 4 track->cluster_written = NULL;
9240 4 track->entry_written = 0;
9241 4 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
9242 }
9243 // Clear the empty_moov flag, as we do want the moov to include
9244 // all the samples at this point.
9245 2 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
9246 }
9247
9248 211 moov_pos = avio_tell(pb);
9249
9250
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 2 times.
211 if (!(mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED))
9251 209 mov_write_mdat_size(s);
9252
9253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
9254
9255
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 208 times.
211 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
9256 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
9257 3 res = shift_data(s);
9258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
9259 ✗ return res;
9260 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9261
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9262 ✗ return res;
9263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 } else if (mov->reserved_moov_size > 0) {
9264 int64_t size;
9265 ✗ if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9266 ✗ return res;
9267 ✗ size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
9268 ✗ if (size < 8){
9269 ✗ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
9270 ✗ return AVERROR(EINVAL);
9271 }
9272 ✗ avio_wb32(pb, size);
9273 ✗ ffio_wfourcc(pb, "free");
9274 ✗ ffio_fill(pb, 0, size - 8);
9275 ✗ avio_seek(pb, moov_pos, SEEK_SET);
9276 } else {
9277
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 208 times.
208 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
9278 ✗ return res;
9279 }
9280
9281
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 209 times.
211 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
9282 // With hybrid fragmentation, only write the mdat size (hiding
9283 // the original moov and all the fragments within the mdat)
9284 // after we've successfully written the complete moov, to avoid
9285 // risk for an unreadable file if writing the final moov fails.
9286 2 mov_write_mdat_size(s);
9287 }
9288
9289 211 res = 0;
9290 } else {
9291 42 mov_auto_flush_fragment(s, 1);
9292
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 42 times.
216 for (i = 0; i < mov->nb_tracks; i++)
9293 174 mov->tracks[i].data_offset = 0;
9294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
9295 int64_t end;
9296 ✗ av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
9297 ✗ res = shift_data(s);
9298 ✗ if (res < 0)
9299 ✗ return res;
9300 ✗ end = avio_tell(pb);
9301 ✗ avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
9302 ✗ mov_write_sidx_tags(pb, mov, -1, 0);
9303 ✗ avio_seek(pb, end, SEEK_SET);
9304 }
9305
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 1 times.
42 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
9306 41 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
9307 41 res = mov_write_mfra_tag(pb, mov);
9308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (res < 0)
9309 ✗ return res;
9310 }
9311 }
9312
9313 253 return res;
9314 }
9315
9316 268 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
9317 const AVPacket *pkt)
9318 {
9319 268 int ret = 1;
9320
9321
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 249 times.
268 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
9322
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
19 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
9323 ✗ ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
9324
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
9325 ✗ ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
9326 }
9327
9328 268 return ret;
9329 }
9330
9331 #if CONFIG_AVIF_MUXER
9332 ✗ static int avif_write_trailer(AVFormatContext *s)
9333 {
9334 ✗ AVIOContext *pb = s->pb;
9335 ✗ MOVMuxContext *mov = s->priv_data;
9336 int64_t pos_backup, extent_offsets[2];
9337 uint8_t *buf;
9338 int buf_size, moov_size;
9339
9340 ✗ if (mov->moov_written) return 0;
9341
9342 ✗ mov->is_animated_avif = s->streams[0]->nb_frames > 1;
9343 ✗ if (mov->is_animated_avif && mov->nb_streams > 1) {
9344 // For animated avif with alpha channel, we need to write a tref tag
9345 // with type "auxl".
9346 ✗ MovTag *tag = mov_add_tref_tag(mov, &mov->tracks[1], MKTAG('a', 'u', 'x', 'l'));
9347 ✗ if (!tag)
9348 ✗ return AVERROR(ENOMEM);
9349
9350 ✗ int ret = mov_add_tref_id(mov, tag, 1);
9351 ✗ if (ret < 0)
9352 ✗ return ret;
9353 }
9354 ✗ mov_write_identification(pb, s);
9355 ✗ mov_write_meta_tag(pb, mov, s);
9356
9357 ✗ moov_size = get_moov_size(s);
9358 ✗ for (int i = 0; i < mov->nb_tracks; i++)
9359 ✗ mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
9360
9361 ✗ if (mov->is_animated_avif) {
9362 int ret;
9363 ✗ if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
9364 ✗ return ret;
9365 }
9366
9367 ✗ buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
9368 ✗ avio_wb32(pb, buf_size + 8);
9369 ✗ ffio_wfourcc(pb, "mdat");
9370
9371 // The offset for the YUV planes is the starting position of mdat.
9372 ✗ extent_offsets[0] = avio_tell(pb);
9373 // The offset for alpha plane is YUV offset + YUV size.
9374 ✗ extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
9375
9376 ✗ avio_write(pb, buf, buf_size);
9377
9378 // write extent offsets.
9379 ✗ pos_backup = avio_tell(pb);
9380 ✗ for (int i = 0; i < mov->nb_streams; i++) {
9381 ✗ if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
9382 ✗ av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
9383 ✗ return AVERROR_INVALIDDATA;
9384 }
9385 ✗ avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
9386 ✗ avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
9387 }
9388 ✗ avio_seek(pb, pos_backup, SEEK_SET);
9389
9390 ✗ return 0;
9391 }
9392 #endif
9393
9394 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
9395 static const AVCodecTag codec_3gp_tags[] = {
9396 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
9397 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9398 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9399 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9400 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
9401 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
9402 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9403 { AV_CODEC_ID_NONE, 0 },
9404 };
9405 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
9406 #endif
9407
9408 static const AVCodecTag codec_mp4_tags[] = {
9409 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
9410 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
9411 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
9412 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
9413 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
9414 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
9415 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
9416 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
9417 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
9418 { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') },
9419 { AV_CODEC_ID_APV, MKTAG('a', 'p', 'v', '1') },
9420 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
9421 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
9422 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
9423 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
9424 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
9425 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
9426 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
9427 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
9428 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
9429 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
9430 { AV_CODEC_ID_AV1, MKTAG('d', 'a', 'v', '1') },
9431 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
9432 { AV_CODEC_ID_APPLE_APAC, MKTAG('a', 'p', 'a', 'c') },
9433 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
9434 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
9435 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
9436 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
9437 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
9438 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
9439 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
9440 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
9441 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
9442 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
9443 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
9444 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
9445 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
9446 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
9447 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
9448 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
9449 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
9450 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
9451 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
9452 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
9453
9454 /* ISO/IEC 23003-5 integer formats */
9455 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
9456 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
9457 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
9458 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
9459 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
9460 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
9461 /* ISO/IEC 23003-5 floating-point formats */
9462 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
9463 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
9464 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
9465 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
9466
9467 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
9468
9469 { AV_CODEC_ID_NONE, 0 },
9470 };
9471 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
9472 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
9473 #endif
9474
9475 static const AVCodecTag codec_ism_tags[] = {
9476 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
9477 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
9478 { AV_CODEC_ID_NONE , 0 },
9479 };
9480
9481 static const AVCodecTag codec_ipod_tags[] = {
9482 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9483 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
9484 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9485 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
9486 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
9487 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
9488 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
9489 { AV_CODEC_ID_NONE, 0 },
9490 };
9491
9492 static const AVCodecTag codec_f4v_tags[] = {
9493 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
9494 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
9495 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
9496 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
9497 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
9498 { AV_CODEC_ID_NONE, 0 },
9499 };
9500
9501 #if CONFIG_AVIF_MUXER
9502
9503 static const AVOption avif_options[] = {
9504 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
9505 { "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 },
9506 { NULL },
9507 };
9508 static const AVCodecTag codec_avif_tags[] = {
9509 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
9510 { AV_CODEC_ID_NONE, 0 },
9511 };
9512 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
9513
9514 static const AVClass mov_avif_muxer_class = {
9515 .class_name = "avif muxer",
9516 .item_name = av_default_item_name,
9517 .option = avif_options,
9518 .version = LIBAVUTIL_VERSION_INT,
9519 };
9520 #endif
9521
9522 #if CONFIG_MOV_MUXER
9523 const FFOutputFormat ff_mov_muxer = {
9524 .p.name = "mov",
9525 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
9526 .p.extensions = "mov",
9527 .priv_data_size = sizeof(MOVMuxContext),
9528 .p.audio_codec = AV_CODEC_ID_AAC,
9529 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9530 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9531 .init = mov_init,
9532 .write_header = mov_write_header,
9533 .write_packet = mov_write_packet,
9534 .write_trailer = mov_write_trailer,
9535 .deinit = mov_free,
9536 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9537 .p.codec_tag = (const AVCodecTag* const []){
9538 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
9539 },
9540 .check_bitstream = mov_check_bitstream,
9541 .p.priv_class = &mov_isobmff_muxer_class,
9542 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9543 };
9544 #endif
9545 #if CONFIG_TGP_MUXER
9546 const FFOutputFormat ff_tgp_muxer = {
9547 .p.name = "3gp",
9548 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
9549 .p.extensions = "3gp",
9550 .priv_data_size = sizeof(MOVMuxContext),
9551 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9552 .p.video_codec = AV_CODEC_ID_H263,
9553 .init = mov_init,
9554 .write_header = mov_write_header,
9555 .write_packet = mov_write_packet,
9556 .write_trailer = mov_write_trailer,
9557 .deinit = mov_free,
9558 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9559 .p.codec_tag = codec_3gp_tags_list,
9560 .check_bitstream = mov_check_bitstream,
9561 .p.priv_class = &mov_isobmff_muxer_class,
9562 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9563 };
9564 #endif
9565 #if CONFIG_MP4_MUXER
9566 const FFOutputFormat ff_mp4_muxer = {
9567 .p.name = "mp4",
9568 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
9569 .p.mime_type = "video/mp4",
9570 .p.extensions = "mp4",
9571 .priv_data_size = sizeof(MOVMuxContext),
9572 .p.audio_codec = AV_CODEC_ID_AAC,
9573 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9574 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9575 .init = mov_init,
9576 .write_header = mov_write_header,
9577 .write_packet = mov_write_packet,
9578 .write_trailer = mov_write_trailer,
9579 .deinit = mov_free,
9580 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
9581 .p.codec_tag = mp4_codec_tags_list,
9582 .check_bitstream = mov_check_bitstream,
9583 .p.priv_class = &mov_isobmff_muxer_class,
9584 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9585 };
9586 #endif
9587 #if CONFIG_PSP_MUXER
9588 const FFOutputFormat ff_psp_muxer = {
9589 .p.name = "psp",
9590 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
9591 .p.extensions = "mp4,psp",
9592 .priv_data_size = sizeof(MOVMuxContext),
9593 .p.audio_codec = AV_CODEC_ID_AAC,
9594 .p.video_codec = CONFIG_LIBX264_ENCODER ?
9595 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
9596 .init = mov_init,
9597 .write_header = mov_write_header,
9598 .write_packet = mov_write_packet,
9599 .write_trailer = mov_write_trailer,
9600 .deinit = mov_free,
9601 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9602 .p.codec_tag = mp4_codec_tags_list,
9603 .check_bitstream = mov_check_bitstream,
9604 .p.priv_class = &mov_isobmff_muxer_class,
9605 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9606 };
9607 #endif
9608 #if CONFIG_TG2_MUXER
9609 const FFOutputFormat ff_tg2_muxer = {
9610 .p.name = "3g2",
9611 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
9612 .p.extensions = "3g2",
9613 .priv_data_size = sizeof(MOVMuxContext),
9614 .p.audio_codec = AV_CODEC_ID_AMR_NB,
9615 .p.video_codec = AV_CODEC_ID_H263,
9616 .init = mov_init,
9617 .write_header = mov_write_header,
9618 .write_packet = mov_write_packet,
9619 .write_trailer = mov_write_trailer,
9620 .deinit = mov_free,
9621 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9622 .p.codec_tag = codec_3gp_tags_list,
9623 .check_bitstream = mov_check_bitstream,
9624 .p.priv_class = &mov_isobmff_muxer_class,
9625 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9626 };
9627 #endif
9628 #if CONFIG_IPOD_MUXER
9629 const FFOutputFormat ff_ipod_muxer = {
9630 .p.name = "ipod",
9631 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
9632 .p.mime_type = "video/mp4",
9633 .p.extensions = "m4v,m4a,m4b",
9634 .priv_data_size = sizeof(MOVMuxContext),
9635 .p.audio_codec = AV_CODEC_ID_AAC,
9636 .p.video_codec = AV_CODEC_ID_H264,
9637 .init = mov_init,
9638 .write_header = mov_write_header,
9639 .write_packet = mov_write_packet,
9640 .write_trailer = mov_write_trailer,
9641 .deinit = mov_free,
9642 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9643 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
9644 .check_bitstream = mov_check_bitstream,
9645 .p.priv_class = &mov_isobmff_muxer_class,
9646 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9647 };
9648 #endif
9649 #if CONFIG_ISMV_MUXER
9650 const FFOutputFormat ff_ismv_muxer = {
9651 .p.name = "ismv",
9652 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
9653 .p.mime_type = "video/mp4",
9654 .p.extensions = "ismv,isma",
9655 .priv_data_size = sizeof(MOVMuxContext),
9656 .p.audio_codec = AV_CODEC_ID_AAC,
9657 .p.video_codec = AV_CODEC_ID_H264,
9658 .init = mov_init,
9659 .write_header = mov_write_header,
9660 .write_packet = mov_write_packet,
9661 .write_trailer = mov_write_trailer,
9662 .deinit = mov_free,
9663 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
9664 .p.codec_tag = (const AVCodecTag* const []){
9665 codec_mp4_tags, codec_ism_tags, 0 },
9666 .check_bitstream = mov_check_bitstream,
9667 .p.priv_class = &mov_isobmff_muxer_class,
9668 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9669 };
9670 #endif
9671 #if CONFIG_F4V_MUXER
9672 const FFOutputFormat ff_f4v_muxer = {
9673 .p.name = "f4v",
9674 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
9675 .p.mime_type = "application/f4v",
9676 .p.extensions = "f4v",
9677 .priv_data_size = sizeof(MOVMuxContext),
9678 .p.audio_codec = AV_CODEC_ID_AAC,
9679 .p.video_codec = AV_CODEC_ID_H264,
9680 .init = mov_init,
9681 .write_header = mov_write_header,
9682 .write_packet = mov_write_packet,
9683 .write_trailer = mov_write_trailer,
9684 .deinit = mov_free,
9685 .p.flags = AVFMT_GLOBALHEADER,
9686 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
9687 .check_bitstream = mov_check_bitstream,
9688 .p.priv_class = &mov_isobmff_muxer_class,
9689 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9690 };
9691 #endif
9692 #if CONFIG_AVIF_MUXER
9693 const FFOutputFormat ff_avif_muxer = {
9694 .p.name = "avif",
9695 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
9696 .p.mime_type = "image/avif",
9697 .p.extensions = "avif",
9698 .priv_data_size = sizeof(MOVMuxContext),
9699 .p.video_codec = AV_CODEC_ID_AV1,
9700 .init = mov_init,
9701 .write_header = mov_write_header,
9702 .write_packet = mov_write_packet,
9703 .write_trailer = avif_write_trailer,
9704 .deinit = mov_free,
9705 .p.flags = AVFMT_GLOBALHEADER,
9706 .p.codec_tag = codec_avif_tags_list,
9707 .p.priv_class = &mov_avif_muxer_class,
9708 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
9709 };
9710 #endif
9711