FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2025-03-08 20:38:41
Exec Total Coverage
Lines: 3592 5386 66.7%
Functions: 172 226 76.1%
Branches: 2103 3687 57.0%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "libavcodec/ac3_parser_internal.h"
41 #include "libavcodec/dnxhddata.h"
42 #include "libavcodec/flac.h"
43 #include "libavcodec/get_bits.h"
44
45 #include "libavcodec/internal.h"
46 #include "libavcodec/put_bits.h"
47 #include "libavcodec/vc1_common.h"
48 #include "libavcodec/raw.h"
49 #include "internal.h"
50 #include "libavutil/avstring.h"
51 #include "libavutil/channel_layout.h"
52 #include "libavutil/csp.h"
53 #include "libavutil/intfloat.h"
54 #include "libavutil/mathematics.h"
55 #include "libavutil/libm.h"
56 #include "libavutil/mem.h"
57 #include "libavutil/opt.h"
58 #include "libavutil/dict.h"
59 #include "libavutil/pixdesc.h"
60 #include "libavutil/stereo3d.h"
61 #include "libavutil/timecode.h"
62 #include "libavutil/dovi_meta.h"
63 #include "libavutil/uuid.h"
64 #include "hevc.h"
65 #include "rtpenc.h"
66 #include "nal.h"
67 #include "mov_chan.h"
68 #include "movenc_ttml.h"
69 #include "mux.h"
70 #include "rawutils.h"
71 #include "ttmlenc.h"
72 #include "version.h"
73 #include "vpcc.h"
74 #include "vvc.h"
75
76 static const AVOption options[] = {
77 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
78 { "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},
79 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
80 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "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 },
82 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
83 { "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 },
84 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
85 { "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},
86 { "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},
87 { "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},
88 { "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},
89 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
90 { "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" },
91 { "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" },
92 { "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" },
93 { "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" },
94 { "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" },
95 { "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" },
96 { "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" },
97 { "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" },
98 { "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" },
99 { "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" },
100 { "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" },
101 { "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" },
102 { "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" },
103 { "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 },
104 { "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" },
105 { "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" },
106 { "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" },
107 { "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" },
108 { "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" },
109 { "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" },
110 { "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" },
111 { "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" },
112 { "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" },
113 { "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" },
114 { "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" },
115 { "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},
116 { "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},
117 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
118 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
119 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
120 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
121 { "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},
122 { "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},
123 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "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"},
125 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
128 { NULL },
129 };
130
131 static const AVClass mov_isobmff_muxer_class = {
132 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
133 .item_name = av_default_item_name,
134 .option = options,
135 .version = LIBAVUTIL_VERSION_INT,
136 };
137
138 static int get_moov_size(AVFormatContext *s);
139 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
140
141 24 static int utf8len(const uint8_t *b)
142 {
143 24 int len = 0;
144 int val;
145
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 24 times.
497 while (*b) {
146
3/8
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 473 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 473 times.
473 GET_UTF8(val, *b++, return -1;)
147 473 len++;
148 }
149 24 return len;
150 }
151
152 //FIXME support 64 bit variant with wide placeholders
153 6185 static int64_t update_size(AVIOContext *pb, int64_t pos)
154 {
155 6185 int64_t curpos = avio_tell(pb);
156 6185 avio_seek(pb, pos, SEEK_SET);
157 6185 avio_wb32(pb, curpos - pos); /* rewrite size */
158 6185 avio_seek(pb, curpos, SEEK_SET);
159
160 6185 return curpos - pos;
161 }
162
163 333 static int co64_required(const MOVTrack *track)
164 {
165
3/4
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 243 times.
333 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
166 return 1;
167 333 return 0;
168 }
169
170 19261 static int is_cover_image(const AVStream *st)
171 {
172 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
173 * is encoded as sparse video track */
174
3/4
✓ Branch 0 taken 19261 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 19249 times.
19261 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
175 }
176
177 6 static int rtp_hinting_needed(const AVStream *st)
178 {
179 /* Add hint tracks for each real audio and video stream */
180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
181 return 0;
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
183
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
184 }
185
186 /* Chunk offset atom */
187 333 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
188 {
189 int i;
190 333 int mode64 = co64_required(track); // use 32 bit size variant if possible
191 333 int64_t pos = avio_tell(pb);
192 333 avio_wb32(pb, 0); /* size */
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mode64)
194 ffio_wfourcc(pb, "co64");
195 else
196 333 ffio_wfourcc(pb, "stco");
197 333 avio_wb32(pb, 0); /* version & flags */
198 333 avio_wb32(pb, track->chunkCount); /* entry count */
199
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
200
2/2
✓ Branch 0 taken 10483 times.
✓ Branch 1 taken 3098 times.
13581 if (!track->cluster[i].chunkNum)
201 10483 continue;
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3098 times.
3098 if (mode64 == 1)
203 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
204 else
205 3098 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
206 }
207 333 return update_size(pb, pos);
208 }
209
210 /* Sample size atom */
211 333 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
212 {
213 333 int equalChunks = 1;
214 333 int i, j, entries = 0, tst = -1, oldtst = -1;
215
216 333 int64_t pos = avio_tell(pb);
217 333 avio_wb32(pb, 0); /* size */
218 333 ffio_wfourcc(pb, "stsz");
219 333 avio_wb32(pb, 0); /* version & flags */
220
221
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
222 13581 tst = track->cluster[i].size / track->cluster[i].entries;
223
4/4
✓ Branch 0 taken 13338 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 8730 times.
✓ Branch 3 taken 4608 times.
13581 if (oldtst != -1 && tst != oldtst)
224 8730 equalChunks = 0;
225 13581 oldtst = tst;
226 13581 entries += track->cluster[i].entries;
227 }
228
4/4
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 90 times.
442 if (equalChunks && track->entry) {
229
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
230 109 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
231 109 avio_wb32(pb, sSize); // sample size
232 109 avio_wb32(pb, entries); // sample count
233 } else {
234 224 avio_wb32(pb, 0); // sample size
235 224 avio_wb32(pb, entries); // sample count
236
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 224 times.
10116 for (i = 0; i < track->entry; i++) {
237
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 9892 times.
19784 for (j = 0; j < track->cluster[i].entries; j++) {
238 9892 avio_wb32(pb, track->cluster[i].size /
239 9892 track->cluster[i].entries);
240 }
241 }
242 }
243 333 return update_size(pb, pos);
244 }
245
246 /* Sample to chunk atom */
247 333 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
248 {
249 333 int index = 0, oldval = -1, i;
250 int64_t entryPos, curpos;
251
252 333 int64_t pos = avio_tell(pb);
253 333 avio_wb32(pb, 0); /* size */
254 333 ffio_wfourcc(pb, "stsc");
255 333 avio_wb32(pb, 0); // version & flags
256 333 entryPos = avio_tell(pb);
257 333 avio_wb32(pb, track->chunkCount); // entry count
258
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
259
4/4
✓ Branch 0 taken 11299 times.
✓ Branch 1 taken 2282 times.
✓ Branch 2 taken 816 times.
✓ Branch 3 taken 10483 times.
13581 if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
260 816 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
261 816 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
262 816 avio_wb32(pb, 0x1); // sample description index
263 816 oldval = track->cluster[i].samples_in_chunk;
264 816 index++;
265 }
266 }
267 333 curpos = avio_tell(pb);
268 333 avio_seek(pb, entryPos, SEEK_SET);
269 333 avio_wb32(pb, index); // rewrite size
270 333 avio_seek(pb, curpos, SEEK_SET);
271
272 333 return update_size(pb, pos);
273 }
274
275 /* Sync sample atom */
276 58 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
277 {
278 int64_t curpos, entryPos;
279 58 int i, index = 0;
280 58 int64_t pos = avio_tell(pb);
281 58 avio_wb32(pb, 0); // size
282
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
283 58 avio_wb32(pb, 0); // version & flags
284 58 entryPos = avio_tell(pb);
285 58 avio_wb32(pb, track->entry); // entry count
286
2/2
✓ Branch 0 taken 3209 times.
✓ Branch 1 taken 58 times.
3267 for (i = 0; i < track->entry; i++) {
287
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 3002 times.
3209 if (track->cluster[i].flags & flag) {
288 207 avio_wb32(pb, i + 1);
289 207 index++;
290 }
291 }
292 58 curpos = avio_tell(pb);
293 58 avio_seek(pb, entryPos, SEEK_SET);
294 58 avio_wb32(pb, index); // rewrite size
295 58 avio_seek(pb, curpos, SEEK_SET);
296 58 return update_size(pb, pos);
297 }
298
299 /* Sample dependency atom */
300 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
301 {
302 int i;
303 uint8_t leading, dependent, reference, redundancy;
304 3 int64_t pos = avio_tell(pb);
305 3 avio_wb32(pb, 0); // size
306 3 ffio_wfourcc(pb, "sdtp");
307 3 avio_wb32(pb, 0); // version & flags
308
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
309 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
310 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
311
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
312 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
313 }
314
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
315 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
316 }
317 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
318 13 (reference << 2) | redundancy);
319 }
320 3 return update_size(pb, pos);
321 }
322
323 #if CONFIG_IAMFENC
324 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
325 {
326 AVIOContext *dyn_bc;
327 5 int64_t pos = avio_tell(pb);
328 5 uint8_t *dyn_buf = NULL;
329 int dyn_size;
330 5 int ret = avio_open_dyn_buf(&dyn_bc);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
332 return ret;
333
334 5 avio_wb32(pb, 0);
335 5 ffio_wfourcc(pb, "iacb");
336 5 avio_w8(pb, 1); // configurationVersion
337
338 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
340 return ret;
341
342 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
343 5 ffio_write_leb(pb, dyn_size);
344 5 avio_write(pb, dyn_buf, dyn_size);
345 5 av_free(dyn_buf);
346
347 5 return update_size(pb, pos);
348 }
349 #endif
350
351 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
352 {
353 avio_wb32(pb, 0x11); /* size */
354 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
355 else ffio_wfourcc(pb, "damr");
356 ffio_wfourcc(pb, "FFMP");
357 avio_w8(pb, 0); /* decoder version */
358
359 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
360 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
361 avio_w8(pb, 0x01); /* Frames per sample */
362 return 0x11;
363 }
364
365 struct eac3_info {
366 AVPacket *pkt;
367 uint8_t ec3_done;
368 uint8_t num_blocks;
369
370 /* Layout of the EC3SpecificBox */
371 /* maximum bitrate */
372 uint16_t data_rate;
373 int8_t ac3_bit_rate_code;
374 /* number of independent substreams */
375 uint8_t num_ind_sub;
376 struct {
377 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
378 uint8_t fscod;
379 /* bit stream identification 5 bits */
380 uint8_t bsid;
381 /* one bit reserved */
382 /* audio service mixing (not supported yet) 1 bit */
383 /* bit stream mode 3 bits */
384 uint8_t bsmod;
385 /* audio coding mode 3 bits */
386 uint8_t acmod;
387 /* sub woofer on 1 bit */
388 uint8_t lfeon;
389 /* 3 bits reserved */
390 /* number of dependent substreams associated with this substream 4 bits */
391 uint8_t num_dep_sub;
392 /* channel locations of the dependent substream(s), if any, 9 bits */
393 uint16_t chan_loc;
394 /* if there is no dependent substream, then one bit reserved instead */
395 } substream[1]; /* TODO: support 8 independent substreams */
396 };
397
398 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
399 {
400 5 struct eac3_info *info = track->eac3_priv;
401 PutBitContext pbc;
402 uint8_t buf[3];
403
404
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!info || !info->ec3_done) {
405 av_log(s, AV_LOG_ERROR,
406 "Cannot write moov atom before AC3 packets."
407 " Set the delay_moov flag to fix this.\n");
408 return AVERROR(EINVAL);
409 }
410
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
412 av_log(s, AV_LOG_ERROR,
413 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
414 "ISOBMFF specification in ETSI TS 102 366!\n",
415 info->substream[0].bsid);
416 return AVERROR(EINVAL);
417 }
418
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
420 av_log(s, AV_LOG_ERROR,
421 "No valid AC3 bit rate code for data rate of %d!\n",
422 info->data_rate);
423 return AVERROR(EINVAL);
424 }
425
426 5 avio_wb32(pb, 11);
427 5 ffio_wfourcc(pb, "dac3");
428
429 5 init_put_bits(&pbc, buf, sizeof(buf));
430 5 put_bits(&pbc, 2, info->substream[0].fscod);
431 5 put_bits(&pbc, 5, info->substream[0].bsid);
432 5 put_bits(&pbc, 3, info->substream[0].bsmod);
433 5 put_bits(&pbc, 3, info->substream[0].acmod);
434 5 put_bits(&pbc, 1, info->substream[0].lfeon);
435 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
436 5 put_bits(&pbc, 5, 0); // reserved
437
438 5 flush_put_bits(&pbc);
439 5 avio_write(pb, buf, sizeof(buf));
440
441 5 return 11;
442 }
443
444 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
445 {
446 1039 AC3HeaderInfo *hdr = NULL;
447 struct eac3_info *info;
448 int num_blocks, ret;
449
450
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
451
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
452 return AVERROR(ENOMEM);
453
454 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
455 }
456 1039 info = track->eac3_priv;
457
458
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
1039 if (!info->pkt && !(info->pkt = av_packet_alloc()))
459 return AVERROR(ENOMEM);
460
461
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1038 times.
1039 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
463 goto end;
464
465 /* drop the packets until we see a good one */
466
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
467 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
468 1 ret = 0;
469 } else
470 ret = AVERROR_INVALIDDATA;
471 1 goto end;
472 }
473
474 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
475 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
476 hdr->ac3_bit_rate_code);
477 1038 num_blocks = hdr->num_blocks;
478
479
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
480 /* AC-3 substream must be the first one */
481
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
482 ret = AVERROR(EINVAL);
483 goto end;
484 }
485
486 /* this should always be the case, given that our AC-3 parser
487 * concatenates dependent frames to their independent parent */
488
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
489
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
490 /* substream ids must be incremental */
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
492 ret = AVERROR(EINVAL);
493 goto end;
494 }
495
496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
497 //info->num_ind_sub++;
498 avpriv_request_sample(mov->fc, "Multiple independent substreams");
499 ret = AVERROR_PATCHWELCOME;
500 goto end;
501
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
502
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 hdr->substreamid == 0 && info->substream[0].bsid) {
503 1 info->ec3_done = 1;
504 1 goto concatenate;
505 }
506 } else {
507 if (hdr->substreamid != 0) {
508 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
509 ret = AVERROR_PATCHWELCOME;
510 goto end;
511 }
512 }
513
514 /* fill the info needed for the "dec3" atom */
515 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
516 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
517 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
518 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
519 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
520
521
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
522 // with AC-3 we only require the information of a single packet,
523 // so we can finish as soon as the basic values of the bit stream
524 // have been set to the track's informational structure.
525 4 info->ec3_done = 1;
526 4 goto concatenate;
527 }
528
529 /* Parse dependent substream(s), if any */
530
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
531 int cumul_size = hdr->frame_size;
532 int parent = hdr->substreamid;
533
534 while (cumul_size != pkt->size) {
535 GetBitContext gbc;
536 int i;
537 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
538 if (ret < 0)
539 goto end;
540 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
541 ret = AVERROR(EINVAL);
542 goto end;
543 }
544 info->substream[parent].num_dep_sub++;
545 ret /= 8;
546
547 /* header is parsed up to lfeon, but custom channel map may be needed */
548 init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret);
549 /* skip bsid */
550 skip_bits(&gbc, 5);
551 /* skip volume control params */
552 for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
553 skip_bits(&gbc, 5); // skip dialog normalization
554 if (get_bits1(&gbc)) {
555 skip_bits(&gbc, 8); // skip compression gain word
556 }
557 }
558 /* get the dependent stream channel map, if exists */
559 if (get_bits1(&gbc))
560 info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
561 else
562 info->substream[parent].chan_loc |= hdr->channel_mode;
563 cumul_size += hdr->frame_size;
564 }
565 }
566 }
567
568 1033 concatenate:
569
2/4
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
1038 if (!info->num_blocks && num_blocks == 6) {
570 1038 ret = pkt->size;
571 1038 goto end;
572 }
573 else if (info->num_blocks + num_blocks > 6) {
574 ret = AVERROR_INVALIDDATA;
575 goto end;
576 }
577
578 if (!info->num_blocks) {
579 ret = av_packet_ref(info->pkt, pkt);
580 if (!ret)
581 info->num_blocks = num_blocks;
582 goto end;
583 } else {
584 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
585 goto end;
586 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
587 info->num_blocks += num_blocks;
588 info->pkt->duration += pkt->duration;
589 if (info->num_blocks != 6)
590 goto end;
591 av_packet_unref(pkt);
592 av_packet_move_ref(pkt, info->pkt);
593 info->num_blocks = 0;
594 }
595 ret = pkt->size;
596
597 1039 end:
598 1039 av_free(hdr);
599
600 1039 return ret;
601 }
602
603 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
604 {
605 PutBitContext pbc;
606 uint8_t *buf;
607 struct eac3_info *info;
608 int size, i;
609
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
611 av_log(s, AV_LOG_ERROR,
612 "Cannot write moov atom before EAC3 packets parsed.\n");
613 return AVERROR(EINVAL);
614 }
615
616 1 info = track->eac3_priv;
617 1 size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3);
618 1 buf = av_malloc(size);
619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
620 return AVERROR(ENOMEM);
621 }
622
623 1 init_put_bits(&pbc, buf, size);
624 1 put_bits(&pbc, 13, info->data_rate);
625 1 put_bits(&pbc, 3, info->num_ind_sub);
626
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
627 1 put_bits(&pbc, 2, info->substream[i].fscod);
628 1 put_bits(&pbc, 5, info->substream[i].bsid);
629 1 put_bits(&pbc, 1, 0); /* reserved */
630 1 put_bits(&pbc, 1, 0); /* asvc */
631 1 put_bits(&pbc, 3, info->substream[i].bsmod);
632 1 put_bits(&pbc, 3, info->substream[i].acmod);
633 1 put_bits(&pbc, 1, info->substream[i].lfeon);
634 1 put_bits(&pbc, 5, 0); /* reserved */
635 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
636
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
637 1 put_bits(&pbc, 1, 0); /* reserved */
638 } else {
639 put_bits(&pbc, 9, info->substream[i].chan_loc);
640 }
641 }
642 1 flush_put_bits(&pbc);
643 1 size = put_bytes_output(&pbc);
644
645 1 avio_wb32(pb, size + 8);
646 1 ffio_wfourcc(pb, "dec3");
647 1 avio_write(pb, buf, size);
648
649 1 av_free(buf);
650
651 1 return size;
652 }
653
654 /**
655 * This function writes extradata "as is".
656 * Extradata must be formatted like a valid atom (with size and tag).
657 */
658 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
659 {
660 12 avio_write(pb, track->par->extradata, track->par->extradata_size);
661 12 return track->par->extradata_size;
662 }
663
664 static int mov_write_enda_tag(AVIOContext *pb)
665 {
666 avio_wb32(pb, 10);
667 ffio_wfourcc(pb, "enda");
668 avio_wb16(pb, 1); /* little endian */
669 return 10;
670 }
671
672 2 static int mov_write_enda_tag_be(AVIOContext *pb)
673 {
674 2 avio_wb32(pb, 10);
675 2 ffio_wfourcc(pb, "enda");
676 2 avio_wb16(pb, 0); /* big endian */
677 2 return 10;
678 }
679
680 316 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
681 {
682 316 int i = 3;
683 316 avio_w8(pb, tag);
684
2/2
✓ Branch 0 taken 948 times.
✓ Branch 1 taken 316 times.
1264 for (; i > 0; i--)
685 948 avio_w8(pb, (size >> (7 * i)) | 0x80);
686 316 avio_w8(pb, size & 0x7F);
687 316 }
688
689 210 static unsigned compute_avg_bitrate(MOVTrack *track)
690 {
691 210 uint64_t size = 0;
692 int i;
693
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 173 times.
210 if (!track->track_duration)
694 37 return 0;
695
2/2
✓ Branch 0 taken 8974 times.
✓ Branch 1 taken 173 times.
9147 for (i = 0; i < track->entry; i++)
696 8974 size += track->cluster[i].size;
697 173 return size * 8 * track->timescale / track->track_duration;
698 }
699
700 struct mpeg4_bit_rate_values {
701 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
702 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
703 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
704 };
705
706 210 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
707 {
708 420 const AVPacketSideData *sd = track->st ?
709 209 av_packet_side_data_get(track->st->codecpar->coded_side_data,
710 209 track->st->codecpar->nb_coded_side_data,
711
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 1 times.
210 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
712
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 176 times.
210 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
713 210 struct mpeg4_bit_rate_values bit_rates = { 0 };
714
715 210 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
716
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 83 times.
210 if (!bit_rates.avg_bit_rate) {
717 // if the average bit rate cannot be calculated at this point, such as
718 // in the case of fragmented MP4, utilize the following values as
719 // fall-back in priority order:
720 //
721 // 1. average bit rate property
722 // 2. bit rate (usually average over the whole clip)
723 // 3. maximum bit rate property
724
725
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
127 if (props && props->avg_bitrate) {
726 3 bit_rates.avg_bit_rate = props->avg_bitrate;
727
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 122 times.
124 } else if (track->par->bit_rate) {
728 2 bit_rates.avg_bit_rate = track->par->bit_rate;
729
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
122 } else if (props && props->max_bitrate) {
730 bit_rates.avg_bit_rate = props->max_bitrate;
731 }
732 }
733
734 // (FIXME should be max rate in any 1 sec window)
735 210 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
736 bit_rates.avg_bit_rate);
737
738 // utilize values from properties if we have them available
739
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 176 times.
210 if (props) {
740 // no avg_bitrate signals that the track is VBR
741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!props->avg_bitrate)
742 bit_rates.avg_bit_rate = props->avg_bitrate;
743 34 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
744 props->max_bitrate);
745 34 bit_rates.buffer_size = props->buffer_size / 8;
746 }
747
748 210 return bit_rates;
749 }
750
751 79 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
752 {
753 79 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
754 79 int64_t pos = avio_tell(pb);
755
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0;
756
757 79 avio_wb32(pb, 0); // size
758 79 ffio_wfourcc(pb, "esds");
759 79 avio_wb32(pb, 0); // Version
760
761 // ES descriptor
762 79 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
763 79 avio_wb16(pb, track->track_id);
764 79 avio_w8(pb, 0x00); // flags (= no flags)
765
766 // DecoderConfig descriptor
767 79 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
768
769 // Object type indication
770
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 track->par->codec_id == AV_CODEC_ID_MP3) &&
772 track->par->sample_rate > 24000)
773 avio_w8(pb, 0x6B); // 11172-3
774 else
775 79 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
776
777 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
778 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
780 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
781
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 25 times.
79 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
782 54 avio_w8(pb, 0x15); // flags (= Audiostream)
783 else
784 25 avio_w8(pb, 0x11); // flags (= Visualstream)
785
786 79 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
787 79 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
788 79 avio_wb32(pb, bit_rates.avg_bit_rate);
789
790
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if (track->vos_len) {
791 // DecoderSpecific info descriptor
792 79 put_descr(pb, 0x05, track->vos_len);
793 79 avio_write(pb, track->vos_data, track->vos_len);
794 }
795
796 // SL descriptor
797 79 put_descr(pb, 0x06, 1);
798 79 avio_w8(pb, 0x02);
799 79 return update_size(pb, pos);
800 }
801
802 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
803 {
804
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
805
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
806
2/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
154 codec_id == AV_CODEC_ID_PCM_F32LE ||
807 codec_id == AV_CODEC_ID_PCM_F64LE;
808 }
809
810 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
811 {
812
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
813
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
814
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
150 codec_id == AV_CODEC_ID_PCM_F32BE ||
815 codec_id == AV_CODEC_ID_PCM_F64BE;
816 }
817
818 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
819 {
820 int ret;
821 int64_t pos = avio_tell(pb);
822 avio_wb32(pb, 0);
823 avio_wl32(pb, track->tag); // store it byteswapped
824 track->par->codec_tag = av_bswap16(track->tag >> 16);
825 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
826 return ret;
827 return update_size(pb, pos);
828 }
829
830 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
831 {
832 int ret;
833 int64_t pos = avio_tell(pb);
834 avio_wb32(pb, 0);
835 ffio_wfourcc(pb, "wfex");
836 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
837 return ret;
838 return update_size(pb, pos);
839 }
840
841 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
842 {
843 int64_t pos = avio_tell(pb);
844 avio_wb32(pb, 0);
845 ffio_wfourcc(pb, "dfLa");
846 avio_w8(pb, 0); /* version */
847 avio_wb24(pb, 0); /* flags */
848
849 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
850 if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
851 return AVERROR_INVALIDDATA;
852
853 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
854 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
855 avio_wb24(pb, track->par->extradata_size); /* Length */
856 avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
857
858 return update_size(pb, pos);
859 }
860
861 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
862 {
863 int64_t pos = avio_tell(pb);
864 int channels, channel_map;
865 avio_wb32(pb, 0);
866 ffio_wfourcc(pb, "dOps");
867 avio_w8(pb, 0); /* Version */
868 if (track->par->extradata_size < 19) {
869 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
870 return AVERROR_INVALIDDATA;
871 }
872 /* extradata contains an Ogg OpusHead, other than byte-ordering and
873 OpusHead's preceeding magic/version, OpusSpecificBox is currently
874 identical. */
875 channels = AV_RB8(track->par->extradata + 9);
876 channel_map = AV_RB8(track->par->extradata + 18);
877
878 avio_w8(pb, channels); /* OuputChannelCount */
879 avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */
880 avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */
881 avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */
882 avio_w8(pb, channel_map); /* ChannelMappingFamily */
883 /* Write the rest of the header out without byte-swapping. */
884 if (channel_map) {
885 if (track->par->extradata_size < 21 + channels) {
886 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
887 return AVERROR_INVALIDDATA;
888 }
889 avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */
890 }
891
892 return update_size(pb, pos);
893 }
894
895 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
896 {
897 int64_t pos = avio_tell(pb);
898 int length;
899 avio_wb32(pb, 0);
900 ffio_wfourcc(pb, "dmlp");
901
902 if (track->vos_len < 20) {
903 av_log(s, AV_LOG_ERROR,
904 "Cannot write moov atom before TrueHD packets."
905 " Set the delay_moov flag to fix this.\n");
906 return AVERROR(EINVAL);
907 }
908
909 length = (AV_RB16(track->vos_data) & 0xFFF) * 2;
910 if (length < 20 || length > track->vos_len)
911 return AVERROR_INVALIDDATA;
912
913 // Only TrueHD is supported
914 if (AV_RB32(track->vos_data + 4) != 0xF8726FBA)
915 return AVERROR_INVALIDDATA;
916
917 avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */
918 avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */
919 avio_wb32(pb, 0); /* reserved */
920
921 return update_size(pb, pos);
922 }
923
924 65 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
925 {
926 65 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
927 65 AVChannelLayout ch_layout = { 0 };
928 int64_t pos;
929 int ambisonic_order, ambi_channels, non_diegetic_channels;
930 int i, ret;
931
932
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (!str)
933 65 return 0;
934
935 ret = av_channel_layout_from_string(&ch_layout, str->value);
936 if (ret < 0) {
937 if (ret == AVERROR(EINVAL)) {
938 invalid:
939 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
940 ret = 0;
941 }
942 av_channel_layout_uninit(&ch_layout);
943 return ret;
944 }
945
946 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
947 goto invalid;
948
949 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
950 if (ambisonic_order < 0)
951 goto invalid;
952
953 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
954 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
955 if (non_diegetic_channels &&
956 (non_diegetic_channels != 2 ||
957 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
958 goto invalid;
959
960 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
961
962 pos = avio_tell(pb);
963
964 avio_wb32(pb, 0); // Size
965 ffio_wfourcc(pb, "SA3D");
966 avio_w8(pb, 0); // version
967 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
968 avio_wb32(pb, ambisonic_order); // ambisonic_order
969 avio_w8(pb, 0); // ambisonic_channel_ordering
970 avio_w8(pb, 0); // ambisonic_normalization
971 avio_wb32(pb, ch_layout.nb_channels); // num_channels
972 for (i = 0; i < ambi_channels; i++)
973 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
974 for (; i < ch_layout.nb_channels; i++)
975 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
976
977 av_channel_layout_uninit(&ch_layout);
978
979 return update_size(pb, pos);
980 }
981
982 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
983 {
984 uint32_t layout_tag, bitmap, *channel_desc;
985 40 int64_t pos = avio_tell(pb);
986 int num_desc, ret;
987
988
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
989 return 0;
990
991 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
992 &bitmap, &channel_desc);
993
994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
995 if (ret == AVERROR(ENOSYS)) {
996 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
997 "lack of channel information\n");
998 ret = 0;
999 }
1000
1001 return ret;
1002 }
1003
1004
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
40 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1006 1 channel_desc = av_malloc(sizeof(*channel_desc));
1007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1008 return AVERROR(ENOMEM);
1009
1010 1 layout_tag = 0;
1011 1 bitmap = 0;
1012 1 *channel_desc = 3; // channel label "Center"
1013 }
1014
1015
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1016
1017 40 avio_wb32(pb, 0); // Size
1018 40 ffio_wfourcc(pb, "chan"); // Type
1019 40 avio_w8(pb, 0); // Version
1020 40 avio_wb24(pb, 0); // Flags
1021 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1022 40 avio_wb32(pb, bitmap); // mChannelBitmap
1023 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1024
1025
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1026 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1027 3 avio_wb32(pb, 0); // mChannelFlags
1028 3 avio_wl32(pb, 0); // mCoordinates[0]
1029 3 avio_wl32(pb, 0); // mCoordinates[1]
1030 3 avio_wl32(pb, 0); // mCoordinates[2]
1031 }
1032
1033 40 av_free(channel_desc);
1034
1035 40 return update_size(pb, pos);
1036 }
1037
1038 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1039 {
1040 15 int64_t pos = avio_tell(pb);
1041
1042 15 avio_wb32(pb, 0); /* size */
1043 15 ffio_wfourcc(pb, "wave");
1044
1045
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1046 15 avio_wb32(pb, 12); /* size */
1047 15 ffio_wfourcc(pb, "frma");
1048 15 avio_wl32(pb, track->tag);
1049 }
1050
1051
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1052 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1053 3 avio_wb32(pb, 12); /* size */
1054 3 ffio_wfourcc(pb, "mp4a");
1055 3 avio_wb32(pb, 0);
1056 3 mov_write_esds_tag(pb, track);
1057
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1058 mov_write_enda_tag(pb);
1059
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1060 2 mov_write_enda_tag_be(pb);
1061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1062 mov_write_amr_tag(pb, track);
1063
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1064 1 mov_write_ac3_tag(s, pb, track);
1065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1066 mov_write_eac3_tag(s, pb, track);
1067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1068 track->par->codec_id == AV_CODEC_ID_QDM2) {
1069 9 mov_write_extradata_tag(pb, track);
1070 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1071 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1072 mov_write_ms_tag(s, pb, track);
1073 }
1074
1075 15 avio_wb32(pb, 8); /* size */
1076 15 avio_wb32(pb, 0); /* null tag */
1077
1078 15 return update_size(pb, pos);
1079 }
1080
1081 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1082 {
1083 uint8_t *unescaped;
1084 const uint8_t *start, *next, *end = track->vos_data + track->vos_len;
1085 int unescaped_size, seq_found = 0;
1086 int level = 0, interlace = 0;
1087 int packet_seq = track->vc1_info.packet_seq;
1088 int packet_entry = track->vc1_info.packet_entry;
1089 int slices = track->vc1_info.slices;
1090 PutBitContext pbc;
1091
1092 if (track->start_dts == AV_NOPTS_VALUE) {
1093 /* No packets written yet, vc1_info isn't authoritative yet. */
1094 /* Assume inline sequence and entry headers. */
1095 packet_seq = packet_entry = 1;
1096 av_log(NULL, AV_LOG_WARNING,
1097 "moov atom written before any packets, unable to write correct "
1098 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1099 }
1100
1101 unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
1102 if (!unescaped)
1103 return AVERROR(ENOMEM);
1104 start = find_next_marker(track->vos_data, end);
1105 for (next = start; next < end; start = next) {
1106 GetBitContext gb;
1107 int size;
1108 next = find_next_marker(start + 4, end);
1109 size = next - start - 4;
1110 if (size <= 0)
1111 continue;
1112 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1113 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1114 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1115 int profile = get_bits(&gb, 2);
1116 if (profile != PROFILE_ADVANCED) {
1117 av_free(unescaped);
1118 return AVERROR(ENOSYS);
1119 }
1120 seq_found = 1;
1121 level = get_bits(&gb, 3);
1122 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1123 * width, height */
1124 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1125 skip_bits(&gb, 1); /* broadcast */
1126 interlace = get_bits1(&gb);
1127 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1128 }
1129 }
1130 if (!seq_found) {
1131 av_free(unescaped);
1132 return AVERROR(ENOSYS);
1133 }
1134
1135 init_put_bits(&pbc, buf, 7);
1136 /* VC1DecSpecStruc */
1137 put_bits(&pbc, 4, 12); /* profile - advanced */
1138 put_bits(&pbc, 3, level);
1139 put_bits(&pbc, 1, 0); /* reserved */
1140 /* VC1AdvDecSpecStruc */
1141 put_bits(&pbc, 3, level);
1142 put_bits(&pbc, 1, 0); /* cbr */
1143 put_bits(&pbc, 6, 0); /* reserved */
1144 put_bits(&pbc, 1, !interlace); /* no interlace */
1145 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1146 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1147 put_bits(&pbc, 1, !slices); /* no slice code */
1148 put_bits(&pbc, 1, 0); /* no bframe */
1149 put_bits(&pbc, 1, 0); /* reserved */
1150
1151 /* framerate */
1152 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1153 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1154 else
1155 put_bits32(&pbc, 0xffffffff);
1156
1157 flush_put_bits(&pbc);
1158
1159 av_free(unescaped);
1160
1161 return 0;
1162 }
1163
1164 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1165 {
1166 uint8_t buf[7] = { 0 };
1167 int ret;
1168
1169 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1170 return ret;
1171
1172 avio_wb32(pb, track->vos_len + 8 + sizeof(buf));
1173 ffio_wfourcc(pb, "dvc1");
1174 avio_write(pb, buf, sizeof(buf));
1175 avio_write(pb, track->vos_data, track->vos_len);
1176
1177 return 0;
1178 }
1179
1180 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1181 {
1182 4 avio_wb32(pb, track->vos_len + 8);
1183 4 ffio_wfourcc(pb, "glbl");
1184 4 avio_write(pb, track->vos_data, track->vos_len);
1185 4 return 8 + track->vos_len;
1186 }
1187
1188 /**
1189 * Compute flags for 'lpcm' tag.
1190 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1191 */
1192 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1193 {
1194
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) {
1195 case AV_CODEC_ID_PCM_F32BE:
1196 case AV_CODEC_ID_PCM_F64BE:
1197 return 11;
1198 case AV_CODEC_ID_PCM_F32LE:
1199 case AV_CODEC_ID_PCM_F64LE:
1200 return 9;
1201 case AV_CODEC_ID_PCM_U8:
1202 return 10;
1203 case AV_CODEC_ID_PCM_S16BE:
1204 case AV_CODEC_ID_PCM_S24BE:
1205 case AV_CODEC_ID_PCM_S32BE:
1206 return 14;
1207 case AV_CODEC_ID_PCM_S8:
1208 case AV_CODEC_ID_PCM_S16LE:
1209 case AV_CODEC_ID_PCM_S24LE:
1210 case AV_CODEC_ID_PCM_S32LE:
1211 return 12;
1212 8 default:
1213 8 return 0;
1214 }
1215 }
1216
1217 25209 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1218 {
1219 int64_t next_dts;
1220
1221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 if (cluster_idx >= track->entry)
1222 return 0;
1223
1224
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 24566 times.
25209 if (cluster_idx + 1 == track->entry)
1225 643 next_dts = track->track_duration + track->start_dts;
1226 else
1227 24566 next_dts = track->cluster[cluster_idx + 1].dts;
1228
1229 25209 next_dts -= track->cluster[cluster_idx].dts;
1230
1231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts >= 0);
1232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts <= INT_MAX);
1233
1234 25209 return next_dts;
1235 }
1236
1237 4 static int get_samples_per_packet(MOVTrack *track)
1238 {
1239 int i, first_duration;
1240
1241 /* use 1 for raw PCM */
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1243 return 1;
1244
1245 /* check to see if duration is constant for all clusters */
1246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1247 return 0;
1248 4 first_duration = get_cluster_duration(track, 0);
1249
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1250
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1251 4 return 0;
1252 }
1253 return first_duration;
1254 }
1255
1256 131 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1257 {
1258 131 int64_t pos = avio_tell(pb);
1259 131 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1260
3/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
131 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1261
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 !bit_rates.buffer_size)
1262 // no useful data to be written, skip
1263 81 return 0;
1264
1265 50 avio_wb32(pb, 0); /* size */
1266 50 ffio_wfourcc(pb, "btrt");
1267
1268 50 avio_wb32(pb, bit_rates.buffer_size);
1269 50 avio_wb32(pb, bit_rates.max_bit_rate);
1270 50 avio_wb32(pb, bit_rates.avg_bit_rate);
1271
1272 50 return update_size(pb, pos);
1273 }
1274
1275 5 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1276 {
1277 5 int64_t pos = avio_tell(pb);
1278 5 int config = 0;
1279 int ret;
1280 5 uint8_t *speaker_pos = NULL;
1281 5 const AVChannelLayout *layout = &track->par->ch_layout;
1282
1283 5 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1284
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
5 if (ret || !config) {
1285 4 config = 0;
1286 4 speaker_pos = av_malloc(layout->nb_channels);
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1288 return AVERROR(ENOMEM);
1289 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1290 4 speaker_pos, layout->nb_channels);
1291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1292 char buf[128] = {0};
1293
1294 av_freep(&speaker_pos);
1295 av_channel_layout_describe(layout, buf, sizeof(buf));
1296 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1297 return ret;
1298 }
1299 }
1300
1301 5 avio_wb32(pb, 0); /* size */
1302 5 ffio_wfourcc(pb, "chnl");
1303 5 avio_wb32(pb, 0); /* version & flags */
1304
1305 5 avio_w8(pb, 1); /* stream_structure */
1306 5 avio_w8(pb, config);
1307
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (config) {
1308 1 avio_wb64(pb, 0);
1309 } else {
1310 4 avio_write(pb, speaker_pos, layout->nb_channels);
1311 4 av_freep(&speaker_pos);
1312 }
1313
1314 5 return update_size(pb, pos);
1315 }
1316
1317 7 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1318 {
1319 7 int64_t pos = avio_tell(pb);
1320 int format_flags;
1321 int sample_size;
1322
1323 7 avio_wb32(pb, 0); /* size */
1324 7 ffio_wfourcc(pb, "pcmC");
1325 7 avio_wb32(pb, 0); /* version & flags */
1326
1327 /* 0x01: indicates little-endian format */
1328 20 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1329
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1331
2/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1332 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1333 7 avio_w8(pb, format_flags);
1334 7 sample_size = track->par->bits_per_raw_sample;
1335
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (!sample_size)
1336 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 av_assert0(sample_size);
1338 7 avio_w8(pb, sample_size);
1339
1340 7 return update_size(pb, pos);
1341 }
1342
1343 108 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1344 {
1345 108 int64_t pos = avio_tell(pb);
1346 108 int version = 0;
1347 108 uint32_t tag = track->tag;
1348 108 int ret = 0;
1349
1350
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV) {
1351
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
40 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1352
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1353 tag = AV_RL32("lpcm");
1354 4 version = 2;
1355
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
62 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1356 26 mov_pcm_be_gt16(track->par->codec_id) ||
1357
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1358
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1360 12 version = 1;
1361 }
1362 }
1363
1364 108 avio_wb32(pb, 0); /* size */
1365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE) {
1366 ffio_wfourcc(pb, "enca");
1367 } else {
1368 108 avio_wl32(pb, tag); // store it byteswapped
1369 }
1370 108 avio_wb32(pb, 0); /* Reserved */
1371 108 avio_wb16(pb, 0); /* Reserved */
1372 108 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1373
1374 /* SoundDescription */
1375 108 avio_wb16(pb, version); /* Version */
1376 108 avio_wb16(pb, 0); /* Revision level */
1377 108 avio_wb32(pb, 0); /* Reserved */
1378
1379
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 104 times.
108 if (version == 2) {
1380 4 avio_wb16(pb, 3);
1381 4 avio_wb16(pb, 16);
1382 4 avio_wb16(pb, 0xfffe);
1383 4 avio_wb16(pb, 0);
1384 4 avio_wb32(pb, 0x00010000);
1385 4 avio_wb32(pb, 72);
1386 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1387 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1388 4 avio_wb32(pb, 0x7F000000);
1389 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1390 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1391 4 avio_wb32(pb, track->sample_size);
1392 4 avio_wb32(pb, get_samples_per_packet(track));
1393 } else {
1394
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 68 times.
104 if (track->mode == MODE_MOV) {
1395 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1396
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1397
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1398 1 avio_wb16(pb, 8); /* bits per sample */
1399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1400 avio_wb16(pb, track->par->bits_per_coded_sample);
1401 else
1402 35 avio_wb16(pb, 16);
1403
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1404 } else { /* reserved for mp4/3gp */
1405
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
131 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1406 63 0 : track->par->ch_layout.nb_channels);
1407
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
68 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 track->par->codec_id == AV_CODEC_ID_ALAC) {
1409 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1410 } else {
1411 63 avio_wb16(pb, 16);
1412 }
1413 68 avio_wb16(pb, 0);
1414 }
1415
1416 104 avio_wb16(pb, 0); /* packet size (= 0) */
1417
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 99 times.
104 if (track->tag == MKTAG('i','a','m','f'))
1418 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1420 avio_wb16(pb, 48000);
1421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1422 avio_wb32(pb, track->par->sample_rate);
1423 else
1424
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
198 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1425 99 track->par->sample_rate : 0);
1426
1427
1/2
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
104 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1428 104 avio_wb16(pb, 0); /* Reserved */
1429 }
1430
1431
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 96 times.
108 if (version == 1) { /* SoundDescription V1 extended info */
1432
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
24 if (mov_pcm_le_gt16(track->par->codec_id) ||
1433 12 mov_pcm_be_gt16(track->par->codec_id))
1434 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1435 else
1436 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1437 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1438 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1439 12 avio_wb32(pb, 2); /* Bytes per sample */
1440 }
1441
1442
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV &&
1443
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1444
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1445
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1446
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1447
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1448
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1449
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1450
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 ||
1451
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) ||
1452
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1453 15 ret = mov_write_wave_tag(s, pb, track);
1454
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42 times.
93 else if (track->tag == MKTAG('m','p','4','a'))
1455 51 ret = mov_write_esds_tag(pb, track);
1456 #if CONFIG_IAMFENC
1457
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 37 times.
42 else if (track->tag == MKTAG('i','a','m','f'))
1458 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1459 #endif
1460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1461 ret = mov_write_amr_tag(pb, track);
1462
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1463 4 ret = mov_write_ac3_tag(s, pb, track);
1464
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
33 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1465 1 ret = mov_write_eac3_tag(s, pb, track);
1466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1467 ret = mov_write_extradata_tag(pb, track);
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1469 ret = mov_write_wfex_tag(s, pb, track);
1470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1471 ret = mov_write_dfla_tag(pb, track);
1472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1473 ret = mov_write_dops_tag(s, pb, track);
1474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1475 ret = mov_write_dmlp_tag(s, pb, track);
1476
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
32 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1477
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (track->par->ch_layout.nb_channels > 1)
1478 5 ret = mov_write_chnl_tag(s, pb, track);
1479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
1480 return ret;
1481 7 ret = mov_write_pcmc_tag(s, pb, track);
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->vos_len > 0)
1483 ret = mov_write_glbl_tag(pb, track);
1484
1485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (ret < 0)
1486 return ret;
1487
1488
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
108 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1489
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1490 return ret;
1491 }
1492
1493
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
108 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1494
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1495 return ret;
1496 }
1497
1498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE
1499 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1500 return ret;
1501 }
1502
1503
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
173 if (mov->write_btrt &&
1504 65 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1505 return ret;
1506
1507 108 ret = update_size(pb, pos);
1508 108 return ret;
1509 }
1510
1511 static int mov_write_d263_tag(AVIOContext *pb)
1512 {
1513 avio_wb32(pb, 0xf); /* size */
1514 ffio_wfourcc(pb, "d263");
1515 ffio_wfourcc(pb, "FFMP");
1516 avio_w8(pb, 0); /* decoder version */
1517 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1518 avio_w8(pb, 0xa); /* level */
1519 avio_w8(pb, 0); /* profile */
1520 return 0xf;
1521 }
1522
1523 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1524 {
1525 1 int64_t pos = avio_tell(pb);
1526
1527 1 avio_wb32(pb, 0);
1528 1 ffio_wfourcc(pb, "av1C");
1529 1 ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF);
1530 1 return update_size(pb, pos);
1531 }
1532
1533 53 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1534 {
1535 53 int64_t pos = avio_tell(pb);
1536
1537 53 avio_wb32(pb, 0);
1538 53 ffio_wfourcc(pb, "avcC");
1539 53 ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
1540 53 return update_size(pb, pos);
1541 }
1542
1543 /* AVS3 Intelligent Media Coding
1544 * Information Technology - Intelligent Media Coding
1545 * Part 6: Intelligent Media Format
1546 */
1547 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1548 {
1549 if (len < 4)
1550 return AVERROR_INVALIDDATA;
1551
1552 if (data[0] == 1) {
1553 // In Avs3DecoderConfigurationRecord format
1554 avio_write(pb, data, len);
1555 return 0;
1556 }
1557
1558 avio_w8(pb, 1); // version
1559 avio_wb16(pb, len); // sequence_header_length
1560 avio_write(pb, data, len); // sequence_header
1561 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1562
1563 return 0;
1564 }
1565
1566 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1567 {
1568 int64_t pos = avio_tell(pb);
1569 avio_wb32(pb, 0);
1570 ffio_wfourcc(pb, "av3c");
1571 mov_write_av3c(pb, track->vos_data, track->vos_len);
1572 return update_size(pb, pos);
1573 }
1574
1575 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1576 {
1577 int64_t pos = avio_tell(pb);
1578
1579 avio_wb32(pb, 0);
1580 ffio_wfourcc(pb, "vpcC");
1581 ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par);
1582 return update_size(pb, pos);
1583 }
1584
1585 3 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1586 {
1587 3 int64_t pos = avio_tell(pb);
1588
1589 3 avio_wb32(pb, 0);
1590 3 ffio_wfourcc(pb, "hvcC");
1591
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1592 1 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1, s);
1593 else
1594 2 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0, s);
1595 3 return update_size(pb, pos);
1596 }
1597
1598 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1599 {
1600 1 int64_t pos = avio_tell(pb);
1601 int ret;
1602
1603 1 avio_wb32(pb, 0);
1604 1 ffio_wfourcc(pb, "lhvC");
1605
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1606 1 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1, s);
1607 else
1608 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0, s);
1609
1610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1611 avio_seek(pb, pos, SEEK_SET);
1612 return ret;
1613 }
1614
1615 1 return update_size(pb, pos);
1616 }
1617
1618 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1619 {
1620 1 int64_t pos = avio_tell(pb);
1621
1622 1 avio_wb32(pb, 0);
1623 1 ffio_wfourcc(pb, "evcC");
1624
1625
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1626 1 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1);
1627 else
1628 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0);
1629
1630 1 return update_size(pb, pos);
1631 }
1632
1633 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1634 {
1635 1 int64_t pos = avio_tell(pb);
1636
1637 1 avio_wb32(pb, 0);
1638 1 ffio_wfourcc(pb, "vvcC");
1639
1640 1 avio_w8 (pb, 0); /* version */
1641 1 avio_wb24(pb, 0); /* flags */
1642
1643
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1644 1 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
1645 else
1646 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
1647 1 return update_size(pb, pos);
1648 }
1649
1650 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1651 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1652 {
1653 int interlaced;
1654 int cid;
1655 23 int display_width = track->par->width;
1656
1657
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (track->vos_data && track->vos_len > 0x29) {
1658
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) {
1659 /* looks like a DNxHD bit stream */
1660 23 interlaced = (track->vos_data[5] & 2);
1661 23 cid = AV_RB32(track->vos_data + 0x28);
1662 } else {
1663 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1664 return 0;
1665 }
1666 } else {
1667 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1668 return 0;
1669 }
1670
1671 23 avio_wb32(pb, 24); /* size */
1672 23 ffio_wfourcc(pb, "ACLR");
1673 23 ffio_wfourcc(pb, "ACLR");
1674 23 ffio_wfourcc(pb, "0001");
1675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1676 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1677 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1678 } else { /* Full range (0-255) */
1679 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1680 }
1681 23 avio_wb32(pb, 0); /* unknown */
1682
1683
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1684 12 avio_wb32(pb, 32);
1685 12 ffio_wfourcc(pb, "ADHR");
1686 12 ffio_wfourcc(pb, "0001");
1687 12 avio_wb32(pb, cid);
1688 12 avio_wb32(pb, 0); /* unknown */
1689 12 avio_wb32(pb, 1); /* unknown */
1690 12 avio_wb32(pb, 0); /* unknown */
1691 12 avio_wb32(pb, 0); /* unknown */
1692 12 return 0;
1693 }
1694
1695 11 avio_wb32(pb, 24); /* size */
1696 11 ffio_wfourcc(pb, "APRG");
1697 11 ffio_wfourcc(pb, "APRG");
1698 11 ffio_wfourcc(pb, "0001");
1699 11 avio_wb32(pb, 1); /* unknown */
1700 11 avio_wb32(pb, 0); /* unknown */
1701
1702 11 avio_wb32(pb, 120); /* size */
1703 11 ffio_wfourcc(pb, "ARES");
1704 11 ffio_wfourcc(pb, "ARES");
1705 11 ffio_wfourcc(pb, "0001");
1706 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1708 && track->par->sample_aspect_ratio.den > 0)
1709 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1710 11 avio_wb32(pb, display_width);
1711 /* values below are based on samples created with quicktime and avid codecs */
1712
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1713 11 avio_wb32(pb, track->par->height / 2);
1714 11 avio_wb32(pb, 2); /* unknown */
1715 11 avio_wb32(pb, 0); /* unknown */
1716 11 avio_wb32(pb, 4); /* unknown */
1717 } else {
1718 avio_wb32(pb, track->par->height);
1719 avio_wb32(pb, 1); /* unknown */
1720 avio_wb32(pb, 0); /* unknown */
1721 if (track->par->height == 1080)
1722 avio_wb32(pb, 5); /* unknown */
1723 else
1724 avio_wb32(pb, 6); /* unknown */
1725 }
1726 /* padding */
1727 11 ffio_fill(pb, 0, 10 * 8);
1728
1729 11 return 0;
1730 }
1731
1732 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1733 {
1734 avio_wb32(pb, 12);
1735 ffio_wfourcc(pb, "DpxE");
1736 if (track->par->extradata_size >= 12 &&
1737 !memcmp(&track->par->extradata[4], "DpxE", 4)) {
1738 avio_wb32(pb, track->par->extradata[11]);
1739 } else {
1740 avio_wb32(pb, 1);
1741 }
1742 return 0;
1743 }
1744
1745 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1746 {
1747 int tag;
1748
1749
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1750
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1751
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');
1752 1 else tag = MKTAG('d','v','c',' ');
1753 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1754 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1755 else tag = MKTAG('d','v','p','p');
1756 } else if (track->par->height == 720) { /* HD 720 line */
1757 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1758 else tag = MKTAG('d','v','h','p');
1759 } else if (track->par->height == 1080) { /* HD 1080 line */
1760 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1761 else tag = MKTAG('d','v','h','6');
1762 } else {
1763 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1764 return 0;
1765 }
1766
1767 1 return tag;
1768 }
1769
1770 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1771 {
1772 3 AVRational rational_framerate = st->avg_frame_rate;
1773 3 int rate = 0;
1774
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1775 3 rate = av_q2d(rational_framerate);
1776 3 return rate;
1777 }
1778
1779 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1780 {
1781 1 int tag = track->par->codec_tag;
1782 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1783 1 AVStream *st = track->st;
1784 1 int rate = defined_frame_rate(s, st);
1785
1786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1787 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1788
1789
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1790
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) {
1791 if (!interlaced) {
1792 if (rate == 24) tag = MKTAG('x','d','v','4');
1793 else if (rate == 25) tag = MKTAG('x','d','v','5');
1794 else if (rate == 30) tag = MKTAG('x','d','v','1');
1795 else if (rate == 50) tag = MKTAG('x','d','v','a');
1796 else if (rate == 60) tag = MKTAG('x','d','v','9');
1797 }
1798
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) {
1799 if (!interlaced) {
1800 if (rate == 24) tag = MKTAG('x','d','v','6');
1801 else if (rate == 25) tag = MKTAG('x','d','v','7');
1802 else if (rate == 30) tag = MKTAG('x','d','v','8');
1803 } else {
1804 if (rate == 25) tag = MKTAG('x','d','v','3');
1805 else if (rate == 30) tag = MKTAG('x','d','v','2');
1806 }
1807
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) {
1808 if (!interlaced) {
1809 if (rate == 24) tag = MKTAG('x','d','v','d');
1810 else if (rate == 25) tag = MKTAG('x','d','v','e');
1811 else if (rate == 30) tag = MKTAG('x','d','v','f');
1812 } else {
1813 if (rate == 25) tag = MKTAG('x','d','v','c');
1814 else if (rate == 30) tag = MKTAG('x','d','v','b');
1815 }
1816 }
1817 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1818 if (track->par->width == 1280 && track->par->height == 720) {
1819 if (!interlaced) {
1820 if (rate == 24) tag = MKTAG('x','d','5','4');
1821 else if (rate == 25) tag = MKTAG('x','d','5','5');
1822 else if (rate == 30) tag = MKTAG('x','d','5','1');
1823 else if (rate == 50) tag = MKTAG('x','d','5','a');
1824 else if (rate == 60) tag = MKTAG('x','d','5','9');
1825 }
1826 } else if (track->par->width == 1920 && track->par->height == 1080) {
1827 if (!interlaced) {
1828 if (rate == 24) tag = MKTAG('x','d','5','d');
1829 else if (rate == 25) tag = MKTAG('x','d','5','e');
1830 else if (rate == 30) tag = MKTAG('x','d','5','f');
1831 } else {
1832 if (rate == 25) tag = MKTAG('x','d','5','c');
1833 else if (rate == 30) tag = MKTAG('x','d','5','b');
1834 }
1835 }
1836 }
1837
1838 1 return tag;
1839 }
1840
1841 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1842 {
1843 2 int tag = track->par->codec_tag;
1844 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1845 2 AVStream *st = track->st;
1846 2 int rate = defined_frame_rate(s, st);
1847
1848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1849 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1850
1851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1852 if (track->par->width == 960 && track->par->height == 720) {
1853 if (!interlaced) {
1854 if (rate == 24) tag = MKTAG('a','i','5','p');
1855 else if (rate == 25) tag = MKTAG('a','i','5','q');
1856 else if (rate == 30) tag = MKTAG('a','i','5','p');
1857 else if (rate == 50) tag = MKTAG('a','i','5','q');
1858 else if (rate == 60) tag = MKTAG('a','i','5','p');
1859 }
1860 } else if (track->par->width == 1440 && track->par->height == 1080) {
1861 if (!interlaced) {
1862 if (rate == 24) tag = MKTAG('a','i','5','3');
1863 else if (rate == 25) tag = MKTAG('a','i','5','2');
1864 else if (rate == 30) tag = MKTAG('a','i','5','3');
1865 } else {
1866 if (rate == 50) tag = MKTAG('a','i','5','5');
1867 else if (rate == 60) tag = MKTAG('a','i','5','6');
1868 }
1869 }
1870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1871 if (track->par->width == 1280 && track->par->height == 720) {
1872 if (!interlaced) {
1873 if (rate == 24) tag = MKTAG('a','i','1','p');
1874 else if (rate == 25) tag = MKTAG('a','i','1','q');
1875 else if (rate == 30) tag = MKTAG('a','i','1','p');
1876 else if (rate == 50) tag = MKTAG('a','i','1','q');
1877 else if (rate == 60) tag = MKTAG('a','i','1','p');
1878 }
1879 } else if (track->par->width == 1920 && track->par->height == 1080) {
1880 if (!interlaced) {
1881 if (rate == 24) tag = MKTAG('a','i','1','3');
1882 else if (rate == 25) tag = MKTAG('a','i','1','2');
1883 else if (rate == 30) tag = MKTAG('a','i','1','3');
1884 } else {
1885 if (rate == 25) tag = MKTAG('a','i','1','5');
1886 else if (rate == 50) tag = MKTAG('a','i','1','5');
1887 else if (rate == 60) tag = MKTAG('a','i','1','6');
1888 }
1889 } else if ( track->par->width == 4096 && track->par->height == 2160
1890 || track->par->width == 3840 && track->par->height == 2160
1891 || track->par->width == 2048 && track->par->height == 1080) {
1892 tag = MKTAG('a','i','v','x');
1893 }
1894 }
1895
1896 2 return tag;
1897 }
1898
1899 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1900 {
1901 int tag = track->par->codec_tag;
1902
1903 if (!tag)
1904 tag = MKTAG('e', 'v', 'c', '1');
1905
1906 return tag;
1907 }
1908
1909 static const struct {
1910 enum AVPixelFormat pix_fmt;
1911 uint32_t tag;
1912 unsigned bps;
1913 } mov_pix_fmt_tags[] = {
1914 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1915 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1916 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1917 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
1918 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
1919 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
1920 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1921 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1922 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1923 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1924 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1925 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1926 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1927 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1928 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1929 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1930 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1931 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1932 };
1933
1934 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1935 {
1936 23 int tag = MKTAG('A','V','d','n');
1937
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1938
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1939 12 tag = MKTAG('A','V','d','h');
1940 23 return tag;
1941 }
1942
1943 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1944 {
1945 17 int tag = track->par->codec_tag;
1946 int i;
1947 enum AVPixelFormat pix_fmt;
1948
1949
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++) {
1950
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1951 17 tag = mov_pix_fmt_tags[i].tag;
1952 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1953
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
1954 5 break;
1955 }
1956 }
1957
1958 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
1959 17 track->par->bits_per_coded_sample);
1960
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
1961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
1962 track->par->format != AV_PIX_FMT_GRAY8 &&
1963 track->par->format != AV_PIX_FMT_NONE)
1964 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
1965 av_get_pix_fmt_name(track->par->format));
1966 17 return tag;
1967 }
1968
1969 165 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
1970 {
1971 165 unsigned int tag = track->par->codec_tag;
1972
1973 // "rtp " is used to distinguish internally created RTP-hint tracks
1974 // (with rtp_ctx) from other tracks.
1975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
165 if (tag == MKTAG('r','t','p',' '))
1976 tag = 0;
1977
3/4
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
✓ Branch 3 taken 36 times.
165 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
1978
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 1 times.
129 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
1979
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 17 times.
128 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
1980
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 track->par->codec_id == AV_CODEC_ID_H263 ||
1981
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 2 times.
111 track->par->codec_id == AV_CODEC_ID_H264 ||
1982
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 23 times.
109 track->par->codec_id == AV_CODEC_ID_DNXHD ||
1983
4/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 67 times.
171 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
1984 85 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
1985
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
1986 1 tag = mov_get_dv_codec_tag(s, track);
1987
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
1988 17 tag = mov_get_rawvideo_codec_tag(s, track);
1989
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
1990 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
1991
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
1992 2 tag = mov_get_h264_codec_tag(s, track);
1993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
1994 tag = mov_get_evc_codec_tag(s, track);
1995
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
1996 23 tag = mov_get_dnxhd_codec_tag(s, track);
1997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
1998 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
1999 if (!tag) { // if no mac fcc found, try with Microsoft tags
2000 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2001 if (tag)
2002 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2003 "the file may be unplayable!\n");
2004 }
2005
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2006 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2008 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2009 if (ms_tag) {
2010 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2011 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2012 "the file may be unplayable!\n");
2013 }
2014 }
2015 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2016 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2017 }
2018
2019 165 return tag;
2020 }
2021
2022 static const AVCodecTag codec_cover_image_tags[] = {
2023 { AV_CODEC_ID_MJPEG, 0xD },
2024 { AV_CODEC_ID_PNG, 0xE },
2025 { AV_CODEC_ID_BMP, 0x1B },
2026 { AV_CODEC_ID_NONE, 0 },
2027 };
2028
2029 95 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2030 unsigned int tag, int codec_id)
2031 {
2032 int i;
2033
2034 /**
2035 * Check that tag + id is in the table
2036 */
2037
2/4
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
95 for (i = 0; tags && tags[i]; i++) {
2038 95 const AVCodecTag *codec_tags = tags[i];
2039
1/2
✓ Branch 0 taken 1298 times.
✗ Branch 1 not taken.
1298 while (codec_tags->id != AV_CODEC_ID_NONE) {
2040
2/2
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 1191 times.
1298 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2041
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 12 times.
107 codec_tags->id == codec_id)
2042 95 return codec_tags->tag;
2043 1203 codec_tags++;
2044 }
2045 }
2046 return 0;
2047 }
2048
2049 262 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2050 {
2051
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 260 times.
262 if (is_cover_image(track->st))
2052 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2053
2054
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 259 times.
260 if (track->mode == MODE_IPOD)
2055
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") &&
2056
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2057 1 !av_match_ext(s->url, "m4b"))
2058 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2059 "Quicktime/Ipod might not play the file\n");
2060
2061
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 95 times.
260 if (track->mode == MODE_MOV) {
2062 165 return mov_get_codec_tag(s, track);
2063 } else
2064 95 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2065 95 track->par->codec_id);
2066 }
2067
2068 /** Write uuid atom.
2069 * Needed to make file play in iPods running newest firmware
2070 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2071 */
2072 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2073 {
2074 avio_wb32(pb, 28);
2075 ffio_wfourcc(pb, "uuid");
2076 avio_wb32(pb, 0x6b6840f2);
2077 avio_wb32(pb, 0x5f244fc5);
2078 avio_wb32(pb, 0xba39a51b);
2079 avio_wb32(pb, 0xcf0323f3);
2080 avio_wb32(pb, 0x0);
2081 return 28;
2082 }
2083
2084 static const uint16_t fiel_data[] = {
2085 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2086 };
2087
2088 95 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2089 {
2090 95 unsigned mov_field_order = 0;
2091
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2092 95 mov_field_order = fiel_data[field_order];
2093 else
2094 return 0;
2095 95 avio_wb32(pb, 10);
2096 95 ffio_wfourcc(pb, "fiel");
2097 95 avio_wb16(pb, mov_field_order);
2098 95 return 10;
2099 }
2100
2101 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2102 {
2103 4 MOVMuxContext *mov = s->priv_data;
2104 4 int ret = AVERROR_BUG;
2105 4 int64_t pos = avio_tell(pb);
2106 4 avio_wb32(pb, 0); /* size */
2107 4 avio_wl32(pb, track->tag); // store it byteswapped
2108 4 avio_wb32(pb, 0); /* Reserved */
2109 4 avio_wb16(pb, 0); /* Reserved */
2110 4 avio_wb16(pb, 1); /* Data-reference index */
2111
2112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2113 mov_write_esds_tag(pb, track);
2114
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2115
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
2116 1 case MOV_ISMV_TTML_TAG:
2117 // ISMV dfxp requires no extradata.
2118 2 break;
2119 1 case MOV_MP4_TTML_TAG:
2120 // As specified in 14496-30, XMLSubtitleSampleEntry
2121 // Namespace
2122 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2123 // Empty schema_location
2124 1 avio_w8(pb, 0);
2125 // Empty auxiliary_mime_types
2126 1 avio_w8(pb, 0);
2127 1 break;
2128 default:
2129 av_log(NULL, AV_LOG_ERROR,
2130 "Unknown codec tag '%s' utilized for TTML stream with "
2131 "index %d (track id %d)!\n",
2132 av_fourcc2str(track->par->codec_tag), track->st->index,
2133 track->track_id);
2134 return AVERROR(EINVAL);
2135 }
2136
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->par->extradata_size)
2137 2 avio_write(pb, track->par->extradata, track->par->extradata_size);
2138
2139
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
8 if (mov->write_btrt &&
2140 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2141 return ret;
2142
2143 4 return update_size(pb, pos);
2144 }
2145
2146 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2147 {
2148 int8_t stereo_mode;
2149
2150 if (stereo_3d->flags != 0) {
2151 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2152 return 0;
2153 }
2154
2155 switch (stereo_3d->type) {
2156 case AV_STEREO3D_2D:
2157 stereo_mode = 0;
2158 break;
2159 case AV_STEREO3D_TOPBOTTOM:
2160 stereo_mode = 1;
2161 break;
2162 case AV_STEREO3D_SIDEBYSIDE:
2163 stereo_mode = 2;
2164 break;
2165 default:
2166 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2167 return 0;
2168 }
2169 avio_wb32(pb, 13); /* size */
2170 ffio_wfourcc(pb, "st3d");
2171 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2172 avio_w8(pb, stereo_mode);
2173 return 13;
2174 }
2175
2176 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2177 {
2178 int64_t sv3d_pos, svhd_pos, proj_pos;
2179 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2180
2181 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2182 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2183 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2184 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2185 return 0;
2186 }
2187
2188 sv3d_pos = avio_tell(pb);
2189 avio_wb32(pb, 0); /* size */
2190 ffio_wfourcc(pb, "sv3d");
2191
2192 svhd_pos = avio_tell(pb);
2193 avio_wb32(pb, 0); /* size */
2194 ffio_wfourcc(pb, "svhd");
2195 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2196 avio_put_str(pb, metadata_source);
2197 update_size(pb, svhd_pos);
2198
2199 proj_pos = avio_tell(pb);
2200 avio_wb32(pb, 0); /* size */
2201 ffio_wfourcc(pb, "proj");
2202
2203 avio_wb32(pb, 24); /* size */
2204 ffio_wfourcc(pb, "prhd");
2205 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2206 avio_wb32(pb, spherical_mapping->yaw);
2207 avio_wb32(pb, spherical_mapping->pitch);
2208 avio_wb32(pb, spherical_mapping->roll);
2209
2210 switch (spherical_mapping->projection) {
2211 case AV_SPHERICAL_EQUIRECTANGULAR:
2212 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2213 avio_wb32(pb, 28); /* size */
2214 ffio_wfourcc(pb, "equi");
2215 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2216 avio_wb32(pb, spherical_mapping->bound_top);
2217 avio_wb32(pb, spherical_mapping->bound_bottom);
2218 avio_wb32(pb, spherical_mapping->bound_left);
2219 avio_wb32(pb, spherical_mapping->bound_right);
2220 break;
2221 case AV_SPHERICAL_CUBEMAP:
2222 avio_wb32(pb, 20); /* size */
2223 ffio_wfourcc(pb, "cbmp");
2224 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2225 avio_wb32(pb, 0); /* layout */
2226 avio_wb32(pb, spherical_mapping->padding); /* padding */
2227 break;
2228 }
2229 update_size(pb, proj_pos);
2230
2231 return update_size(pb, sv3d_pos);
2232 }
2233
2234 5 static inline int64_t rescale_rational(AVRational q, int b)
2235 {
2236 5 return av_rescale(q.num, b, q.den);
2237 }
2238
2239 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2240 const AVStereo3D *stereo3d)
2241 {
2242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2243 return;
2244
2245 1 avio_wb32(pb, 12); /* size */
2246 1 ffio_wfourcc(pb, "hfov");
2247 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2248 }
2249
2250 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2251 const AVSphericalMapping *spherical_mapping)
2252 {
2253 1 avio_wb32(pb, 24); /* size */
2254 1 ffio_wfourcc(pb, "proj");
2255 1 avio_wb32(pb, 16); /* size */
2256 1 ffio_wfourcc(pb, "prji");
2257 1 avio_wb32(pb, 0); /* version + flags */
2258
2259
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) {
2260 1 case AV_SPHERICAL_RECTILINEAR:
2261 1 ffio_wfourcc(pb, "rect");
2262 1 break;
2263 case AV_SPHERICAL_EQUIRECTANGULAR:
2264 ffio_wfourcc(pb, "equi");
2265 break;
2266 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2267 ffio_wfourcc(pb, "hequ");
2268 break;
2269 case AV_SPHERICAL_FISHEYE:
2270 ffio_wfourcc(pb, "fish");
2271 break;
2272 default:
2273 av_assert0(0);
2274 }
2275 1 }
2276
2277 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2278 const AVStereo3D *stereo3d)
2279 {
2280 1 int64_t pos = avio_tell(pb);
2281 1 int view = 0;
2282
2283 1 avio_wb32(pb, 0); /* size */
2284 1 ffio_wfourcc(pb, "eyes");
2285
2286 // stri is mandatory
2287 1 avio_wb32(pb, 13); /* size */
2288 1 ffio_wfourcc(pb, "stri");
2289 1 avio_wb32(pb, 0); /* version + flags */
2290
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2291 case AV_STEREO3D_VIEW_LEFT:
2292 view |= 1 << 0;
2293 break;
2294 case AV_STEREO3D_VIEW_RIGHT:
2295 view |= 1 << 1;
2296 break;
2297 1 case AV_STEREO3D_VIEW_PACKED:
2298 1 view |= (1 << 0) | (1 << 1);
2299 1 break;
2300 }
2301 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2302 1 avio_w8(pb, view);
2303
2304 // hero is optional
2305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2306 avio_wb32(pb, 13); /* size */
2307 ffio_wfourcc(pb, "hero");
2308 avio_wb32(pb, 0); /* version + flags */
2309 avio_w8(pb, stereo3d->primary_eye);
2310 }
2311
2312 // it's not clear if cams is mandatory or optional
2313
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2314 1 avio_wb32(pb, 24); /* size */
2315 1 ffio_wfourcc(pb, "cams");
2316 1 avio_wb32(pb, 16); /* size */
2317 1 ffio_wfourcc(pb, "blin");
2318 1 avio_wb32(pb, 0); /* version + flags */
2319 1 avio_wb32(pb, stereo3d->baseline);
2320 }
2321
2322 // it's not clear if cmfy is mandatory or optional
2323
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2324 1 avio_wb32(pb, 24); /* size */
2325 1 ffio_wfourcc(pb, "cmfy");
2326 1 avio_wb32(pb, 16); /* size */
2327 1 ffio_wfourcc(pb, "dadj");
2328 1 avio_wb32(pb, 0); /* version + flags */
2329 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2330 }
2331
2332 1 return update_size(pb, pos);
2333 }
2334
2335 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2336 const AVStereo3D *stereo3d,
2337 const AVSphericalMapping *spherical_mapping)
2338 {
2339 int64_t pos;
2340
2341
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2343 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2344 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2345 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2346 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2347 spherical_mapping->projection);
2348 spherical_mapping = NULL;
2349 }
2350
2351
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2352
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2354 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2355 !stereo3d->baseline &&
2356 !stereo3d->horizontal_disparity_adjustment.num))) {
2357 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2358 stereo3d = NULL;
2359 }
2360
2361
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2362 return 0;
2363
2364 1 pos = avio_tell(pb);
2365 1 avio_wb32(pb, 0); /* size */
2366 1 ffio_wfourcc(pb, "vexu");
2367
2368
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2369 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2370
2371
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2372 1 mov_write_eyes_tag(s, pb, stereo3d);
2373
2374 1 return update_size(pb, pos);
2375 }
2376
2377 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2378 {
2379 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2380
2381 avio_wb32(pb, 32); /* size = 8 + 24 */
2382 if (dovi->dv_profile > 10)
2383 ffio_wfourcc(pb, "dvwC");
2384 else if (dovi->dv_profile > 7)
2385 ffio_wfourcc(pb, "dvvC");
2386 else
2387 ffio_wfourcc(pb, "dvcC");
2388
2389 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2390 avio_write(pb, buf, sizeof(buf));
2391
2392 return 32; /* 8 + 24 */
2393 }
2394
2395 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2396 uint32_t top, uint32_t bottom,
2397 uint32_t left, uint32_t right)
2398 {
2399 5 uint32_t cropped_width = track->par->width - left - right;
2400 5 uint32_t cropped_height = track->height - top - bottom;
2401 AVRational horizOff =
2402 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2403 5 (AVRational) { left, 1 });
2404 AVRational vertOff =
2405 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2406 5 (AVRational) { top, 1 });
2407
2408 5 avio_wb32(pb, 40);
2409 5 ffio_wfourcc(pb, "clap");
2410 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2411 5 avio_wb32(pb, 1); /* apertureWidthD */
2412 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2413 5 avio_wb32(pb, 1); /* apertureHeightD */
2414
2415 5 avio_wb32(pb, -horizOff.num);
2416 5 avio_wb32(pb, horizOff.den);
2417 5 avio_wb32(pb, -vertOff.num);
2418 5 avio_wb32(pb, vertOff.den);
2419
2420 5 return 40;
2421 }
2422
2423 6 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2424 {
2425 AVRational sar;
2426 6 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2427 6 track->par->sample_aspect_ratio.den, INT_MAX);
2428
2429 6 avio_wb32(pb, 16);
2430 6 ffio_wfourcc(pb, "pasp");
2431 6 avio_wb32(pb, sar.num);
2432 6 avio_wb32(pb, sar.den);
2433 6 return 16;
2434 }
2435
2436 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2437 {
2438 uint32_t gama = 0;
2439 if (gamma <= 0.0)
2440 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2441 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2442
2443 if (gamma > 1e-6) {
2444 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2445 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2446
2447 av_assert0(track->mode == MODE_MOV);
2448 avio_wb32(pb, 12);
2449 ffio_wfourcc(pb, "gama");
2450 avio_wb32(pb, gama);
2451 return 12;
2452 } else {
2453 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2454 }
2455 return 0;
2456 }
2457
2458 9 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2459 {
2460 9 int64_t pos = avio_tell(pb);
2461
2462 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2463 // Ref (MP4): ISO/IEC 14496-12:2012
2464
2465
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (prefer_icc) {
2466 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2467 4 track->st->codecpar->nb_coded_side_data,
2468 AV_PKT_DATA_ICC_PROFILE);
2469
2470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2471 avio_wb32(pb, 12 + sd->size);
2472 ffio_wfourcc(pb, "colr");
2473 ffio_wfourcc(pb, "prof");
2474 avio_write(pb, sd->data, sd->size);
2475 return 12 + sd->size;
2476 }
2477 else {
2478 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2479 }
2480 }
2481
2482 /* We should only ever be called for MOV, MP4 and AVIF. */
2483
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2484 track->mode == MODE_AVIF);
2485
2486 9 avio_wb32(pb, 0); /* size */
2487 9 ffio_wfourcc(pb, "colr");
2488
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2489 1 ffio_wfourcc(pb, "nclx");
2490 else
2491 8 ffio_wfourcc(pb, "nclc");
2492 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2493 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2494 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2495 9 avio_wb16(pb, track->par->color_primaries);
2496 9 avio_wb16(pb, track->par->color_trc);
2497 9 avio_wb16(pb, track->par->color_space);
2498
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2499 1 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2500 1 avio_w8(pb, full_range << 7);
2501 }
2502
2503 9 return update_size(pb, pos);
2504 }
2505
2506 200 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2507 {
2508 const AVPacketSideData *side_data;
2509 const AVContentLightMetadata *content_light_metadata;
2510
2511 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2512 200 track->st->codecpar->nb_coded_side_data,
2513 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2514
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (!side_data) {
2515 200 return 0;
2516 }
2517 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2518
2519 avio_wb32(pb, 12); // size
2520 ffio_wfourcc(pb, "clli");
2521 avio_wb16(pb, content_light_metadata->MaxCLL);
2522 avio_wb16(pb, content_light_metadata->MaxFALL);
2523 return 12;
2524 }
2525
2526 200 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2527 {
2528 200 const int chroma_den = 50000;
2529 200 const int luma_den = 10000;
2530 const AVPacketSideData *side_data;
2531 200 const AVMasteringDisplayMetadata *metadata = NULL;
2532
2533 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2534 200 track->st->codecpar->nb_coded_side_data,
2535 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (side_data)
2537 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2538
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
200 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2539 200 return 0;
2540 }
2541
2542 avio_wb32(pb, 32); // size
2543 ffio_wfourcc(pb, "mdcv");
2544 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2545 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2546 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2547 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2548 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2549 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2550 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2551 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2552 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2553 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2554 return 32;
2555 }
2556
2557 200 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2558 {
2559 200 const int illuminance_den = 10000;
2560 200 const int ambient_den = 50000;
2561 const AVPacketSideData *side_data;
2562 const AVAmbientViewingEnvironment *ambient;
2563
2564
2565 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2566 200 track->st->codecpar->nb_coded_side_data,
2567 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2568
2569
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 1 times.
200 if (!side_data)
2570 199 return 0;
2571
2572 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2573
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)
2574 return 0;
2575
2576 1 avio_wb32(pb, 16); // size
2577 1 ffio_wfourcc(pb, "amve");
2578 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2579 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2580 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2581 1 return 16;
2582 }
2583
2584 205 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2585 {
2586 AVDictionaryEntry *encoder;
2587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2588
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
204 || (track->par->width == 1440 && track->par->height == 1080)
2589
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 191 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
410 || (track->par->width == 1920 && track->par->height == 1080);
2590
2591
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 if ((track->mode == MODE_AVIF ||
2592
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
205 track->mode == MODE_MOV ||
2593
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 145 times.
✓ Branch 3 taken 55 times.
267 track->mode == MODE_MP4) &&
2594 200 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2595 145 av_strlcpy(compressor_name, encoder->value, 32);
2596
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2597 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2598 AVStream *st = track->st;
2599 int rate = defined_frame_rate(NULL, st);
2600 av_strlcatf(compressor_name, len, "XDCAM");
2601 if (track->par->format == AV_PIX_FMT_YUV422P) {
2602 av_strlcatf(compressor_name, len, " HD422");
2603 } else if(track->par->width == 1440) {
2604 av_strlcatf(compressor_name, len, " HD");
2605 } else
2606 av_strlcatf(compressor_name, len, " EX");
2607
2608 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2609
2610 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2611 }
2612 205 }
2613
2614 static int mov_write_ccst_tag(AVIOContext *pb)
2615 {
2616 int64_t pos = avio_tell(pb);
2617 // Write sane defaults:
2618 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2619 // intra_pred_used = 1 : intra prediction may or may not be used.
2620 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2621 // reference images can be used.
2622 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2623 (1 << 6) | /* intra_pred_used */
2624 (15 << 2); /* max_ref_per_pic */
2625 avio_wb32(pb, 0); /* size */
2626 ffio_wfourcc(pb, "ccst");
2627 avio_wb32(pb, 0); /* Version & flags */
2628 avio_w8(pb, ccstValue);
2629 avio_wb24(pb, 0); /* reserved */
2630 return update_size(pb, pos);
2631 }
2632
2633 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2634 {
2635 int64_t pos = avio_tell(pb);
2636 avio_wb32(pb, 0); /* size */
2637 ffio_wfourcc(pb, aux_type);
2638 avio_wb32(pb, 0); /* Version & flags */
2639 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2640 return update_size(pb, pos);
2641 }
2642
2643 205 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2644 {
2645 205 int ret = AVERROR_BUG;
2646 205 int64_t pos = avio_tell(pb);
2647 const AVPacketSideData *sd;
2648 205 char compressor_name[32] = { 0 };
2649 205 int avid = 0;
2650
2651
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)
2652
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2653
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2654
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2655
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2656 #if FF_API_V408_CODECID
2657
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V308
2658
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V408
2659
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V410
2660 #endif
2661
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 201 times.
410 || track->par->codec_id == AV_CODEC_ID_V210);
2662
2663 205 avio_wb32(pb, 0); /* size */
2664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2665 ffio_wfourcc(pb, "encv");
2666 } else {
2667 205 avio_wl32(pb, track->tag); // store it byteswapped
2668 }
2669 205 avio_wb32(pb, 0); /* Reserved */
2670 205 avio_wb16(pb, 0); /* Reserved */
2671 205 avio_wb16(pb, 1); /* Data-reference index */
2672
2673
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 201 times.
205 if (uncompressed_ycbcr) {
2674 4 avio_wb16(pb, 2); /* Codec stream version */
2675 } else {
2676 201 avio_wb16(pb, 0); /* Codec stream version */
2677 }
2678 205 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2679
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV) {
2680 138 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2681
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
138 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2682 17 avio_wb32(pb, 0); /* Temporal Quality */
2683 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2684 } else {
2685 121 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2686 121 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2687 }
2688 } else {
2689 67 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2690 }
2691 205 avio_wb16(pb, track->par->width); /* Video width */
2692 205 avio_wb16(pb, track->height); /* Video height */
2693 205 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2694 205 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2695 205 avio_wb32(pb, 0); /* Data size (= 0) */
2696 205 avio_wb16(pb, 1); /* Frame count (= 1) */
2697
2698 205 find_compressor(compressor_name, 32, track);
2699 205 avio_w8(pb, strlen(compressor_name));
2700 205 avio_write(pb, compressor_name, 31);
2701
2702
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV &&
2703
2/4
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 138 times.
138 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2704 avio_wb16(pb, 0x18);
2705
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 107 times.
205 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2706 31 avio_wb16(pb, track->par->bits_per_coded_sample |
2707
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2708 else
2709 174 avio_wb16(pb, 0x18); /* Reserved */
2710
2711
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 133 times.
210 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2712 int pal_size, i;
2713 5 avio_wb16(pb, 0); /* Color table ID */
2714 5 avio_wb32(pb, 0); /* Color table seed */
2715 5 avio_wb16(pb, 0x8000); /* Color table flags */
2716
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)
2717 return AVERROR(EINVAL);
2718 5 pal_size = 1 << track->par->bits_per_coded_sample;
2719 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2720
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2721 1040 uint32_t rgb = track->palette[i];
2722 1040 uint16_t r = (rgb >> 16) & 0xff;
2723 1040 uint16_t g = (rgb >> 8) & 0xff;
2724 1040 uint16_t b = rgb & 0xff;
2725 1040 avio_wb16(pb, 0);
2726 1040 avio_wb16(pb, (r << 8) | r);
2727 1040 avio_wb16(pb, (g << 8) | g);
2728 1040 avio_wb16(pb, (b << 8) | b);
2729 }
2730 } else
2731 200 avio_wb16(pb, 0xffff); /* Reserved */
2732
2733
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 180 times.
205 if (track->tag == MKTAG('m','p','4','v'))
2734 25 mov_write_esds_tag(pb, track);
2735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 else if (track->par->codec_id == AV_CODEC_ID_H263)
2736 mov_write_d263_tag(pb);
2737
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 3 times.
180 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
177 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2739 3 mov_write_extradata_tag(pb, track);
2740 3 avio_wb32(pb, 0);
2741
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 154 times.
177 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2742 23 mov_write_avid_tag(pb, track);
2743 23 avid = 1;
2744
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 151 times.
154 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2745 3 mov_write_hvcc_tag(mov->fc, pb, track);
2746
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2747 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2749 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2750 }
2751
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 150 times.
151 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2752 1 mov_write_vvcc_tag(pb, track);
2753
16/30
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 53 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 53 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 53 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 53 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 53 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 53 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 53 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 53 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 53 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 53 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 53 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 53 times.
✗ Branch 29 not taken.
150 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2754 53 mov_write_avcc_tag(pb, track);
2755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (track->mode == MODE_IPOD)
2756 mov_write_uuid_tag_ipod(pb);
2757 }
2758
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2759 1 mov_write_evcc_tag(pb, track);
2760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2761 mov_write_vpcc_tag(mov->fc, pb, track);
2762
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2763 1 mov_write_av1c_tag(pb, track);
2764
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
95 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
2765 mov_write_dvc1_tag(pb, track);
2766
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2767
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 track->par->codec_id == AV_CODEC_ID_VP6A) {
2768 /* Don't write any potential extradata here - the cropping
2769 * is signalled via the normal width/height fields. */
2770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2771 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2772 mov_write_dpxe_tag(pb, track);
2773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2774 mov_write_av3c_tag(pb, track);
2775
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 91 times.
95 } else if (track->vos_len > 0)
2776 4 mov_write_glbl_tag(pb, track);
2777
2778
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 53 times.
205 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2779
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 25 times.
152 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2780
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 23 times.
127 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2781 104 int field_order = track->par->field_order;
2782
2783
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 9 times.
104 if (field_order != AV_FIELD_UNKNOWN)
2784 95 mov_write_fiel_tag(pb, track, field_order);
2785 }
2786
2787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2788 if (track->mode == MODE_MOV)
2789 mov_write_gama_tag(s, pb, track, mov->gamma);
2790 else
2791 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2792 }
2793
5/6
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
405 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2794 405 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2795
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
205 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2796
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2797
5/6
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 191 times.
391 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2798 191 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2799 AV_PKT_DATA_ICC_PROFILE)) {
2800
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
9 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2801 9 mov_write_colr_tag(pb, track, prefer_icc);
2802 }
2803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2804 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2805 }
2806
2807
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 5 times.
205 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2808 200 mov_write_clli_tag(pb, track);
2809 200 mov_write_mdcv_tag(pb, track);
2810 200 mov_write_amve_tag(pb, track);
2811 }
2812
2813
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
205 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2814 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2815 track->st->codecpar->nb_coded_side_data,
2816 AV_PKT_DATA_STEREO3D);
2817 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2818 track->st->codecpar->nb_coded_side_data,
2819 AV_PKT_DATA_SPHERICAL);
2820 if (stereo_3d)
2821 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2822 if (spherical_mapping)
2823 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2824 }
2825
2826
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 5 times.
205 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2828 138 const AVStereo3D *stereo3d = NULL;
2829 138 const AVSphericalMapping *spherical_mapping = NULL;
2830
2831 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2832 138 track->st->codecpar->nb_coded_side_data,
2833 AV_PKT_DATA_STEREO3D);
2834
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2835 1 stereo3d = (AVStereo3D *)sd->data;
2836
2837 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2838 138 track->st->codecpar->nb_coded_side_data,
2839 AV_PKT_DATA_SPHERICAL);
2840
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2841 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2842
2843
3/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 137 times.
138 if (stereo3d || spherical_mapping)
2844 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2845
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (stereo3d)
2846 1 mov_write_hfov_tag(s, pb, stereo3d);
2847 }
2848
2849
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
205 if (track->mode == MODE_MP4) {
2850 62 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2851 62 track->st->codecpar->nb_coded_side_data,
2852 AV_PKT_DATA_DOVI_CONF);
2853
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
62 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2854 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 } else if (dovi) {
2856 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2857 }
2858 }
2859
2860
3/4
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 199 times.
205 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2861 6 mov_write_pasp_tag(pb, track);
2862 }
2863
2864 205 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2865 205 track->st->codecpar->nb_coded_side_data,
2866 AV_PKT_DATA_FRAME_CROPPING);
2867
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
206 if (sd && sd->size >= sizeof(uint32_t) * 4) {
2868 1 uint64_t top = AV_RL32(sd->data + 0);
2869 1 uint64_t bottom = AV_RL32(sd->data + 4);
2870 1 uint64_t left = AV_RL32(sd->data + 8);
2871 1 uint64_t right = AV_RL32(sd->data + 12);
2872
2873
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2875 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2876 return AVERROR(EINVAL);
2877 }
2878
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)
2879 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2880
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 200 times.
204 } else if (uncompressed_ycbcr)
2881 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2882
2883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2884 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2885 }
2886
2887
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
267 if (mov->write_btrt &&
2888 62 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2889 return ret;
2890
2891 /* extra padding for avid stsd */
2892 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2893
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 182 times.
205 if (avid)
2894 23 avio_wb32(pb, 0);
2895
2896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
2897 mov_write_ccst_tag(pb);
2898 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2899 mov_write_aux_tag(pb, "auxi");
2900 }
2901
2902 205 return update_size(pb, pos);
2903 }
2904
2905 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2906 {
2907 2 int64_t pos = avio_tell(pb);
2908 2 avio_wb32(pb, 0); /* size */
2909 2 ffio_wfourcc(pb, "rtp ");
2910 2 avio_wb32(pb, 0); /* Reserved */
2911 2 avio_wb16(pb, 0); /* Reserved */
2912 2 avio_wb16(pb, 1); /* Data-reference index */
2913
2914 2 avio_wb16(pb, 1); /* Hint track version */
2915 2 avio_wb16(pb, 1); /* Highest compatible version */
2916 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2917
2918 2 avio_wb32(pb, 12); /* size */
2919 2 ffio_wfourcc(pb, "tims");
2920 2 avio_wb32(pb, track->timescale);
2921
2922 2 return update_size(pb, pos);
2923 }
2924
2925 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2926 {
2927 2 uint64_t str_size =strlen(reel_name);
2928 2 int64_t pos = avio_tell(pb);
2929
2930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2931 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2932 avio_wb16(pb, 0);
2933 return AVERROR(EINVAL);
2934 }
2935
2936 2 avio_wb32(pb, 0); /* size */
2937 2 ffio_wfourcc(pb, "name"); /* Data format */
2938 2 avio_wb16(pb, str_size); /* string size */
2939 2 avio_wb16(pb, track->language); /* langcode */
2940 2 avio_write(pb, reel_name, str_size); /* reel name */
2941 2 return update_size(pb,pos);
2942 }
2943
2944 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2945 {
2946 13 int64_t pos = avio_tell(pb);
2947 #if 1
2948 int frame_duration;
2949 int nb_frames;
2950 13 AVDictionaryEntry *t = NULL;
2951
2952
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) {
2953 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
2954 return AVERROR(EINVAL);
2955 } else {
2956 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
2957
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);
2958 }
2959
2960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
2961 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
2962 return AVERROR(EINVAL);
2963 }
2964
2965 13 avio_wb32(pb, 0); /* size */
2966 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
2967 13 avio_wb32(pb, 0); /* Reserved */
2968 13 avio_wb32(pb, 1); /* Data reference index */
2969 13 avio_wb32(pb, 0); /* Flags */
2970 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
2971 13 avio_wb32(pb, track->timescale); /* Timescale */
2972 13 avio_wb32(pb, frame_duration); /* Frame duration */
2973 13 avio_w8(pb, nb_frames); /* Number of frames */
2974 13 avio_w8(pb, 0); /* Reserved */
2975
2976 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
2977
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)
2978 2 mov_write_source_reference_tag(pb, track, t->value);
2979 else
2980 11 avio_wb16(pb, 0); /* zero size */
2981 #else
2982
2983 avio_wb32(pb, 0); /* size */
2984 ffio_wfourcc(pb, "tmcd"); /* Data format */
2985 avio_wb32(pb, 0); /* Reserved */
2986 avio_wb32(pb, 1); /* Data reference index */
2987 if (track->par->extradata_size)
2988 avio_write(pb, track->par->extradata, track->par->extradata_size);
2989 #endif
2990 13 return update_size(pb, pos);
2991 }
2992
2993 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
2994 {
2995 1 int64_t pos = avio_tell(pb);
2996 1 avio_wb32(pb, 0); /* size */
2997 1 ffio_wfourcc(pb, "gpmd");
2998 1 avio_wb32(pb, 0); /* Reserved */
2999 1 avio_wb16(pb, 0); /* Reserved */
3000 1 avio_wb16(pb, 1); /* Data-reference index */
3001 1 avio_wb32(pb, 0); /* Reserved */
3002 1 return update_size(pb, pos);
3003 }
3004
3005 333 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3006 {
3007 333 int64_t pos = avio_tell(pb);
3008 333 int ret = 0;
3009 333 avio_wb32(pb, 0); /* size */
3010 333 ffio_wfourcc(pb, "stsd");
3011 333 avio_wb32(pb, 0); /* version & flags */
3012 333 avio_wb32(pb, 1); /* entry count */
3013
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3014 205 ret = mov_write_video_tag(s, pb, mov, track);
3015
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3016 108 ret = mov_write_audio_tag(s, pb, mov, track);
3017
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3018 4 ret = mov_write_subtitle_tag(s, pb, track);
3019
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3020 2 ret = mov_write_rtp_tag(pb, track);
3021
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3022 13 ret = mov_write_tmcd_tag(pb, track);
3023
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3024 1 ret = mov_write_gpmd_tag(pb, track);
3025
3026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
3027 return ret;
3028
3029 333 return update_size(pb, pos);
3030 }
3031
3032 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3033 {
3034 9 MOVMuxContext *mov = s->priv_data;
3035 MOVCtts *ctts_entries;
3036 9 uint32_t entries = 0;
3037 uint32_t atom_size;
3038 int i;
3039
3040 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3042 return AVERROR(ENOMEM);
3043 9 ctts_entries[0].count = 1;
3044 9 ctts_entries[0].offset = track->cluster[0].cts;
3045
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3046
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3047 130 ctts_entries[entries].count++; /* compress */
3048 } else {
3049 421 entries++;
3050 421 ctts_entries[entries].offset = track->cluster[i].cts;
3051 421 ctts_entries[entries].count = 1;
3052 }
3053 }
3054 9 entries++; /* last one */
3055 9 atom_size = 16 + (entries * 8);
3056 9 avio_wb32(pb, atom_size); /* size */
3057 9 ffio_wfourcc(pb, "ctts");
3058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3059 avio_w8(pb, 1); /* version */
3060 else
3061 9 avio_w8(pb, 0); /* version */
3062 9 avio_wb24(pb, 0); /* flags */
3063 9 avio_wb32(pb, entries); /* entry count */
3064
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3065 430 avio_wb32(pb, ctts_entries[i].count);
3066 430 avio_wb32(pb, ctts_entries[i].offset);
3067 }
3068 9 av_free(ctts_entries);
3069 9 return atom_size;
3070 }
3071
3072 /* Time to sample atom */
3073 333 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3074 {
3075 333 MOVStts *stts_entries = NULL;
3076 333 uint32_t entries = -1;
3077 uint32_t atom_size;
3078 int i;
3079
3080
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 75 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3081 33 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!stts_entries)
3083 return AVERROR(ENOMEM);
3084 33 stts_entries[0].count = track->sample_count;
3085 33 stts_entries[0].duration = 1;
3086 33 entries = 1;
3087 } else {
3088
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 90 times.
300 if (track->entry) {
3089 210 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (!stts_entries)
3091 return AVERROR(ENOMEM);
3092 }
3093
2/2
✓ Branch 0 taken 12206 times.
✓ Branch 1 taken 300 times.
12506 for (i = 0; i < track->entry; i++) {
3094 12206 int duration = get_cluster_duration(track, i);
3095
4/4
✓ Branch 0 taken 11996 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 11593 times.
✓ Branch 3 taken 403 times.
12206 if (i && duration == stts_entries[entries].duration) {
3096 11593 stts_entries[entries].count++; /* compress */
3097 } else {
3098 613 entries++;
3099 613 stts_entries[entries].duration = duration;
3100 613 stts_entries[entries].count = 1;
3101 }
3102 }
3103 300 entries++; /* last one */
3104 }
3105 333 atom_size = 16 + (entries * 8);
3106 333 avio_wb32(pb, atom_size); /* size */
3107 333 ffio_wfourcc(pb, "stts");
3108 333 avio_wb32(pb, 0); /* version & flags */
3109 333 avio_wb32(pb, entries); /* entry count */
3110
2/2
✓ Branch 0 taken 646 times.
✓ Branch 1 taken 333 times.
979 for (i = 0; i < entries; i++) {
3111 646 avio_wb32(pb, stts_entries[i].count);
3112 646 avio_wb32(pb, stts_entries[i].duration);
3113 }
3114 333 av_free(stts_entries);
3115 333 return atom_size;
3116 }
3117
3118 333 static int mov_write_dref_tag(AVIOContext *pb)
3119 {
3120 333 avio_wb32(pb, 28); /* size */
3121 333 ffio_wfourcc(pb, "dref");
3122 333 avio_wb32(pb, 0); /* version & flags */
3123 333 avio_wb32(pb, 1); /* entry count */
3124
3125 333 avio_wb32(pb, 0xc); /* size */
3126 //FIXME add the alis and rsrc atom
3127 333 ffio_wfourcc(pb, "url ");
3128 333 avio_wb32(pb, 1); /* version & flags */
3129
3130 333 return 28;
3131 }
3132
3133 53 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3134 {
3135 struct sgpd_entry {
3136 int count;
3137 int16_t roll_distance;
3138 int group_description_index;
3139 };
3140
3141 53 struct sgpd_entry *sgpd_entries = NULL;
3142 53 int entries = -1;
3143 53 int group = 0;
3144 int i, j;
3145
3146 53 const int OPUS_SEEK_PREROLL_MS = 80;
3147 53 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3148 53 (AVRational){1, 1000},
3149 53 (AVRational){1, 48000});
3150
3151
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 12 times.
53 if (!track->entry)
3152 41 return 0;
3153
3154 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3156 return AVERROR(ENOMEM);
3157
3158
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 av_assert0(track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC);
3159
3160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3161 for (i = 0; i < track->entry; i++) {
3162 int roll_samples_remaining = roll_samples;
3163 int distance = 0;
3164 for (j = i - 1; j >= 0; j--) {
3165 roll_samples_remaining -= get_cluster_duration(track, j);
3166 distance++;
3167 if (roll_samples_remaining <= 0)
3168 break;
3169 }
3170 /* We don't have enough preceeding samples to compute a valid
3171 roll_distance here, so this sample can't be independently
3172 decoded. */
3173 if (roll_samples_remaining > 0)
3174 distance = 0;
3175 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3176 if (distance > 32)
3177 return AVERROR_INVALIDDATA;
3178 if (i && distance == sgpd_entries[entries].roll_distance) {
3179 sgpd_entries[entries].count++;
3180 } else {
3181 entries++;
3182 sgpd_entries[entries].count = 1;
3183 sgpd_entries[entries].roll_distance = distance;
3184 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3185 }
3186 }
3187 } else {
3188 12 entries++;
3189 12 sgpd_entries[entries].count = track->sample_count;
3190 12 sgpd_entries[entries].roll_distance = 1;
3191 12 sgpd_entries[entries].group_description_index = ++group;
3192 }
3193 12 entries++;
3194
3195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3196 av_free(sgpd_entries);
3197 return 0;
3198 }
3199
3200 /* Write sgpd tag */
3201 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3202 12 ffio_wfourcc(pb, "sgpd");
3203 12 avio_wb32(pb, 1 << 24); /* fullbox */
3204 12 ffio_wfourcc(pb, "roll");
3205 12 avio_wb32(pb, 2); /* default_length */
3206 12 avio_wb32(pb, group); /* entry_count */
3207
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3208
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3209 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3210 }
3211 }
3212
3213 /* Write sbgp tag */
3214 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3215 12 ffio_wfourcc(pb, "sbgp");
3216 12 avio_wb32(pb, 0); /* fullbox */
3217 12 ffio_wfourcc(pb, "roll");
3218 12 avio_wb32(pb, entries); /* entry_count */
3219
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3220 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3221 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3222 }
3223
3224 12 av_free(sgpd_entries);
3225 12 return 0;
3226 }
3227
3228 333 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3229 {
3230 333 int64_t pos = avio_tell(pb);
3231 333 int ret = 0;
3232
3233 333 avio_wb32(pb, 0); /* size */
3234 333 ffio_wfourcc(pb, "stbl");
3235
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3236 return ret;
3237 333 mov_write_stts_tag(pb, track);
3238
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 205 times.
333 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3239
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3240
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3241
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
128 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3242
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
128 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3243
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 100 times.
207 track->has_keyframes && track->has_keyframes < track->entry)
3244 58 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3245
4/4
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 202 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable)
3246 3 mov_write_sdtp_tag(pb, track);
3247
3/4
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 187 times.
333 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3248 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3249
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3250
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 22 times.
205 track->flags & MOV_TRACK_CTTS && track->entry) {
3251
3252
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3253 return ret;
3254 }
3255 333 mov_write_stsc_tag(pb, track);
3256 333 mov_write_stsz_tag(pb, track);
3257 333 mov_write_stco_tag(pb, track);
3258
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
333 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3259 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3260 }
3261
3/4
✓ Branch 0 taken 333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 280 times.
333 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3262 53 mov_preroll_write_stbl_atoms(pb, track);
3263 }
3264 333 return update_size(pb, pos);
3265 }
3266
3267 333 static int mov_write_dinf_tag(AVIOContext *pb)
3268 {
3269 333 int64_t pos = avio_tell(pb);
3270 333 avio_wb32(pb, 0); /* size */
3271 333 ffio_wfourcc(pb, "dinf");
3272 333 mov_write_dref_tag(pb);
3273 333 return update_size(pb, pos);
3274 }
3275
3276 6 static int mov_write_nmhd_tag(AVIOContext *pb)
3277 {
3278 6 avio_wb32(pb, 12);
3279 6 ffio_wfourcc(pb, "nmhd");
3280 6 avio_wb32(pb, 0);
3281 6 return 12;
3282 }
3283
3284 1 static int mov_write_sthd_tag(AVIOContext *pb)
3285 {
3286 1 avio_wb32(pb, 12);
3287 1 ffio_wfourcc(pb, "sthd");
3288 1 avio_wb32(pb, 0);
3289 1 return 12;
3290 }
3291
3292 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3293 {
3294 9 int64_t pos = avio_tell(pb);
3295 9 const char *font = "Lucida Grande";
3296 9 avio_wb32(pb, 0); /* size */
3297 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3298 9 avio_wb32(pb, 0); /* version & flags */
3299 9 avio_wb16(pb, 0); /* text font */
3300 9 avio_wb16(pb, 0); /* text face */
3301 9 avio_wb16(pb, 12); /* text size */
3302 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3303 9 avio_wb16(pb, 0x0000); /* text color (red) */
3304 9 avio_wb16(pb, 0x0000); /* text color (green) */
3305 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3306 9 avio_wb16(pb, 0xffff); /* background color (red) */
3307 9 avio_wb16(pb, 0xffff); /* background color (green) */
3308 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3309 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3310 9 avio_write(pb, font, strlen(font)); /* font name */
3311 9 return update_size(pb, pos);
3312 }
3313
3314 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3315 {
3316 11 int64_t pos = avio_tell(pb);
3317 11 avio_wb32(pb, 0); /* size */
3318 11 ffio_wfourcc(pb, "gmhd");
3319 11 avio_wb32(pb, 0x18); /* gmin size */
3320 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3321 11 avio_wb32(pb, 0); /* version & flags */
3322 11 avio_wb16(pb, 0x40); /* graphics mode = */
3323 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3324 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3325 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3326 11 avio_wb16(pb, 0); /* balance */
3327 11 avio_wb16(pb, 0); /* reserved */
3328
3329 /*
3330 * This special text atom is required for
3331 * Apple Quicktime chapters. The contents
3332 * don't appear to be documented, so the
3333 * bytes are copied verbatim.
3334 */
3335
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3336 11 avio_wb32(pb, 0x2C); /* size */
3337 11 ffio_wfourcc(pb, "text");
3338 11 avio_wb16(pb, 0x01);
3339 11 avio_wb32(pb, 0x00);
3340 11 avio_wb32(pb, 0x00);
3341 11 avio_wb32(pb, 0x00);
3342 11 avio_wb32(pb, 0x01);
3343 11 avio_wb32(pb, 0x00);
3344 11 avio_wb32(pb, 0x00);
3345 11 avio_wb32(pb, 0x00);
3346 11 avio_wb32(pb, 0x00004000);
3347 11 avio_wb16(pb, 0x0000);
3348 }
3349
3350
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3351 9 int64_t tmcd_pos = avio_tell(pb);
3352 9 avio_wb32(pb, 0); /* size */
3353 9 ffio_wfourcc(pb, "tmcd");
3354 9 mov_write_tcmi_tag(pb, track);
3355 9 update_size(pb, tmcd_pos);
3356
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3357 1 int64_t gpmd_pos = avio_tell(pb);
3358 1 avio_wb32(pb, 0); /* size */
3359 1 ffio_wfourcc(pb, "gpmd");
3360 1 avio_wb32(pb, 0); /* version */
3361 1 update_size(pb, gpmd_pos);
3362 }
3363 11 return update_size(pb, pos);
3364 }
3365
3366 108 static int mov_write_smhd_tag(AVIOContext *pb)
3367 {
3368 108 avio_wb32(pb, 16); /* size */
3369 108 ffio_wfourcc(pb, "smhd");
3370 108 avio_wb32(pb, 0); /* version & flags */
3371 108 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3372 108 avio_wb16(pb, 0); /* reserved */
3373 108 return 16;
3374 }
3375
3376 205 static int mov_write_vmhd_tag(AVIOContext *pb)
3377 {
3378 205 avio_wb32(pb, 0x14); /* size (always 0x14) */
3379 205 ffio_wfourcc(pb, "vmhd");
3380 205 avio_wb32(pb, 0x01); /* version & flags */
3381 205 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3382 205 return 0x14;
3383 }
3384
3385 218 static int is_clcp_track(MOVTrack *track)
3386 {
3387
1/2
✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
436 return track->tag == MKTAG('c','7','0','8') ||
3388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 track->tag == MKTAG('c','6','0','8');
3389 }
3390
3391 520 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3392 {
3393 520 MOVMuxContext *mov = s->priv_data;
3394 520 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3395 520 int64_t pos = avio_tell(pb);
3396 size_t descr_len;
3397
3398 520 hdlr = "dhlr";
3399 520 hdlr_type = "url ";
3400 520 descr = "DataHandler";
3401
3402
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
520 if (track) {
3403
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3404
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
3406 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3407 descr = "PictureHandler";
3408 } else {
3409 205 hdlr_type = "vide";
3410 205 descr = "VideoHandler";
3411 }
3412
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3413 108 hdlr_type = "soun";
3414 108 descr = "SoundHandler";
3415
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3416
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3417 hdlr_type = "clcp";
3418 descr = "ClosedCaptionHandler";
3419 } else {
3420
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3421 1 hdlr_type = "sbtl";
3422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3423 hdlr_type = "subp";
3424
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3425 1 hdlr_type = "subt";
3426 } else {
3427 2 hdlr_type = "text";
3428 }
3429 4 descr = "SubtitleHandler";
3430 }
3431
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3432 2 hdlr_type = "hint";
3433 2 descr = "HintHandler";
3434
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3435 13 hdlr_type = "tmcd";
3436 13 descr = "TimeCodeHandler";
3437
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3438 1 hdlr_type = "meta";
3439 1 descr = "GoPro MET"; // GoPro Metadata
3440 } else {
3441 av_log(s, AV_LOG_WARNING,
3442 "Unknown hdlr_type for %s, writing dummy values\n",
3443 av_fourcc2str(track->par->codec_tag));
3444 }
3445
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 3 times.
333 if (track->st) {
3446 // hdlr.name is used by some players to identify the content title
3447 // of the track. So if an alternate handler description is
3448 // specified, use it.
3449 AVDictionaryEntry *t;
3450 330 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3451
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 309 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
330 if (t && utf8len(t->value))
3452 21 descr = t->value;
3453 }
3454 }
3455
3456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 520 times.
520 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3457 descr = "";
3458
3459 520 avio_wb32(pb, 0); /* size */
3460 520 ffio_wfourcc(pb, "hdlr");
3461 520 avio_wb32(pb, 0); /* Version & flags */
3462 520 avio_write(pb, hdlr, 4); /* handler */
3463 520 ffio_wfourcc(pb, hdlr_type); /* handler type */
3464 520 avio_wb32(pb, 0); /* reserved */
3465 520 avio_wb32(pb, 0); /* reserved */
3466 520 avio_wb32(pb, 0); /* reserved */
3467 520 descr_len = strlen(descr);
3468
4/4
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 187 times.
✓ Branch 3 taken 146 times.
520 if (!track || track->mode == MODE_MOV)
3469 374 avio_w8(pb, descr_len); /* pascal string */
3470 520 avio_write(pb, descr, descr_len); /* handler description */
3471
4/4
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 146 times.
✓ Branch 3 taken 187 times.
520 if (track && track->mode != MODE_MOV)
3472 146 avio_w8(pb, 0); /* c string */
3473 520 return update_size(pb, pos);
3474 }
3475
3476 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3477 {
3478 int64_t pos = avio_tell(pb);
3479 avio_wb32(pb, 0); /* size */
3480 ffio_wfourcc(pb, "pitm");
3481 avio_wb32(pb, 0); /* Version & flags */
3482 avio_wb16(pb, item_id); /* item_id */
3483 return update_size(pb, pos);
3484 }
3485
3486 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3487 {
3488 int64_t pos = avio_tell(pb);
3489 avio_wb32(pb, 0); /* size */
3490 ffio_wfourcc(pb, "iloc");
3491 avio_wb32(pb, 0); /* Version & flags */
3492 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3493 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3494 avio_wb16(pb, mov->nb_streams); /* item_count */
3495
3496 for (int i = 0; i < mov->nb_streams; i++) {
3497 avio_wb16(pb, i + 1); /* item_id */
3498 avio_wb16(pb, 0); /* data_reference_index */
3499 avio_wb16(pb, 1); /* extent_count */
3500 mov->avif_extent_pos[i] = avio_tell(pb);
3501 avio_wb32(pb, 0); /* extent_offset (written later) */
3502 // For animated AVIF, we simply write the first packet's size.
3503 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3504 }
3505
3506 return update_size(pb, pos);
3507 }
3508
3509 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3510 {
3511 int64_t iinf_pos = avio_tell(pb);
3512 avio_wb32(pb, 0); /* size */
3513 ffio_wfourcc(pb, "iinf");
3514 avio_wb32(pb, 0); /* Version & flags */
3515 avio_wb16(pb, mov->nb_streams); /* entry_count */
3516
3517 for (int i = 0; i < mov->nb_streams; i++) {
3518 int64_t infe_pos = avio_tell(pb);
3519 avio_wb32(pb, 0); /* size */
3520 ffio_wfourcc(pb, "infe");
3521 avio_w8(pb, 0x2); /* Version */
3522 avio_wb24(pb, 0); /* flags */
3523 avio_wb16(pb, i + 1); /* item_id */
3524 avio_wb16(pb, 0); /* item_protection_index */
3525 avio_write(pb, "av01", 4); /* item_type */
3526 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3527 update_size(pb, infe_pos);
3528 }
3529
3530 return update_size(pb, iinf_pos);
3531 }
3532
3533
3534 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3535 {
3536 int64_t auxl_pos;
3537 int64_t iref_pos = avio_tell(pb);
3538 avio_wb32(pb, 0); /* size */
3539 ffio_wfourcc(pb, "iref");
3540 avio_wb32(pb, 0); /* Version & flags */
3541
3542 auxl_pos = avio_tell(pb);
3543 avio_wb32(pb, 0); /* size */
3544 ffio_wfourcc(pb, "auxl");
3545 avio_wb16(pb, 2); /* from_item_ID */
3546 avio_wb16(pb, 1); /* reference_count */
3547 avio_wb16(pb, 1); /* to_item_ID */
3548 update_size(pb, auxl_pos);
3549
3550 return update_size(pb, iref_pos);
3551 }
3552
3553 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3554 int stream_index)
3555 {
3556 int64_t pos = avio_tell(pb);
3557 avio_wb32(pb, 0); /* size */
3558 ffio_wfourcc(pb, "ispe");
3559 avio_wb32(pb, 0); /* Version & flags */
3560 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3561 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3562 return update_size(pb, pos);
3563 }
3564
3565 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3566 int stream_index)
3567 {
3568 int64_t pos = avio_tell(pb);
3569 const AVPixFmtDescriptor *pixdesc =
3570 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3571 avio_wb32(pb, 0); /* size */
3572 ffio_wfourcc(pb, "pixi");
3573 avio_wb32(pb, 0); /* Version & flags */
3574 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3575 for (int i = 0; i < pixdesc->nb_components; ++i) {
3576 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3577 }
3578 return update_size(pb, pos);
3579 }
3580
3581 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3582 {
3583 int64_t pos = avio_tell(pb);
3584 avio_wb32(pb, 0); /* size */
3585 ffio_wfourcc(pb, "ipco");
3586 for (int i = 0; i < mov->nb_streams; i++) {
3587 mov_write_ispe_tag(pb, mov, s, i);
3588 mov_write_pixi_tag(pb, mov, s, i);
3589 mov_write_av1c_tag(pb, &mov->tracks[i]);
3590 if (!i)
3591 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3592 else
3593 mov_write_aux_tag(pb, "auxC");
3594 }
3595 return update_size(pb, pos);
3596 }
3597
3598 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3599 {
3600 int64_t pos = avio_tell(pb);
3601 avio_wb32(pb, 0); /* size */
3602 ffio_wfourcc(pb, "ipma");
3603 avio_wb32(pb, 0); /* Version & flags */
3604 avio_wb32(pb, mov->nb_streams); /* entry_count */
3605
3606 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3607 avio_wb16(pb, i + 1); /* item_ID */
3608 avio_w8(pb, 4); /* association_count */
3609
3610 // ispe association.
3611 avio_w8(pb, index++); /* essential and property_index */
3612 // pixi association.
3613 avio_w8(pb, index++); /* essential and property_index */
3614 // av1C association.
3615 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3616 // colr/auxC association.
3617 avio_w8(pb, index++); /* essential and property_index */
3618 }
3619 return update_size(pb, pos);
3620 }
3621
3622 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3623 {
3624 int64_t pos = avio_tell(pb);
3625 avio_wb32(pb, 0); /* size */
3626 ffio_wfourcc(pb, "iprp");
3627 mov_write_ipco_tag(pb, mov, s);
3628 mov_write_ipma_tag(pb, mov, s);
3629 return update_size(pb, pos);
3630 }
3631
3632 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3633 {
3634 /* This atom must be present, but leaving the values at zero
3635 * seems harmless. */
3636 2 avio_wb32(pb, 28); /* size */
3637 2 ffio_wfourcc(pb, "hmhd");
3638 2 avio_wb32(pb, 0); /* version, flags */
3639 2 avio_wb16(pb, 0); /* maxPDUsize */
3640 2 avio_wb16(pb, 0); /* avgPDUsize */
3641 2 avio_wb32(pb, 0); /* maxbitrate */
3642 2 avio_wb32(pb, 0); /* avgbitrate */
3643 2 avio_wb32(pb, 0); /* reserved */
3644 2 return 28;
3645 }
3646
3647 333 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3648 {
3649 333 int64_t pos = avio_tell(pb);
3650 int ret;
3651
3652 333 avio_wb32(pb, 0); /* size */
3653 333 ffio_wfourcc(pb, "minf");
3654
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3655 205 mov_write_vmhd_tag(pb);
3656
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3657 108 mov_write_smhd_tag(pb);
3658
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3659
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
4 if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
3660 1 mov_write_gmhd_tag(pb, track);
3661
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3662 1 mov_write_sthd_tag(pb);
3663 } else {
3664 2 mov_write_nmhd_tag(pb);
3665 }
3666
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3667 2 mov_write_hmhd_tag(pb);
3668
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3669
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3670 4 mov_write_nmhd_tag(pb);
3671 else
3672 9 mov_write_gmhd_tag(pb, track);
3673
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3674 1 mov_write_gmhd_tag(pb, track);
3675 }
3676
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3677 187 mov_write_hdlr_tag(s, pb, NULL);
3678 333 mov_write_dinf_tag(pb);
3679
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3680 return ret;
3681 333 return update_size(pb, pos);
3682 }
3683
3684 1294 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3685 int64_t *start, int64_t *end)
3686 {
3687
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1244 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1294 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3688 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3689 // another track's duration, while the end_pts may be left at zero.
3690 // Calculate the pts duration for that track instead.
3691 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3692 38 *start = av_rescale(*start, track->timescale,
3693 38 mov->tracks[track->src_track].timescale);
3694 38 *end = av_rescale(*end, track->timescale,
3695 38 mov->tracks[track->src_track].timescale);
3696 38 return;
3697 }
3698
2/2
✓ Branch 0 taken 1198 times.
✓ Branch 1 taken 58 times.
1256 if (track->end_pts != AV_NOPTS_VALUE &&
3699
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_dts != AV_NOPTS_VALUE &&
3700
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_cts != AV_NOPTS_VALUE) {
3701 1198 *start = track->start_dts + track->start_cts;
3702 1198 *end = track->end_pts;
3703 1198 return;
3704 }
3705 58 *start = 0;
3706 58 *end = track->track_duration;
3707 }
3708
3709 616 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3710 {
3711 int64_t start, end;
3712 616 get_pts_range(mov, track, &start, &end);
3713 616 return end - start;
3714 }
3715
3716 // Calculate the actual duration of the track, after edits.
3717 // If it starts with a pts < 0, that is removed by the edit list.
3718 // If it starts with a pts > 0, the edit list adds a delay before that.
3719 // Thus, with edit lists enabled, the post-edit output of the file is
3720 // starting with pts=0.
3721 640 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3722 {
3723 int64_t start, end;
3724 640 get_pts_range(mov, track, &start, &end);
3725
2/2
✓ Branch 0 taken 572 times.
✓ Branch 1 taken 68 times.
640 if (mov->use_editlist != 0)
3726 572 start = 0;
3727 640 return end - start;
3728 }
3729
3730 903 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3731 {
3732
4/4
✓ Branch 0 taken 666 times.
✓ Branch 1 taken 237 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 652 times.
903 if (track && track->mode == MODE_ISM)
3733 14 return 1;
3734
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 4 times.
889 if (duration < INT32_MAX)
3735 885 return 0;
3736 4 return 1;
3737 }
3738
3739 333 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3740 MOVTrack *track)
3741 {
3742 333 int64_t duration = calc_samples_pts_duration(mov, track);
3743 333 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3744
3745
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3746 333 ffio_wfourcc(pb, "mdhd");
3747 333 avio_w8(pb, version);
3748 333 avio_wb24(pb, 0); /* flags */
3749
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 if (version == 1) {
3750 11 avio_wb64(pb, track->time);
3751 11 avio_wb64(pb, track->time);
3752 } else {
3753 322 avio_wb32(pb, track->time); /* creation time */
3754 322 avio_wb32(pb, track->time); /* modification time */
3755 }
3756 333 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3757
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 83 times.
333 if (!track->entry && mov->mode == MODE_ISM)
3758
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3759
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3760
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 79 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3761 else
3762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3763 333 avio_wb16(pb, track->language); /* language */
3764 333 avio_wb16(pb, 0); /* reserved (quality) */
3765
3766
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
333 if (version != 0 && track->mode == MODE_MOV) {
3767 av_log(NULL, AV_LOG_ERROR,
3768 "FATAL error, file duration too long for timebase, this file will not be\n"
3769 "playable with QuickTime. Choose a different timebase with "
3770 "-video_track_timescale or a different container format\n");
3771 }
3772
3773 333 return 32;
3774 }
3775
3776 333 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3777 MOVMuxContext *mov, MOVTrack *track)
3778 {
3779 333 int64_t pos = avio_tell(pb);
3780 int ret;
3781
3782 333 avio_wb32(pb, 0); /* size */
3783 333 ffio_wfourcc(pb, "mdia");
3784 333 mov_write_mdhd_tag(pb, mov, track);
3785 333 mov_write_hdlr_tag(s, pb, track);
3786
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3787 return ret;
3788 333 return update_size(pb, pos);
3789 }
3790
3791 /* transformation matrix
3792 |a b u|
3793 |c d v|
3794 |tx ty w| */
3795 569 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3796 int16_t d, int16_t tx, int16_t ty)
3797 {
3798 569 avio_wb32(pb, a << 16); /* 16.16 format */
3799 569 avio_wb32(pb, b << 16); /* 16.16 format */
3800 569 avio_wb32(pb, 0); /* u in 2.30 format */
3801 569 avio_wb32(pb, c << 16); /* 16.16 format */
3802 569 avio_wb32(pb, d << 16); /* 16.16 format */
3803 569 avio_wb32(pb, 0); /* v in 2.30 format */
3804 569 avio_wb32(pb, tx << 16); /* 16.16 format */
3805 569 avio_wb32(pb, ty << 16); /* 16.16 format */
3806 569 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3807 569 }
3808
3809 333 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3810 MOVTrack *track, AVStream *st)
3811 {
3812 666 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3813 333 mov->movie_timescale, track->timescale,
3814 AV_ROUND_UP);
3815 int version;
3816 333 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3817 333 int group = 0;
3818
3819 333 uint32_t *display_matrix = NULL;
3820 int i;
3821
3822
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->mode == MODE_AVIF)
3823 if (!mov->avif_loop_count)
3824 duration = INT64_MAX;
3825 else
3826 duration *= mov->avif_loop_count;
3827
3828
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
333 if (st) {
3829 const AVPacketSideData *sd;
3830
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (mov->per_stream_grouping)
3831 group = st->index;
3832 else
3833 320 group = st->codecpar->codec_type;
3834
3835 320 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3836 320 st->codecpar->nb_coded_side_data,
3837 AV_PKT_DATA_DISPLAYMATRIX);
3838
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 319 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
320 if (sd && sd->size == 9 * sizeof(*display_matrix))
3839 1 display_matrix = (uint32_t *)sd->data;
3840 }
3841
3842
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 25 times.
333 if (track->flags & MOV_TRACK_ENABLED)
3843 308 flags |= MOV_TKHD_FLAG_ENABLED;
3844
3845 333 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3846
3847
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3848 333 ffio_wfourcc(pb, "tkhd");
3849 333 avio_w8(pb, version);
3850 333 avio_wb24(pb, flags);
3851
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 if (version == 1) {
3852 7 avio_wb64(pb, track->time);
3853 7 avio_wb64(pb, track->time);
3854 } else {
3855 326 avio_wb32(pb, track->time); /* creation time */
3856 326 avio_wb32(pb, track->time); /* modification time */
3857 }
3858 333 avio_wb32(pb, track->track_id); /* track-id */
3859 333 avio_wb32(pb, 0); /* reserved */
3860
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 83 times.
333 if (!track->entry && mov->mode == MODE_ISM)
3861
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3862
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3864 else
3865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3866
3867 333 avio_wb32(pb, 0); /* reserved */
3868 333 avio_wb32(pb, 0); /* reserved */
3869 333 avio_wb16(pb, 0); /* layer */
3870 333 avio_wb16(pb, group); /* alternate group) */
3871 /* Volume, only for audio */
3872
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3873 108 avio_wb16(pb, 0x0100);
3874 else
3875 225 avio_wb16(pb, 0);
3876 333 avio_wb16(pb, 0); /* reserved */
3877
3878 /* Matrix structure */
3879
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 332 times.
333 if (display_matrix) {
3880
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3881 9 avio_wb32(pb, display_matrix[i]);
3882 } else {
3883 332 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3884 }
3885 /* Track width and height, for visual only */
3886
4/4
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 115 times.
✓ Branch 3 taken 205 times.
333 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3887
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 112 times.
323 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3888 int64_t track_width_1616;
3889
3/4
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
208 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
3890 138 track_width_1616 = track->par->width * 0x10000ULL;
3891 } else {
3892 70 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3893 70 track->par->width * 0x10000LL,
3894 70 st->sample_aspect_ratio.den);
3895
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 68 times.
70 if (!track_width_1616 ||
3896
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 track->height != track->par->height ||
3897 track_width_1616 > UINT32_MAX)
3898 68 track_width_1616 = track->par->width * 0x10000ULL;
3899 }
3900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track_width_1616 > UINT32_MAX) {
3901 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3902 track_width_1616 = 0;
3903 }
3904 208 avio_wb32(pb, track_width_1616);
3905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track->height > 0xFFFF) {
3906 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3907 avio_wb32(pb, 0);
3908 } else
3909 208 avio_wb32(pb, track->height * 0x10000U);
3910 } else {
3911 125 avio_wb32(pb, 0);
3912 125 avio_wb32(pb, 0);
3913 }
3914 333 return 0x5c;
3915 }
3916
3917 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3918 {
3919 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3920 1 track->par->sample_aspect_ratio.den);
3921
3922 1 int64_t pos = avio_tell(pb);
3923
3924 1 avio_wb32(pb, 0); /* size */
3925 1 ffio_wfourcc(pb, "tapt");
3926
3927 1 avio_wb32(pb, 20);
3928 1 ffio_wfourcc(pb, "clef");
3929 1 avio_wb32(pb, 0);
3930 1 avio_wb32(pb, width << 16);
3931 1 avio_wb32(pb, track->par->height << 16);
3932
3933 1 avio_wb32(pb, 20);
3934 1 ffio_wfourcc(pb, "prof");
3935 1 avio_wb32(pb, 0);
3936 1 avio_wb32(pb, width << 16);
3937 1 avio_wb32(pb, track->par->height << 16);
3938
3939 1 avio_wb32(pb, 20);
3940 1 ffio_wfourcc(pb, "enof");
3941 1 avio_wb32(pb, 0);
3942 1 avio_wb32(pb, track->par->width << 16);
3943 1 avio_wb32(pb, track->par->height << 16);
3944
3945 1 return update_size(pb, pos);
3946 }
3947
3948 // This box is written in the following cases:
3949 // * Seems important for the psp playback. Without it the movie seems to hang.
3950 // * Used for specifying the looping behavior of animated AVIF (as specified
3951 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
3952 283 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
3953 MOVTrack *track)
3954 {
3955 566 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
3956 283 mov->movie_timescale, track->timescale,
3957 AV_ROUND_UP);
3958 283 int version = duration < INT32_MAX ? 0 : 1;
3959 int entry_size, entry_count, size;
3960 283 int64_t delay, start_ct = track->start_cts;
3961 283 int64_t start_dts = track->start_dts;
3962 283 int flags = 0;
3963
3964
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 54 times.
283 if (track->entry) {
3965
2/4
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 229 times.
229 if (start_dts != track->cluster[0].dts || start_ct != track->cluster[0].cts) {
3966
3967 av_log(mov->fc, AV_LOG_DEBUG,
3968 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
3969 track->cluster[0].dts, track->cluster[0].cts,
3970 start_dts, start_ct, track->track_id);
3971 start_dts = track->cluster[0].dts;
3972 start_ct = track->cluster[0].cts;
3973 }
3974 }
3975
3976 283 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
3977 283 track->timescale, AV_ROUND_DOWN);
3978
3979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (mov->mode == MODE_AVIF) {
3980 delay = 0;
3981 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
3982 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
3983 // list is not repeated, while (flags & 1) equal to 1 specifies that the
3984 // edit list is repeated.
3985 flags = mov->avif_loop_count != 1;
3986 start_ct = 0;
3987 }
3988
3989 283 version |= delay < INT32_MAX ? 0 : 1;
3990
3991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 entry_size = (version == 1) ? 20 : 12;
3992
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 entry_count = 1 + (delay > 0);
3993 283 size = 24 + entry_count * entry_size;
3994
3995 /* write the atom data */
3996 283 avio_wb32(pb, size);
3997 283 ffio_wfourcc(pb, "edts");
3998 283 avio_wb32(pb, size - 8);
3999 283 ffio_wfourcc(pb, "elst");
4000 283 avio_w8(pb, version);
4001 283 avio_wb24(pb, flags); /* flags */
4002
4003 283 avio_wb32(pb, entry_count);
4004
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 if (delay > 0) { /* add an empty edit to delay presentation */
4005 /* In the positive delay case, the delay includes the cts
4006 * offset, and the second edit list entry below trims out
4007 * the same amount from the actual content. This makes sure
4008 * that the offset last sample is included in the edit
4009 * list duration as well. */
4010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
4011 avio_wb64(pb, delay);
4012 avio_wb64(pb, -1);
4013 } else {
4014 2 avio_wb32(pb, delay);
4015 2 avio_wb32(pb, -1);
4016 }
4017 2 avio_wb32(pb, 0x00010000);
4018
1/2
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
281 } else if (mov->mode != MODE_AVIF) {
4019 /* Avoid accidentally ending up with start_ct = -1 which has got a
4020 * special meaning. Normally start_ct should end up positive or zero
4021 * here, but use FFMIN in case dts is a small positive integer
4022 * rounded to 0 when represented in movie timescale units. */
4023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
281 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
4024 281 start_ct = -FFMIN(start_dts, 0);
4025 /* Note, this delay is calculated from the pts of the first sample,
4026 * ensuring that we don't reduce the duration for cases with
4027 * dts<0 pts=0. */
4028 281 duration += delay;
4029 }
4030
4031 /* For fragmented files, we don't know the full length yet. Setting
4032 * duration to 0 allows us to only specify the offset, including
4033 * the rest of the content (from all future fragments) without specifying
4034 * an explicit duration. */
4035
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 225 times.
283 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
4036 58 duration = 0;
4037
4038 /* duration */
4039
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (version == 1) {
4040 avio_wb64(pb, duration);
4041 avio_wb64(pb, start_ct);
4042 } else {
4043 283 avio_wb32(pb, duration);
4044 283 avio_wb32(pb, start_ct);
4045 }
4046 283 avio_wb32(pb, 0x00010000);
4047 283 return size;
4048 }
4049
4050 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4051 {
4052 14 avio_wb32(pb, 20); // size
4053 14 ffio_wfourcc(pb, "tref");
4054 14 avio_wb32(pb, 12); // size (subatom)
4055 14 avio_wl32(pb, track->tref_tag);
4056 14 avio_wb32(pb, track->tref_id);
4057 14 return 20;
4058 }
4059
4060 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4061 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4062 {
4063 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4064 2 ffio_wfourcc(pb, "uuid");
4065 2 ffio_wfourcc(pb, "USMT");
4066 2 avio_wb32(pb, 0x21d24fce);
4067 2 avio_wb32(pb, 0xbb88695c);
4068 2 avio_wb32(pb, 0xfac9c740);
4069 2 avio_wb32(pb, 0x1c); // another size here!
4070 2 ffio_wfourcc(pb, "MTDT");
4071 2 avio_wb32(pb, 0x00010012);
4072 2 avio_wb32(pb, 0x0a);
4073 2 avio_wb32(pb, 0x55c40000);
4074 2 avio_wb32(pb, 0x1);
4075 2 avio_wb32(pb, 0x0);
4076 2 return 0x34;
4077 }
4078
4079 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4080 {
4081 2 AVFormatContext *ctx = track->rtp_ctx;
4082 2 char buf[1000] = "";
4083 int len;
4084
4085 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4086 NULL, NULL, 0, 0, ctx);
4087 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4088 2 len = strlen(buf);
4089
4090 2 avio_wb32(pb, len + 24);
4091 2 ffio_wfourcc(pb, "udta");
4092 2 avio_wb32(pb, len + 16);
4093 2 ffio_wfourcc(pb, "hnti");
4094 2 avio_wb32(pb, len + 8);
4095 2 ffio_wfourcc(pb, "sdp ");
4096 2 avio_write(pb, buf, len);
4097 2 return len + 24;
4098 }
4099
4100 312 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4101 const char *tag, const char *str)
4102 {
4103 312 int64_t pos = avio_tell(pb);
4104 312 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4105
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 311 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
312 if (!t || !utf8len(t->value))
4106 311 return 0;
4107
4108 1 avio_wb32(pb, 0); /* size */
4109 1 ffio_wfourcc(pb, tag); /* type */
4110 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4111 1 return update_size(pb, pos);
4112 }
4113
4114 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4115 const char *value)
4116 {
4117 2 int64_t pos = avio_tell(pb);
4118
4119 /* Box|FullBox basics */
4120 2 avio_wb32(pb, 0); /* size placeholder */
4121 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4122 2 avio_w8(pb, 0); /* version = 0 */
4123 2 avio_wb24(pb, 0); /* flags = 0 */
4124
4125 /* Required null-terminated scheme URI */
4126 2 avio_write(pb, (const unsigned char *)scheme_uri,
4127 2 strlen(scheme_uri));
4128 2 avio_w8(pb, 0);
4129
4130 /* Optional value string */
4131
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])
4132 2 avio_write(pb, (const unsigned char *)value,
4133 2 strlen(value));
4134
4135 2 avio_w8(pb, 0);
4136
4137 2 return update_size(pb, pos);
4138 }
4139
4140 131 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4141 {
4142 131 int ret = AVERROR_BUG;
4143
4144
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 131 times.
262 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4145 131 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4146
4147
2/2
✓ Branch 0 taken 655 times.
✓ Branch 1 taken 131 times.
786 for (int j = 0; map.value_maps[j].disposition; j++) {
4148 655 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4149
2/2
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 2 times.
655 if (!(st->disposition & value_map.disposition))
4150 653 continue;
4151
4152
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)
4153 return ret;
4154 }
4155 }
4156
4157 131 return 0;
4158 }
4159
4160 333 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4161 AVStream *st)
4162 {
4163 AVIOContext *pb_buf;
4164 int ret, size;
4165 uint8_t *buf;
4166
4167
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 320 times.
333 if (!st)
4168 13 return 0;
4169
4170 320 ret = avio_open_dyn_buf(&pb_buf);
4171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (ret < 0)
4172 return ret;
4173
4174
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 8 times.
320 if (mov->mode & (MODE_MP4|MODE_MOV))
4175 312 mov_write_track_metadata(pb_buf, st, "name", "title");
4176
4177
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 189 times.
320 if (mov->mode & MODE_MP4) {
4178
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
131 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4179 return ret;
4180 }
4181
4182
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 317 times.
320 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4183 3 avio_wb32(pb, size + 8);
4184 3 ffio_wfourcc(pb, "udta");
4185 3 avio_write(pb, buf, size);
4186 }
4187 320 ffio_free_dyn_buf(&pb_buf);
4188
4189 320 return 0;
4190 }
4191
4192 333 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4193 MOVTrack *track, AVStream *st)
4194 {
4195 333 int64_t pos = avio_tell(pb);
4196 333 int entry_backup = track->entry;
4197 333 int chunk_backup = track->chunkCount;
4198 int ret;
4199
4200 /* If we want to have an empty moov, but some samples already have been
4201 * buffered (delay_moov), pretend that no samples have been written yet. */
4202
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
333 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4203 90 track->chunkCount = track->entry = 0;
4204
4205 333 avio_wb32(pb, 0); /* size */
4206 333 ffio_wfourcc(pb, "trak");
4207 333 mov_write_tkhd_tag(pb, mov, track, st);
4208
4209 av_assert2(mov->use_editlist >= 0);
4210
4211
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (track->start_dts != AV_NOPTS_VALUE) {
4212
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 24 times.
307 if (mov->use_editlist)
4213 283 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4214
5/8
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
24 else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
4215 av_log(mov->fc, AV_LOG_WARNING,
4216 "Not writing any edit list even though one would have been required\n");
4217 }
4218
4219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->is_animated_avif)
4220 mov_write_edts_tag(pb, mov, track);
4221
4222
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 319 times.
333 if (track->tref_tag)
4223 14 mov_write_tref_tag(pb, track);
4224
4225
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4226 return ret;
4227
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->mode == MODE_PSP)
4228 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4229
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->tag == MKTAG('r','t','p',' '))
4230 2 mov_write_udta_sdp(pb, track);
4231
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 if (track->mode == MODE_MOV) {
4232
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 49 times.
187 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4233 138 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4234
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
138 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4235 1 mov_write_tapt_tag(pb, track);
4236 }
4237 }
4238
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
187 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4239 mov_write_tapt_tag(pb, track);
4240 }
4241 }
4242 333 mov_write_track_udta_tag(pb, mov, st);
4243 333 track->entry = entry_backup;
4244 333 track->chunkCount = chunk_backup;
4245 333 return update_size(pb, pos);
4246 }
4247
4248 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4249 {
4250 int i, has_audio = 0, has_video = 0;
4251 int64_t pos = avio_tell(pb);
4252 int audio_profile = mov->iods_audio_profile;
4253 int video_profile = mov->iods_video_profile;
4254 for (i = 0; i < mov->nb_tracks; i++) {
4255 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4256 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4257 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4258 }
4259 }
4260 if (audio_profile < 0)
4261 audio_profile = 0xFF - has_audio;
4262 if (video_profile < 0)
4263 video_profile = 0xFF - has_video;
4264 avio_wb32(pb, 0x0); /* size */
4265 ffio_wfourcc(pb, "iods");
4266 avio_wb32(pb, 0); /* version & flags */
4267 put_descr(pb, 0x10, 7);
4268 avio_wb16(pb, 0x004f);
4269 avio_w8(pb, 0xff);
4270 avio_w8(pb, 0xff);
4271 avio_w8(pb, audio_profile);
4272 avio_w8(pb, video_profile);
4273 avio_w8(pb, 0xff);
4274 return update_size(pb, pos);
4275 }
4276
4277 108 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4278 {
4279 108 avio_wb32(pb, 0x20); /* size */
4280 108 ffio_wfourcc(pb, "trex");
4281 108 avio_wb32(pb, 0); /* version & flags */
4282 108 avio_wb32(pb, track->track_id); /* track ID */
4283 108 avio_wb32(pb, 1); /* default sample description index */
4284 108 avio_wb32(pb, 0); /* default sample duration */
4285 108 avio_wb32(pb, 0); /* default sample size */
4286 108 avio_wb32(pb, 0); /* default sample flags */
4287 108 return 0;
4288 }
4289
4290 56 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4291 {
4292 56 int64_t pos = avio_tell(pb);
4293 int i;
4294 56 avio_wb32(pb, 0x0); /* size */
4295 56 ffio_wfourcc(pb, "mvex");
4296
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 56 times.
164 for (i = 0; i < mov->nb_tracks; i++)
4297 108 mov_write_trex_tag(pb, &mov->tracks[i]);
4298 56 return update_size(pb, pos);
4299 }
4300
4301 237 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4302 {
4303 237 int max_track_id = 1, i;
4304 237 int64_t max_track_len = 0;
4305 int version;
4306 int timescale;
4307
4308
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
4309
3/4
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 307 times.
✗ Branch 3 not taken.
335 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4310 614 int64_t max_track_len_temp = av_rescale_rnd(
4311 307 calc_pts_duration(mov, &mov->tracks[i]),
4312 307 mov->movie_timescale,
4313 307 mov->tracks[i].timescale,
4314 AV_ROUND_UP);
4315
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 69 times.
307 if (max_track_len < max_track_len_temp)
4316 238 max_track_len = max_track_len_temp;
4317
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 224 times.
307 if (max_track_id < mov->tracks[i].track_id)
4318 83 max_track_id = mov->tracks[i].track_id;
4319 }
4320 }
4321 /* If using delay_moov, make sure the output is the same as if no
4322 * samples had been written yet. */
4323
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 190 times.
237 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4324 47 max_track_len = 0;
4325 47 max_track_id = 1;
4326 }
4327
4328 237 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4330
4331 237 ffio_wfourcc(pb, "mvhd");
4332 237 avio_w8(pb, version);
4333 237 avio_wb24(pb, 0); /* flags */
4334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (version == 1) {
4335 avio_wb64(pb, mov->time);
4336 avio_wb64(pb, mov->time);
4337 } else {
4338 237 avio_wb32(pb, mov->time); /* creation time */
4339 237 avio_wb32(pb, mov->time); /* modification time */
4340 }
4341
4342 237 timescale = mov->movie_timescale;
4343
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
237 if (mov->mode == MODE_AVIF && !timescale)
4344 timescale = mov->tracks[0].timescale;
4345
4346 237 avio_wb32(pb, timescale);
4347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4348
4349 237 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4350 237 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4351 237 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4352
4353 /* Matrix structure */
4354 237 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4355
4356 237 avio_wb32(pb, 0); /* reserved (preview time) */
4357 237 avio_wb32(pb, 0); /* reserved (preview duration) */
4358 237 avio_wb32(pb, 0); /* reserved (poster time) */
4359 237 avio_wb32(pb, 0); /* reserved (selection time) */
4360 237 avio_wb32(pb, 0); /* reserved (selection duration) */
4361 237 avio_wb32(pb, 0); /* reserved (current time) */
4362 237 avio_wb32(pb, max_track_id + 1); /* Next track id */
4363 237 return 0x6c;
4364 }
4365
4366 82 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4367 AVFormatContext *s)
4368 {
4369 82 avio_wb32(pb, 33); /* size */
4370 82 ffio_wfourcc(pb, "hdlr");
4371 82 avio_wb32(pb, 0);
4372 82 avio_wb32(pb, 0);
4373 82 ffio_wfourcc(pb, "mdir");
4374 82 ffio_wfourcc(pb, "appl");
4375 82 avio_wb32(pb, 0);
4376 82 avio_wb32(pb, 0);
4377 82 avio_w8(pb, 0);
4378 82 return 33;
4379 }
4380
4381 /* helper function to write a data tag with the specified string as data */
4382 54 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4383 {
4384 54 size_t data_len = strlen(data);
4385
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 34 times.
54 if (long_style) {
4386 20 int size = 16 + data_len;
4387 20 avio_wb32(pb, size); /* size */
4388 20 ffio_wfourcc(pb, "data");
4389 20 avio_wb32(pb, 1);
4390 20 avio_wb32(pb, 0);
4391 20 avio_write(pb, data, data_len);
4392 20 return size;
4393 } else {
4394 34 avio_wb16(pb, data_len); /* string length */
4395
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4396 26 lang = ff_mov_iso639_to_lang("und", 1);
4397 34 avio_wb16(pb, lang);
4398 34 avio_write(pb, data, data_len);
4399 34 return data_len + 4;
4400 }
4401 }
4402
4403 54 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4404 const char *value, int lang, int long_style)
4405 {
4406 54 int size = 0;
4407
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
54 if (value && value[0]) {
4408 54 int64_t pos = avio_tell(pb);
4409 54 avio_wb32(pb, 0); /* size */
4410 54 ffio_wfourcc(pb, name);
4411 54 mov_write_string_data_tag(pb, value, lang, long_style);
4412 54 size = update_size(pb, pos);
4413 }
4414 54 return size;
4415 }
4416
4417 3714 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4418 const char *tag, int *lang)
4419 {
4420 int l, len, len2;
4421 3714 AVDictionaryEntry *t, *t2 = NULL;
4422 char tag2[16];
4423
4424 3714 *lang = 0;
4425
4426
2/2
✓ Branch 1 taken 3662 times.
✓ Branch 2 taken 52 times.
3714 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4427 3662 return NULL;
4428
4429 52 len = strlen(t->key);
4430 52 snprintf(tag2, sizeof(tag2), "%s-", tag);
4431
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 44 times.
52 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4432 8 len2 = strlen(t2->key);
4433
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)
4434
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4435 8 *lang = l;
4436 8 return t;
4437 }
4438 }
4439 44 return t;
4440 }
4441
4442 3632 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4443 const char *name, const char *tag,
4444 int long_style)
4445 {
4446 int lang;
4447 3632 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4448
2/2
✓ Branch 0 taken 3580 times.
✓ Branch 1 taken 52 times.
3632 if (!t)
4449 3580 return 0;
4450 52 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4451 }
4452
4453 /* iTunes bpm number */
4454 82 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4455 {
4456 82 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 int size = 0, tmpo = t ? atoi(t->value) : 0;
4458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (tmpo) {
4459 size = 26;
4460 avio_wb32(pb, size);
4461 ffio_wfourcc(pb, "tmpo");
4462 avio_wb32(pb, size-8); /* size */
4463 ffio_wfourcc(pb, "data");
4464 avio_wb32(pb, 0x15); //type specifier
4465 avio_wb32(pb, 0);
4466 avio_wb16(pb, tmpo); // data
4467 }
4468 82 return size;
4469 }
4470
4471 /* 3GPP TS 26.244 */
4472 82 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4473 {
4474 int lang;
4475 82 int64_t pos = avio_tell(pb);
4476 double latitude, longitude, altitude;
4477 int32_t latitude_fix, longitude_fix, altitude_fix;
4478 82 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4479 82 const char *ptr, *place = "";
4480 char *end;
4481 static const char *astronomical_body = "earth";
4482
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (!t)
4483 82 return 0;
4484
4485 ptr = t->value;
4486 latitude = strtod(ptr, &end);
4487 if (end == ptr) {
4488 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4489 return 0;
4490 }
4491 ptr = end;
4492 longitude = strtod(ptr, &end);
4493 if (end == ptr) {
4494 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4495 return 0;
4496 }
4497 ptr = end;
4498 altitude = strtod(ptr, &end);
4499 /* If no altitude was present, the default 0 should be fine */
4500 if (*end == '/')
4501 place = end + 1;
4502
4503 latitude_fix = (int32_t) ((1 << 16) * latitude);
4504 longitude_fix = (int32_t) ((1 << 16) * longitude);
4505 altitude_fix = (int32_t) ((1 << 16) * altitude);
4506
4507 avio_wb32(pb, 0); /* size */
4508 ffio_wfourcc(pb, "loci"); /* type */
4509 avio_wb32(pb, 0); /* version + flags */
4510 avio_wb16(pb, lang);
4511 avio_write(pb, place, strlen(place) + 1);
4512 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4513 avio_wb32(pb, longitude_fix);
4514 avio_wb32(pb, latitude_fix);
4515 avio_wb32(pb, altitude_fix);
4516 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4517 avio_w8(pb, 0); /* additional notes, null terminated string */
4518
4519 return update_size(pb, pos);
4520 }
4521
4522 /* iTunes track or disc number */
4523 164 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4524 AVFormatContext *s, int disc)
4525 {
4526
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 82 times.
164 AVDictionaryEntry *t = av_dict_get(s->metadata,
4527 disc ? "disc" : "track",
4528 NULL, 0);
4529
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 int size = 0, track = t ? atoi(t->value) : 0;
4530
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 if (track) {
4531 2 int tracks = 0;
4532 2 char *slash = strchr(t->value, '/');
4533
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4534 2 tracks = atoi(slash + 1);
4535 2 avio_wb32(pb, 32); /* size */
4536
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4537 2 avio_wb32(pb, 24); /* size */
4538 2 ffio_wfourcc(pb, "data");
4539 2 avio_wb32(pb, 0); // 8 bytes empty
4540 2 avio_wb32(pb, 0);
4541 2 avio_wb16(pb, 0); // empty
4542 2 avio_wb16(pb, track); // track / disc number
4543 2 avio_wb16(pb, tracks); // total track / disc number
4544 2 avio_wb16(pb, 0); // empty
4545 2 size = 32;
4546 }
4547 164 return size;
4548 }
4549
4550 492 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4551 const char *name, const char *tag,
4552 int len)
4553 {
4554 492 AVDictionaryEntry *t = NULL;
4555 uint8_t num;
4556 492 int size = 24 + len;
4557
4558
3/4
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 328 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 164 times.
492 if (len != 1 && len != 4)
4559 return -1;
4560
4561
2/2
✓ Branch 1 taken 490 times.
✓ Branch 2 taken 2 times.
492 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4562 490 return 0;
4563 2 num = atoi(t->value);
4564
4565 2 avio_wb32(pb, size);
4566 2 ffio_wfourcc(pb, name);
4567 2 avio_wb32(pb, size - 8);
4568 2 ffio_wfourcc(pb, "data");
4569 2 avio_wb32(pb, 0x15);
4570 2 avio_wb32(pb, 0);
4571
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4572 2 else avio_w8 (pb, num);
4573
4574 2 return size;
4575 }
4576
4577 82 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4578 {
4579 82 MOVMuxContext *mov = s->priv_data;
4580 82 int64_t pos = 0;
4581
4582
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 82 times.
221 for (int i = 0; i < mov->nb_streams; i++) {
4583 139 MOVTrack *trk = &mov->tracks[i];
4584
4585
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
139 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4586 137 continue;
4587
4588
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4589 1 pos = avio_tell(pb);
4590 1 avio_wb32(pb, 0);
4591 1 ffio_wfourcc(pb, "covr");
4592 }
4593 2 avio_wb32(pb, 16 + trk->cover_image->size);
4594 2 ffio_wfourcc(pb, "data");
4595 2 avio_wb32(pb, trk->tag);
4596 2 avio_wb32(pb , 0);
4597 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4598 }
4599
4600
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 81 times.
82 return pos ? update_size(pb, pos) : 0;
4601 }
4602
4603 /* iTunes meta data list */
4604 82 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4605 AVFormatContext *s)
4606 {
4607 82 int64_t pos = avio_tell(pb);
4608 82 avio_wb32(pb, 0); /* size */
4609 82 ffio_wfourcc(pb, "ilst");
4610 82 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4611 82 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4612 82 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4613 82 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4614 82 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4615 82 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4616
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4617
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 80 times.
82 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4618 2 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4619 }
4620 82 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4621 82 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4622 82 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4623 82 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4624 82 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4625 82 mov_write_string_metadata(s, pb, "desc", "description",1);
4626 82 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4627 82 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4628 82 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4629 82 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4630 82 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4631 82 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4632 82 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4633 82 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4634 82 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4635 82 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4636 82 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4637 82 mov_write_covr(pb, s);
4638 82 mov_write_trkn_tag(pb, mov, s, 0); // track number
4639 82 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4640 82 mov_write_tmpo_tag(pb, s);
4641 82 return update_size(pb, pos);
4642 }
4643
4644 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4645 AVFormatContext *s)
4646 {
4647 avio_wb32(pb, 33); /* size */
4648 ffio_wfourcc(pb, "hdlr");
4649 avio_wb32(pb, 0);
4650 avio_wb32(pb, 0);
4651 ffio_wfourcc(pb, "mdta");
4652 avio_wb32(pb, 0);
4653 avio_wb32(pb, 0);
4654 avio_wb32(pb, 0);
4655 avio_w8(pb, 0);
4656 return 33;
4657 }
4658
4659 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4660 AVFormatContext *s)
4661 {
4662 const AVDictionaryEntry *t = NULL;
4663 int64_t pos = avio_tell(pb);
4664 int64_t curpos, entry_pos;
4665 int count = 0;
4666
4667 avio_wb32(pb, 0); /* size */
4668 ffio_wfourcc(pb, "keys");
4669 avio_wb32(pb, 0);
4670 entry_pos = avio_tell(pb);
4671 avio_wb32(pb, 0); /* entry count */
4672
4673 while (t = av_dict_iterate(s->metadata, t)) {
4674 size_t key_len = strlen(t->key);
4675 avio_wb32(pb, key_len + 8);
4676 ffio_wfourcc(pb, "mdta");
4677 avio_write(pb, t->key, key_len);
4678 count += 1;
4679 }
4680 curpos = avio_tell(pb);
4681 avio_seek(pb, entry_pos, SEEK_SET);
4682 avio_wb32(pb, count); // rewrite entry count
4683 avio_seek(pb, curpos, SEEK_SET);
4684
4685 return update_size(pb, pos);
4686 }
4687
4688 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4689 AVFormatContext *s)
4690 {
4691 const AVDictionaryEntry *t = NULL;
4692 int64_t pos = avio_tell(pb);
4693 int count = 1; /* keys are 1-index based */
4694
4695 avio_wb32(pb, 0); /* size */
4696 ffio_wfourcc(pb, "ilst");
4697
4698 while (t = av_dict_iterate(s->metadata, t)) {
4699 int64_t entry_pos = avio_tell(pb);
4700 avio_wb32(pb, 0); /* size */
4701 avio_wb32(pb, count); /* key */
4702 mov_write_string_data_tag(pb, t->value, 0, 1);
4703 update_size(pb, entry_pos);
4704 count += 1;
4705 }
4706 return update_size(pb, pos);
4707 }
4708
4709 /* meta data tags */
4710 82 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4711 AVFormatContext *s)
4712 {
4713 82 int size = 0;
4714 82 int64_t pos = avio_tell(pb);
4715 82 avio_wb32(pb, 0); /* size */
4716 82 ffio_wfourcc(pb, "meta");
4717 82 avio_wb32(pb, 0);
4718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4719 mov_write_mdta_hdlr_tag(pb, mov, s);
4720 mov_write_mdta_keys_tag(pb, mov, s);
4721 mov_write_mdta_ilst_tag(pb, mov, s);
4722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (mov->mode == MODE_AVIF) {
4723 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4724 // We always write the primary item id as 1 since only one track is
4725 // supported for AVIF.
4726 mov_write_pitm_tag(pb, 1);
4727 mov_write_iloc_tag(pb, mov, s);
4728 mov_write_iinf_tag(pb, mov, s);
4729 if (mov->nb_streams > 1)
4730 mov_write_iref_tag(pb, mov, s);
4731 mov_write_iprp_tag(pb, mov, s);
4732 } else {
4733 /* iTunes metadata tag */
4734 82 mov_write_itunes_hdlr_tag(pb, mov, s);
4735 82 mov_write_ilst_tag(pb, mov, s);
4736 }
4737 82 size = update_size(pb, pos);
4738 82 return size;
4739 }
4740
4741 154 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4742 const char *name, const char *key)
4743 {
4744 int len;
4745 AVDictionaryEntry *t;
4746
4747
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4748 154 return 0;
4749
4750 len = strlen(t->value);
4751 if (len > 0) {
4752 int size = len + 8;
4753 avio_wb32(pb, size);
4754 ffio_wfourcc(pb, name);
4755 avio_write(pb, t->value, len);
4756 return size;
4757 }
4758 return 0;
4759 }
4760
4761 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4762 {
4763 int val;
4764 while (*b) {
4765 GET_UTF8(val, *b++, return -1;)
4766 avio_wb16(pb, val);
4767 }
4768 avio_wb16(pb, 0x00);
4769 return 0;
4770 }
4771
4772 static uint16_t language_code(const char *str)
4773 {
4774 return (((str[0] - 0x60) & 0x1F) << 10) +
4775 (((str[1] - 0x60) & 0x1F) << 5) +
4776 (( str[2] - 0x60) & 0x1F);
4777 }
4778
4779 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4780 const char *tag, const char *str)
4781 {
4782 int64_t pos = avio_tell(pb);
4783 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4784 if (!t || !utf8len(t->value))
4785 return 0;
4786 avio_wb32(pb, 0); /* size */
4787 ffio_wfourcc(pb, tag); /* type */
4788 avio_wb32(pb, 0); /* version + flags */
4789 if (!strcmp(tag, "yrrc"))
4790 avio_wb16(pb, atoi(t->value));
4791 else {
4792 avio_wb16(pb, language_code("eng")); /* language */
4793 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4794 if (!strcmp(tag, "albm") &&
4795 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4796 avio_w8(pb, atoi(t->value));
4797 }
4798 return update_size(pb, pos);
4799 }
4800
4801 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4802 {
4803 1 int64_t pos = avio_tell(pb);
4804 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4805
4806 1 avio_wb32(pb, 0); // size
4807 1 ffio_wfourcc(pb, "chpl");
4808 1 avio_wb32(pb, 0x01000000); // version + flags
4809 1 avio_wb32(pb, 0); // unknown
4810 1 avio_w8(pb, nb_chapters);
4811
4812
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4813 4 AVChapter *c = s->chapters[i];
4814 AVDictionaryEntry *t;
4815 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4816
4817
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4818
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4819 4 avio_w8(pb, len);
4820 4 avio_write(pb, t->value, len);
4821 } else
4822 avio_w8(pb, 0);
4823 }
4824 1 return update_size(pb, pos);
4825 }
4826
4827 236 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4828 AVFormatContext *s)
4829 {
4830 AVIOContext *pb_buf;
4831 int ret, size;
4832 uint8_t *buf;
4833
4834 236 ret = avio_open_dyn_buf(&pb_buf);
4835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (ret < 0)
4836 return ret;
4837
4838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (mov->mode & MODE_3GP) {
4839 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4840 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4841 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4842 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4843 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4844 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4845 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4846 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4847 mov_write_loci_tag(s, pb_buf);
4848
3/4
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 154 times.
✗ Branch 3 not taken.
236 } 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
4849 154 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4850 154 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4851 154 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4852 154 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4853 154 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4854 154 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4855 // currently ignored by mov.c
4856 154 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4857 // add support for libquicktime, this atom is also actually read by mov.c
4858 154 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4859 154 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4860 154 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4861 154 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4862 154 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4863 154 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4864 154 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4865 154 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4866 } else {
4867 /* iTunes meta data */
4868 82 mov_write_meta_tag(pb_buf, mov, s);
4869 82 mov_write_loci_tag(s, pb_buf);
4870 }
4871
4872
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
236 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
4873 1 mov_write_chpl_tag(pb_buf, s);
4874
4875
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 126 times.
236 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4876 110 avio_wb32(pb, size + 8);
4877 110 ffio_wfourcc(pb, "udta");
4878 110 avio_write(pb, buf, size);
4879 }
4880 236 ffio_free_dyn_buf(&pb_buf);
4881
4882 236 return 0;
4883 }
4884
4885 static void mov_write_psp_udta_tag(AVIOContext *pb,
4886 const char *str, const char *lang, int type)
4887 {
4888 int len = utf8len(str) + 1;
4889 if (len <= 0)
4890 return;
4891 avio_wb16(pb, len * 2 + 10); /* size */
4892 avio_wb32(pb, type); /* type */
4893 avio_wb16(pb, language_code(lang)); /* language */
4894 avio_wb16(pb, 0x01); /* ? */
4895 ascii_to_wc(pb, str);
4896 }
4897
4898 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4899 {
4900 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4901 int64_t pos, pos2;
4902
4903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4904 pos = avio_tell(pb);
4905 avio_wb32(pb, 0); /* size placeholder*/
4906 ffio_wfourcc(pb, "uuid");
4907 ffio_wfourcc(pb, "USMT");
4908 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4909 avio_wb32(pb, 0xbb88695c);
4910 avio_wb32(pb, 0xfac9c740);
4911
4912 pos2 = avio_tell(pb);
4913 avio_wb32(pb, 0); /* size placeholder*/
4914 ffio_wfourcc(pb, "MTDT");
4915 avio_wb16(pb, 4);
4916
4917 // ?
4918 avio_wb16(pb, 0x0C); /* size */
4919 avio_wb32(pb, 0x0B); /* type */
4920 avio_wb16(pb, language_code("und")); /* language */
4921 avio_wb16(pb, 0x0); /* ? */
4922 avio_wb16(pb, 0x021C); /* data */
4923
4924 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4925 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4926 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4927 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
4928
4929 update_size(pb, pos2);
4930 return update_size(pb, pos);
4931 }
4932
4933 1 return 0;
4934 }
4935
4936 322 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
4937 {
4938 AVEncryptionInitInfo *info;
4939 322 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4940 322 st->codecpar->nb_coded_side_data,
4941 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
4942
1/2
✓ Branch 0 taken 322 times.
✗ Branch 1 not taken.
322 if (!sd)
4943 322 return 0;
4944
4945 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
4946 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
4947 int64_t pos;
4948
4949 if (!copy->data_size && !copy->num_key_ids)
4950 continue;
4951
4952 pos = avio_tell(pb);
4953 avio_wb32(pb, 0); /* size placeholder */
4954 ffio_wfourcc(pb, "pssh");
4955 avio_w8(pb, 1); /* version */
4956 avio_wb24(pb, 0);
4957 for (int i = 0; i < copy->system_id_size; i++)
4958 avio_w8(pb, copy->system_id[i]);
4959 avio_wb32(pb, copy->num_key_ids);
4960 for (int i = 0; i < copy->num_key_ids; i++)
4961 for (int j = 0; j < copy->key_id_size; j++)
4962 avio_w8(pb, copy->key_ids[i][j]);
4963 avio_wb32(pb, copy->data_size);
4964 avio_write(pb, copy->data, copy->data_size);
4965 update_size(pb, pos);
4966 }
4967
4968 av_encryption_init_info_free(info);
4969
4970 return 0;
4971 }
4972
4973 307 static void build_chunks(MOVTrack *trk)
4974 {
4975 int i;
4976 307 MOVIentry *chunk = &trk->cluster[0];
4977 307 uint64_t chunkSize = chunk->size;
4978 307 chunk->chunkNum = 1;
4979
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 252 times.
307 if (trk->chunkCount)
4980 55 return;
4981 252 trk->chunkCount = 1;
4982
2/2
✓ Branch 0 taken 14753 times.
✓ Branch 1 taken 252 times.
15005 for (i = 1; i<trk->entry; i++){
4983
2/2
✓ Branch 0 taken 12852 times.
✓ Branch 1 taken 1901 times.
14753 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
4984
2/2
✓ Branch 0 taken 12207 times.
✓ Branch 1 taken 645 times.
12852 chunkSize + trk->cluster[i].size < (1<<20)){
4985 12207 chunkSize += trk->cluster[i].size;
4986 12207 chunk->samples_in_chunk += trk->cluster[i].entries;
4987 } else {
4988 2546 trk->cluster[i].chunkNum = chunk->chunkNum+1;
4989 2546 chunk=&trk->cluster[i];
4990 2546 chunkSize = chunk->size;
4991 2546 trk->chunkCount++;
4992 }
4993 }
4994 }
4995
4996 /**
4997 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
4998 * the stream ids are used as track ids.
4999 *
5000 * This assumes mov->tracks and s->streams are in the same order and
5001 * there are no gaps in either of them (so mov->tracks[n] refers to
5002 * s->streams[n]).
5003 *
5004 * As an exception, there can be more entries in
5005 * s->streams than in mov->tracks, in which case new track ids are
5006 * generated (starting after the largest found stream id).
5007 */
5008 237 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5009 {
5010 int i;
5011
5012
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 209 times.
237 if (mov->track_ids_ok)
5013 28 return 0;
5014
5015
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->use_stream_ids_as_track_ids) {
5016 1 int next_generated_track_id = 0;
5017
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5018 2 AVStream *st = mov->tracks[i].st;
5019
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5020 2 next_generated_track_id = st->id;
5021 }
5022
5023
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5024
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))
5025 continue;
5026
5027
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;
5028 }
5029 } else {
5030 208 int last_track_id = 0;
5031
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 208 times.
482 for (i = 0; i < mov->nb_tracks; i++) {
5032
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
274 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5033 2 continue;
5034
5035 272 last_track_id =
5036 272 mov->tracks[i].track_id = (mov->tracks[i].st
5037 269 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5038
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 3 times.
272 : FFMAX(i, last_track_id)) + 1;
5039 }
5040 }
5041
5042 209 mov->track_ids_ok = 1;
5043
5044 209 return 0;
5045 }
5046
5047 237 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5048 AVFormatContext *s)
5049 {
5050 int i;
5051 237 int64_t pos = avio_tell(pb);
5052 237 avio_wb32(pb, 0); /* size placeholder*/
5053 237 ffio_wfourcc(pb, "moov");
5054
5055 237 mov_setup_track_ids(mov, s);
5056
5057
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5058
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26 times.
335 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5059 2 continue;
5060
5061 333 mov->tracks[i].time = mov->time;
5062
5063
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (mov->tracks[i].entry)
5064 307 build_chunks(&mov->tracks[i]);
5065 }
5066
5067
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->chapter_track)
5068
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5069 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5070 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5071 }
5072
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5073 335 MOVTrack *track = &mov->tracks[i];
5074
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 333 times.
335 if (track->tag == MKTAG('r','t','p',' ')) {
5075 2 track->tref_tag = MKTAG('h','i','n','t');
5076 2 track->tref_id = mov->tracks[track->src_track].track_id;
5077
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5078 108 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5079 108 track->st->codecpar->nb_coded_side_data,
5080 AV_PKT_DATA_FALLBACK_TRACK );
5081
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
108 if (sd && sd->size == sizeof(int)) {
5082 int *fallback = (int *)sd->data;
5083 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5084 track->tref_tag = MKTAG('f','a','l','l');
5085 track->tref_id = mov->tracks[*fallback].track_id;
5086 }
5087 }
5088 }
5089 }
5090
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5091
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 322 times.
335 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5092 13 int src_trk = mov->tracks[i].src_track;
5093 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5094 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5095 //src_trk may have a different timescale than the tmcd track
5096 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5097 13 mov->tracks[i].timescale,
5098 13 mov->tracks[src_trk].timescale);
5099 }
5100 }
5101
5102 237 mov_write_mvhd_tag(pb, mov);
5103
4/6
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 83 times.
237 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5104 mov_write_iods_tag(pb, mov);
5105
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5106
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26 times.
335 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5108
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
333 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
5110 return ret;
5111 }
5112 }
5113
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 181 times.
237 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5114 56 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5115
5116
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->mode == MODE_PSP)
5117 1 mov_write_uuidusmt_tag(pb, s);
5118
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 else if (mov->mode != MODE_AVIF)
5119 236 mov_write_udta_tag(pb, mov, s);
5120
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 237 times.
559 for (i = 0; i < mov->nb_streams; i++)
5121 322 mov_write_pssh_tag(pb, mov->tracks[i].st);
5122
5123 237 return update_size(pb, pos);
5124 }
5125
5126 static void param_write_int(AVIOContext *pb, const char *name, int value)
5127 {
5128 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5129 }
5130
5131 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5132 {
5133 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5134 }
5135
5136 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5137 {
5138 char buf[150];
5139 len = FFMIN(sizeof(buf) / 2 - 1, len);
5140 ff_data_to_hex(buf, value, len, 0);
5141 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5142 }
5143
5144 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5145 {
5146 int64_t pos = avio_tell(pb);
5147 int i;
5148
5149 static const AVUUID uuid = {
5150 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5151 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5152 };
5153
5154 avio_wb32(pb, 0);
5155 ffio_wfourcc(pb, "uuid");
5156 avio_write(pb, uuid, AV_UUID_LEN);
5157 avio_wb32(pb, 0);
5158
5159 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5160 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5161 avio_printf(pb, "<head>\n");
5162 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5163 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5164 LIBAVFORMAT_IDENT);
5165 avio_printf(pb, "</head>\n");
5166 avio_printf(pb, "<body>\n");
5167 avio_printf(pb, "<switch>\n");
5168
5169 mov_setup_track_ids(mov, s);
5170
5171 for (i = 0; i < mov->nb_tracks; i++) {
5172 MOVTrack *track = &mov->tracks[i];
5173 struct mpeg4_bit_rate_values bit_rates =
5174 calculate_mpeg4_bit_rates(track);
5175 const char *type;
5176 int track_id = track->track_id;
5177 char track_name_buf[32] = { 0 };
5178
5179 AVStream *st = track->st;
5180 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5181
5182 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5183 type = "video";
5184 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5185 type = "audio";
5186 } else {
5187 continue;
5188 }
5189
5190 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5191 bit_rates.avg_bit_rate);
5192 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5193 param_write_int(pb, "trackID", track_id);
5194 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5195
5196 /* Build track name piece by piece: */
5197 /* 1. track type */
5198 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5199 /* 2. track language, if available */
5200 if (lang)
5201 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5202 "_%s", lang->value);
5203 /* 3. special type suffix */
5204 /* "_cc" = closed captions, "_ad" = audio_description */
5205 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5206 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5207 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5208 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5209
5210 param_write_string(pb, "trackName", track_name_buf);
5211
5212 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5213 if (track->par->codec_id == AV_CODEC_ID_H264) {
5214 uint8_t *ptr;
5215 int size = track->par->extradata_size;
5216 if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr,
5217 &size)) {
5218 param_write_hex(pb, "CodecPrivateData",
5219 ptr ? ptr : track->par->extradata,
5220 size);
5221 av_free(ptr);
5222 }
5223 param_write_string(pb, "FourCC", "H264");
5224 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5225 param_write_string(pb, "FourCC", "WVC1");
5226 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5227 track->par->extradata_size);
5228 }
5229 param_write_int(pb, "MaxWidth", track->par->width);
5230 param_write_int(pb, "MaxHeight", track->par->height);
5231 param_write_int(pb, "DisplayWidth", track->par->width);
5232 param_write_int(pb, "DisplayHeight", track->par->height);
5233 } else {
5234 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5235 switch (track->par->profile) {
5236 case AV_PROFILE_AAC_HE_V2:
5237 param_write_string(pb, "FourCC", "AACP");
5238 break;
5239 case AV_PROFILE_AAC_HE:
5240 param_write_string(pb, "FourCC", "AACH");
5241 break;
5242 default:
5243 param_write_string(pb, "FourCC", "AACL");
5244 }
5245 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5246 param_write_string(pb, "FourCC", "WMAP");
5247 }
5248 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5249 track->par->extradata_size);
5250 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5251 track->par->codec_id));
5252 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5253 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5254 0 : track->par->sample_rate);
5255 param_write_int(pb, "BitsPerSample", 16);
5256 param_write_int(pb, "PacketSize", track->par->block_align ?
5257 track->par->block_align : 4);
5258 }
5259 avio_printf(pb, "</%s>\n", type);
5260 }
5261 avio_printf(pb, "</switch>\n");
5262 avio_printf(pb, "</body>\n");
5263 avio_printf(pb, "</smil>\n");
5264
5265 return update_size(pb, pos);
5266 }
5267
5268 142 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5269 {
5270 142 avio_wb32(pb, 16);
5271 142 ffio_wfourcc(pb, "mfhd");
5272 142 avio_wb32(pb, 0);
5273 142 avio_wb32(pb, mov->fragments);
5274 142 return 0;
5275 }
5276
5277 10742 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5278 {
5279
2/2
✓ Branch 0 taken 7200 times.
✓ Branch 1 taken 3542 times.
10742 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5280 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5281 }
5282
5283 234 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5284 MOVTrack *track, int64_t moof_offset)
5285 {
5286 234 int64_t pos = avio_tell(pb);
5287 234 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5288 MOV_TFHD_BASE_DATA_OFFSET;
5289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (!track->entry) {
5290 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5291 } else {
5292 234 flags |= MOV_TFHD_DEFAULT_FLAGS;
5293 }
5294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5295 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5296
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 156 times.
234 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5297 78 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5298 78 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5299 }
5300 /* CMAF requires all values to be explicit in tfhd atoms */
5301
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (mov->flags & FF_MOV_FLAG_CMAF)
5302 8 flags |= MOV_TFHD_STSD_ID;
5303
5304 /* Don't set a default sample size, the silverlight player refuses
5305 * to play files with that set. Don't set a default sample duration,
5306 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5307 * file format says it MUST NOT be set. */
5308
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (track->mode == MODE_ISM)
5309 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5310 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5311
5312 234 avio_wb32(pb, 0); /* size placeholder */
5313 234 ffio_wfourcc(pb, "tfhd");
5314 234 avio_w8(pb, 0); /* version */
5315 234 avio_wb24(pb, flags);
5316
5317 234 avio_wb32(pb, track->track_id); /* track-id */
5318
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 108 times.
234 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5319 126 avio_wb64(pb, moof_offset);
5320
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (flags & MOV_TFHD_STSD_ID) {
5321 8 avio_wb32(pb, 1);
5322 }
5323
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5324 204 track->default_duration = get_cluster_duration(track, 0);
5325 204 avio_wb32(pb, track->default_duration);
5326 }
5327
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5328
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 track->default_size = track->entry ? track->cluster[0].size : 1;
5329 204 avio_wb32(pb, track->default_size);
5330 } else
5331 30 track->default_size = -1;
5332
5333
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5334 /* Set the default flags based on the second sample, if available.
5335 * If the first sample is different, that can be signaled via a separate field. */
5336
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 10 times.
234 if (track->entry > 1)
5337 224 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5338 else
5339 10 track->default_sample_flags =
5340 10 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5341
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5342 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5343 234 avio_wb32(pb, track->default_sample_flags);
5344 }
5345
5346 234 return update_size(pb, pos);
5347 }
5348
5349 234 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5350 MOVTrack *track, int moof_size,
5351 int first, int end)
5352 {
5353 234 int64_t pos = avio_tell(pb);
5354 234 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5355 int i;
5356
5357
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5358
2/2
✓ Branch 1 taken 618 times.
✓ Branch 2 taken 9426 times.
10044 if (get_cluster_duration(track, i) != track->default_duration)
5359 618 flags |= MOV_TRUN_SAMPLE_DURATION;
5360
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 9544 times.
10044 if (track->cluster[i].size != track->default_size)
5361 500 flags |= MOV_TRUN_SAMPLE_SIZE;
5362
4/4
✓ Branch 0 taken 9810 times.
✓ Branch 1 taken 234 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 9800 times.
10044 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5363 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5364 }
5365
3/4
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
234 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5366
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 116 times.
226 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5367 110 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5368
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 166 times.
234 if (track->flags & MOV_TRACK_CTTS)
5369 68 flags |= MOV_TRUN_SAMPLE_CTS;
5370
5371 234 avio_wb32(pb, 0); /* size placeholder */
5372 234 ffio_wfourcc(pb, "trun");
5373
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 180 times.
234 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5374 54 avio_w8(pb, 1); /* version */
5375 else
5376 180 avio_w8(pb, 0); /* version */
5377 234 avio_wb24(pb, flags);
5378
5379 234 avio_wb32(pb, end - first); /* sample count */
5380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5381 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5382 !mov->first_trun)
5383 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5384 else
5385 234 avio_wb32(pb, moof_size + 8 + track->data_offset +
5386 234 track->cluster[first].pos); /* data offset */
5387
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 124 times.
234 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5388 110 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5389
5390
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5391
2/2
✓ Branch 0 taken 722 times.
✓ Branch 1 taken 9322 times.
10044 if (flags & MOV_TRUN_SAMPLE_DURATION)
5392 722 avio_wb32(pb, get_cluster_duration(track, i));
5393
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 8980 times.
10044 if (flags & MOV_TRUN_SAMPLE_SIZE)
5394 1064 avio_wb32(pb, track->cluster[i].size);
5395
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 9672 times.
10044 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5396 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5397
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 8064 times.
10044 if (flags & MOV_TRUN_SAMPLE_CTS)
5398 1980 avio_wb32(pb, track->cluster[i].cts);
5399 }
5400
5401 234 mov->first_trun = 0;
5402 234 return update_size(pb, pos);
5403 }
5404
5405 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5406 {
5407 30 int64_t pos = avio_tell(pb);
5408 static const uint8_t uuid[] = {
5409 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5410 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5411 };
5412
5413 30 avio_wb32(pb, 0); /* size placeholder */
5414 30 ffio_wfourcc(pb, "uuid");
5415 30 avio_write(pb, uuid, AV_UUID_LEN);
5416 30 avio_w8(pb, 1);
5417 30 avio_wb24(pb, 0);
5418 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5419 30 avio_wb64(pb, track->end_pts -
5420 30 (track->cluster[0].dts + track->cluster[0].cts));
5421
5422 30 return update_size(pb, pos);
5423 }
5424
5425 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5426 MOVTrack *track, int entry)
5427 {
5428 int n = track->nb_frag_info - 1 - entry, i;
5429 int size = 8 + 16 + 4 + 1 + 16*n;
5430 static const uint8_t uuid[] = {
5431 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5432 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5433 };
5434
5435 if (entry < 0)
5436 return 0;
5437
5438 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5439 avio_wb32(pb, size);
5440 ffio_wfourcc(pb, "uuid");
5441 avio_write(pb, uuid, AV_UUID_LEN);
5442 avio_w8(pb, 1);
5443 avio_wb24(pb, 0);
5444 avio_w8(pb, n);
5445 for (i = 0; i < n; i++) {
5446 int index = entry + 1 + i;
5447 avio_wb64(pb, track->frag_info[index].time);
5448 avio_wb64(pb, track->frag_info[index].duration);
5449 }
5450 if (n < mov->ism_lookahead) {
5451 int free_size = 16 * (mov->ism_lookahead - n);
5452 avio_wb32(pb, free_size);
5453 ffio_wfourcc(pb, "free");
5454 ffio_fill(pb, 0, free_size - 8);
5455 }
5456
5457 return 0;
5458 }
5459
5460 117 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5461 MOVTrack *track)
5462 {
5463 117 int64_t pos = avio_tell(pb);
5464 int i;
5465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 for (i = 0; i < mov->ism_lookahead; i++) {
5466 /* Update the tfrf tag for the last ism_lookahead fragments,
5467 * nb_frag_info - 1 is the next fragment to be written. */
5468 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5469 }
5470 117 avio_seek(pb, pos, SEEK_SET);
5471 117 return 0;
5472 }
5473
5474 71 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5475 int size)
5476 {
5477 int i;
5478
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 71 times.
204 for (i = 0; i < mov->nb_tracks; i++) {
5479 133 MOVTrack *track = &mov->tracks[i];
5480 MOVFragmentInfo *info;
5481
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 117 times.
133 if ((tracks >= 0 && i != tracks) || !track->entry)
5482 16 continue;
5483 117 track->nb_frag_info++;
5484
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 54 times.
117 if (track->nb_frag_info >= track->frag_info_capacity) {
5485 63 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5486
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
63 if (av_reallocp_array(&track->frag_info,
5487 new_capacity,
5488 sizeof(*track->frag_info)))
5489 return AVERROR(ENOMEM);
5490 63 track->frag_info_capacity = new_capacity;
5491 }
5492 117 info = &track->frag_info[track->nb_frag_info - 1];
5493 117 info->offset = avio_tell(pb);
5494 117 info->size = size;
5495 // Try to recreate the original pts for the first packet
5496 // from the fields we have stored
5497 117 info->time = track->cluster[0].dts + track->cluster[0].cts;
5498 117 info->duration = track->end_pts -
5499 117 (track->cluster[0].dts + track->cluster[0].cts);
5500 // If the pts is less than zero, we will have trimmed
5501 // away parts of the media track using an edit list,
5502 // and the corresponding start presentation time is zero.
5503
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 109 times.
117 if (info->time < 0) {
5504 8 info->duration += info->time;
5505 8 info->time = 0;
5506 }
5507 117 info->tfrf_offset = 0;
5508 117 mov_write_tfrf_tags(pb, mov, track);
5509 }
5510 71 return 0;
5511 }
5512
5513 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5514 {
5515 int i;
5516 for (i = 0; i < mov->nb_tracks; i++) {
5517 MOVTrack *track = &mov->tracks[i];
5518 if ((tracks >= 0 && i != tracks) || !track->entry)
5519 continue;
5520 if (track->nb_frag_info > max) {
5521 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5522 track->nb_frag_info = max;
5523 }
5524 }
5525 }
5526
5527 204 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5528 {
5529 204 int64_t pos = avio_tell(pb);
5530
5531 204 avio_wb32(pb, 0); /* size */
5532 204 ffio_wfourcc(pb, "tfdt");
5533 204 avio_w8(pb, 1); /* version */
5534 204 avio_wb24(pb, 0);
5535 204 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5536 204 return update_size(pb, pos);
5537 }
5538
5539 234 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5540 MOVTrack *track, int64_t moof_offset,
5541 int moof_size)
5542 {
5543 234 int64_t pos = avio_tell(pb);
5544 234 int i, start = 0;
5545 234 avio_wb32(pb, 0); /* size placeholder */
5546 234 ffio_wfourcc(pb, "traf");
5547
5548 234 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5549
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (mov->mode != MODE_ISM)
5550 204 mov_write_tfdt_tag(pb, track);
5551
2/2
✓ Branch 0 taken 9810 times.
✓ Branch 1 taken 234 times.
10044 for (i = 1; i < track->entry; i++) {
5552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9810 times.
9810 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5553 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5554 start = i;
5555 }
5556 }
5557 234 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5558
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (mov->mode == MODE_ISM) {
5559 30 mov_write_tfxd_tag(pb, track);
5560
5561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5562 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5563
5564 if (track->nb_frag_info > 0) {
5565 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5566 if (!info->tfrf_offset)
5567 info->tfrf_offset = avio_tell(pb);
5568 }
5569 avio_wb32(pb, 8 + size);
5570 ffio_wfourcc(pb, "free");
5571 ffio_fill(pb, 0, size);
5572 }
5573 }
5574
5575
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
234 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5576 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5577
5578 234 return update_size(pb, pos);
5579 }
5580
5581 142 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5582 int tracks, int moof_size)
5583 {
5584 142 int64_t pos = avio_tell(pb);
5585 int i;
5586
5587 142 avio_wb32(pb, 0); /* size placeholder */
5588 142 ffio_wfourcc(pb, "moof");
5589 142 mov->first_trun = 1;
5590
5591 142 mov_write_mfhd_tag(pb, mov);
5592
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 142 times.
408 for (i = 0; i < mov->nb_tracks; i++) {
5593 266 MOVTrack *track = &mov->tracks[i];
5594
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 30 times.
266 if (tracks >= 0 && i != tracks)
5595 24 continue;
5596
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 234 times.
242 if (!track->entry)
5597 8 continue;
5598
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
234 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5599 mov_write_pssh_tag(pb, track->st);
5600 234 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5601 }
5602
5603 142 return update_size(pb, pos);
5604 }
5605
5606 70 static int mov_write_sidx_tag(AVIOContext *pb,
5607 MOVTrack *track, int ref_size, int total_sidx_size)
5608 {
5609 70 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5610 int64_t presentation_time, duration, offset;
5611 unsigned starts_with_SAP;
5612 int i, entries;
5613
5614
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (track->entry) {
5615 70 entries = 1;
5616 70 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5617 70 track->start_dts - track->start_cts;
5618 70 duration = track->end_pts -
5619 70 (track->cluster[0].dts + track->cluster[0].cts);
5620 70 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5621
5622 // pts<0 should be cut away using edts
5623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (presentation_time < 0) {
5624 duration += presentation_time;
5625 presentation_time = 0;
5626 }
5627 } else {
5628 entries = track->nb_frag_info;
5629 if (entries <= 0)
5630 return 0;
5631 presentation_time = track->frag_info[0].time;
5632 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5633 if (presentation_time > 0)
5634 presentation_time -= track->start_dts + track->start_cts;
5635 }
5636
5637 70 avio_wb32(pb, 0); /* size */
5638 70 ffio_wfourcc(pb, "sidx");
5639 70 avio_w8(pb, 1); /* version */
5640 70 avio_wb24(pb, 0);
5641 70 avio_wb32(pb, track->track_id); /* reference_ID */
5642 70 avio_wb32(pb, track->timescale); /* timescale */
5643 70 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5644 70 offset_pos = avio_tell(pb);
5645 70 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5646 70 avio_wb16(pb, 0); /* reserved */
5647
5648 70 avio_wb16(pb, entries); /* reference_count */
5649
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 70 times.
140 for (i = 0; i < entries; i++) {
5650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!track->entry) {
5651 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5652 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5653 }
5654 duration = track->frag_info[i].duration;
5655 ref_size = track->frag_info[i].size;
5656 starts_with_SAP = 1;
5657 }
5658 70 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5659 70 avio_wb32(pb, duration); /* subsegment_duration */
5660 70 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5661 }
5662
5663 70 end_pos = avio_tell(pb);
5664 70 offset = pos + total_sidx_size - end_pos;
5665 70 avio_seek(pb, offset_pos, SEEK_SET);
5666 70 avio_wb64(pb, offset);
5667 70 avio_seek(pb, end_pos, SEEK_SET);
5668 70 return update_size(pb, pos);
5669 }
5670
5671 20 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5672 int tracks, int ref_size)
5673 {
5674 int i, round, ret;
5675 AVIOContext *avio_buf;
5676 20 int total_size = 0;
5677
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (round = 0; round < 2; round++) {
5678 // First run one round to calculate the total size of all
5679 // sidx atoms.
5680 // This would be much simpler if we'd only write one sidx
5681 // atom, for the first track in the moof.
5682
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0) {
5683
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5684 return ret;
5685 } else {
5686 20 avio_buf = pb;
5687 }
5688
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
110 for (i = 0; i < mov->nb_tracks; i++) {
5689 70 MOVTrack *track = &mov->tracks[i];
5690
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 if (tracks >= 0 && i != tracks)
5691 continue;
5692 // When writing a sidx for the full file, entry is 0, but
5693 // we want to include all tracks. ref_size is 0 in this case,
5694 // since we read it from frag_info instead.
5695
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 if (!track->entry && ref_size > 0)
5696 continue;
5697 70 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5698 total_size);
5699 }
5700
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0)
5701 20 total_size = ffio_close_null_buf(avio_buf);
5702 }
5703 20 return 0;
5704 }
5705
5706 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5707 {
5708 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5709 MOVTrack *first_track;
5710 int flags = 24;
5711
5712 /* PRFT should be associated with at most one track. So, choosing only the
5713 * first track. */
5714 if (tracks > 0)
5715 return 0;
5716 first_track = &(mov->tracks[0]);
5717
5718 if (!first_track->entry) {
5719 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5720 return 0;
5721 }
5722
5723 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5724 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5725 return 0;
5726 }
5727
5728 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5729 if (first_track->cluster[0].prft.wallclock) {
5730 /* Round the NTP time to whole milliseconds. */
5731 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5732 NTP_OFFSET_US);
5733 flags = first_track->cluster[0].prft.flags;
5734 } else
5735 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5736 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5737 pts_us = av_rescale_q(first_track->cluster[0].pts,
5738 first_track->st->time_base, AV_TIME_BASE_Q);
5739 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5740 } else {
5741 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5742 mov->write_prft);
5743 return 0;
5744 }
5745
5746 avio_wb32(pb, 0); // Size place holder
5747 ffio_wfourcc(pb, "prft"); // Type
5748 avio_w8(pb, 1); // Version
5749 avio_wb24(pb, flags); // Flags
5750 avio_wb32(pb, first_track->track_id); // reference track ID
5751 avio_wb64(pb, ntp_ts); // NTP time stamp
5752 avio_wb64(pb, first_track->cluster[0].pts); //media time
5753 return update_size(pb, pos);
5754 }
5755
5756 71 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5757 int64_t mdat_size)
5758 {
5759 AVIOContext *avio_buf;
5760 int ret, moof_size;
5761
5762
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5763 return ret;
5764 71 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5765 71 moof_size = ffio_close_null_buf(avio_buf);
5766
5767
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 51 times.
71 if (mov->flags & FF_MOV_FLAG_DASH &&
5768
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5769 20 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5770
5771
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
71 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
5772 mov_write_prft_tag(pb, mov, tracks);
5773
5774
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5776 mov->ism_lookahead) {
5777
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
5778 return ret;
5779
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5781 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5782 }
5783 }
5784
5785 71 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5786 }
5787
5788 61 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5789 {
5790 61 int64_t pos = avio_tell(pb);
5791 int i;
5792
5793 61 avio_wb32(pb, 0); /* size placeholder */
5794 61 ffio_wfourcc(pb, "tfra");
5795 61 avio_w8(pb, 1); /* version */
5796 61 avio_wb24(pb, 0);
5797
5798 61 avio_wb32(pb, track->track_id);
5799 61 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5800 61 avio_wb32(pb, track->nb_frag_info);
5801
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 61 times.
175 for (i = 0; i < track->nb_frag_info; i++) {
5802 114 avio_wb64(pb, track->frag_info[i].time);
5803 114 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5804 114 avio_w8(pb, 1); /* traf number */
5805 114 avio_w8(pb, 1); /* trun number */
5806 114 avio_w8(pb, 1); /* sample number */
5807 }
5808
5809 61 return update_size(pb, pos);
5810 }
5811
5812 33 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5813 {
5814 AVIOContext *mfra_pb;
5815 int i, ret, sz;
5816 uint8_t *buf;
5817
5818 33 ret = avio_open_dyn_buf(&mfra_pb);
5819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret < 0)
5820 return ret;
5821
5822 33 avio_wb32(mfra_pb, 0); /* size placeholder */
5823 33 ffio_wfourcc(mfra_pb, "mfra");
5824 /* An empty mfra atom is enough to indicate to the publishing point that
5825 * the stream has ended. */
5826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_ISML)
5827 goto done_mfra;
5828
5829
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++) {
5830 63 MOVTrack *track = &mov->tracks[i];
5831
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (track->nb_frag_info)
5832 61 mov_write_tfra_tag(mfra_pb, track);
5833 }
5834
5835 33 avio_wb32(mfra_pb, 16);
5836 33 ffio_wfourcc(mfra_pb, "mfro");
5837 33 avio_wb32(mfra_pb, 0); /* version + flags */
5838 33 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5839
5840 33 done_mfra:
5841
5842 33 sz = update_size(mfra_pb, 0);
5843 33 ret = avio_get_dyn_buf(mfra_pb, &buf);
5844 33 avio_write(pb, buf, ret);
5845 33 ffio_free_dyn_buf(&mfra_pb);
5846
5847 33 return sz;
5848 }
5849
5850 175 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5851 {
5852 175 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5853
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5854
5855 175 mov->mdat_pos = avio_tell(pb);
5856 175 avio_wb32(pb, 0); /* size placeholder*/
5857 175 ffio_wfourcc(pb, "mdat");
5858 175 return 0;
5859 }
5860
5861 418 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5862 int has_h264, int has_video, int write_minor)
5863 {
5864 418 MOVMuxContext *mov = s->priv_data;
5865 418 int minor = 0x200;
5866
5867
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
418 if (mov->major_brand && strlen(mov->major_brand) >= 4)
5868 ffio_wfourcc(pb, mov->major_brand);
5869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 else if (mov->mode == MODE_3GP) {
5870 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5871 minor = has_h264 ? 0x100 : 0x200;
5872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode == MODE_AVIF) {
5873 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5874 minor = 0;
5875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode & MODE_3G2) {
5876 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5877 minor = has_h264 ? 0x20000 : 0x10000;
5878
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 416 times.
418 } else if (mov->mode == MODE_PSP)
5879 2 ffio_wfourcc(pb, "MSNV");
5880
4/4
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 302 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 56 times.
416 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
5881
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 52 times.
58 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5882 6 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5883
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 302 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 86 times.
410 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5884 22 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5885
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
388 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5886 ffio_wfourcc(pb, "iso4");
5887
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 302 times.
388 else if (mov->mode == MODE_MP4)
5888 86 ffio_wfourcc(pb, "isom");
5889
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 300 times.
302 else if (mov->mode == MODE_IPOD)
5890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5891
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 292 times.
300 else if (mov->mode == MODE_ISM)
5892 8 ffio_wfourcc(pb, "isml");
5893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 else if (mov->mode == MODE_F4V)
5894 ffio_wfourcc(pb, "f4v ");
5895 else
5896 292 ffio_wfourcc(pb, "qt ");
5897
5898
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 209 times.
418 if (write_minor)
5899 209 avio_wb32(pb, minor);
5900 418 }
5901
5902 209 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5903 {
5904 209 MOVMuxContext *mov = s->priv_data;
5905 209 int64_t pos = avio_tell(pb);
5906 209 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
5907 209 int has_iamf = 0;
5908
5909 #if CONFIG_IAMFENC
5910
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 for (int i = 0; i < s->nb_stream_groups; i++) {
5911 5 const AVStreamGroup *stg = s->stream_groups[i];
5912
5913
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5914 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5915 5 has_iamf = 1;
5916 5 break;
5917 }
5918 }
5919 #endif
5920
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
5921 267 AVStream *st = mov->tracks[i].st;
5922
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 265 times.
267 if (is_cover_image(st))
5923 2 continue;
5924
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 87 times.
265 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5925 178 has_video = 1;
5926
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 231 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
5927 34 has_h264 = 1;
5928
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 264 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
5929 1 has_av1 = 1;
5930
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 4 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
5931
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 1 times.
261 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
5932
2/4
✓ Branch 0 taken 260 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 260 times.
520 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
5933 260 av_packet_side_data_get(st->codecpar->coded_side_data,
5934 260 st->codecpar->nb_coded_side_data,
5935 AV_PKT_DATA_DOVI_CONF))
5936 5 has_dolby = 1;
5937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
5938 has_id3 = 1;
5939 }
5940
5941 209 avio_wb32(pb, 0); /* size */
5942 209 ffio_wfourcc(pb, "ftyp");
5943
5944 // Write major brand
5945 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
5946 // Write the major brand as the first compatible brand as well
5947 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
5948
5949 // Write compatible brands, ensuring that we don't write the major brand as a
5950 // compatible brand a second time.
5951
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM) {
5952 4 ffio_wfourcc(pb, "piff");
5953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 } else if (mov->mode == MODE_AVIF) {
5954 const AVPixFmtDescriptor *pix_fmt_desc =
5955 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
5956 const int depth = pix_fmt_desc->comp[0].depth;
5957 if (mov->is_animated_avif) {
5958 // For animated AVIF, major brand is "avis". Add "avif" as a
5959 // compatible brand.
5960 ffio_wfourcc(pb, "avif");
5961 ffio_wfourcc(pb, "msf1");
5962 ffio_wfourcc(pb, "iso8");
5963 }
5964 ffio_wfourcc(pb, "mif1");
5965 ffio_wfourcc(pb, "miaf");
5966 if (depth == 8 || depth == 10) {
5967 // MA1B and MA1A brands are based on AV1 profile. Short hand for
5968 // computing that is based on chroma subsampling type. 420 chroma
5969 // subsampling is MA1B. 444 chroma subsampling is MA1A.
5970 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
5971 // 444 chroma subsampling.
5972 ffio_wfourcc(pb, "MA1A");
5973 } else {
5974 // 420 chroma subsampling.
5975 ffio_wfourcc(pb, "MA1B");
5976 }
5977 }
5978
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 146 times.
205 } else if (mov->mode != MODE_MOV) {
5979 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
5980 // brand, if not already the major brand. This is compatible with users that
5981 // don't understand tfdt.
5982
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 2 times.
59 if (mov->mode == MODE_MP4) {
5983
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (mov->flags & FF_MOV_FLAG_CMAF)
5984 1 ffio_wfourcc(pb, "cmfc");
5985
4/4
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 3 times.
57 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
5986 26 ffio_wfourcc(pb, "iso6");
5987
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (has_av1)
5988 1 ffio_wfourcc(pb, "av01");
5989
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (has_dolby)
5990 3 ffio_wfourcc(pb, "dby1");
5991
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 52 times.
57 if (has_iamf)
5992 5 ffio_wfourcc(pb, "iamf");
5993 } else {
5994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5995 ffio_wfourcc(pb, "iso6");
5996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5997 ffio_wfourcc(pb, "iso5");
5998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5999 ffio_wfourcc(pb, "iso4");
6000 }
6001 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6002
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 12 times.
59 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6003 // write isom for mp4 only if it it's not the major brand already.
6004
4/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 43 times.
47 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6005 4 ffio_wfourcc(pb, "isom");
6006 47 ffio_wfourcc(pb, "iso2");
6007
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 27 times.
47 if (has_h264)
6008 20 ffio_wfourcc(pb, "avc1");
6009 }
6010 }
6011
6012
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 152 times.
209 if (mov->mode == MODE_MP4)
6013 57 ffio_wfourcc(pb, "mp41");
6014
6015
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
209 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6016 ffio_wfourcc(pb, "dash");
6017
6018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (has_id3)
6019 ffio_wfourcc(pb, "aid3");
6020
6021 209 return update_size(pb, pos);
6022 }
6023
6024 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6025 {
6026 1 AVStream *video_st = s->streams[0];
6027 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6028 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6029 1 int audio_rate = audio_par->sample_rate;
6030 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6031
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 :
6032 0;
6033 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6034 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6035
6036
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) {
6037 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6038 return AVERROR(EINVAL);
6039 }
6040
6041 1 avio_wb32(pb, 0x94); /* size */
6042 1 ffio_wfourcc(pb, "uuid");
6043 1 ffio_wfourcc(pb, "PROF");
6044
6045 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6046 1 avio_wb32(pb, 0xbb88695c);
6047 1 avio_wb32(pb, 0xfac9c740);
6048
6049 1 avio_wb32(pb, 0x0); /* ? */
6050 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6051
6052 1 avio_wb32(pb, 0x14); /* size */
6053 1 ffio_wfourcc(pb, "FPRF");
6054 1 avio_wb32(pb, 0x0); /* ? */
6055 1 avio_wb32(pb, 0x0); /* ? */
6056 1 avio_wb32(pb, 0x0); /* ? */
6057
6058 1 avio_wb32(pb, 0x2c); /* size */
6059 1 ffio_wfourcc(pb, "APRF"); /* audio */
6060 1 avio_wb32(pb, 0x0);
6061 1 avio_wb32(pb, 0x2); /* TrackID */
6062 1 ffio_wfourcc(pb, "mp4a");
6063 1 avio_wb32(pb, 0x20f);
6064 1 avio_wb32(pb, 0x0);
6065 1 avio_wb32(pb, audio_kbitrate);
6066 1 avio_wb32(pb, audio_kbitrate);
6067 1 avio_wb32(pb, audio_rate);
6068 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6069
6070 1 avio_wb32(pb, 0x34); /* size */
6071 1 ffio_wfourcc(pb, "VPRF"); /* video */
6072 1 avio_wb32(pb, 0x0);
6073 1 avio_wb32(pb, 0x1); /* TrackID */
6074
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6075 1 ffio_wfourcc(pb, "avc1");
6076 1 avio_wb16(pb, 0x014D);
6077 1 avio_wb16(pb, 0x0015);
6078 } else {
6079 ffio_wfourcc(pb, "mp4v");
6080 avio_wb16(pb, 0x0000);
6081 avio_wb16(pb, 0x0103);
6082 }
6083 1 avio_wb32(pb, 0x0);
6084 1 avio_wb32(pb, video_kbitrate);
6085 1 avio_wb32(pb, video_kbitrate);
6086 1 avio_wb32(pb, frame_rate);
6087 1 avio_wb32(pb, frame_rate);
6088 1 avio_wb16(pb, video_par->width);
6089 1 avio_wb16(pb, video_par->height);
6090 1 avio_wb32(pb, 0x010001); /* ? */
6091
6092 1 return 0;
6093 }
6094
6095 209 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6096 {
6097 209 MOVMuxContext *mov = s->priv_data;
6098 int i;
6099
6100 209 mov_write_ftyp_tag(pb,s);
6101
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->mode == MODE_PSP) {
6102 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6103
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6104 2 AVStream *st = mov->tracks[i].st;
6105
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6106 continue;
6107
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6108 1 video_streams_nb++;
6109
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6110 1 audio_streams_nb++;
6111 else
6112 other_streams_nb++;
6113 }
6114
6115
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) {
6116 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6117 return AVERROR(EINVAL);
6118 }
6119 1 return mov_write_uuidprof_tag(pb, s);
6120 }
6121 208 return 0;
6122 }
6123
6124 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6125 {
6126 8 uint32_t c = -1;
6127 8 int i, closed_gop = 0;
6128
6129
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6130 368 c = (c << 8) + pkt->data[i];
6131
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6132 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6133
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6134 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6135
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
6136 8 *flags = MOV_SYNC_SAMPLE;
6137 else
6138 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6139 8 break;
6140 }
6141 }
6142 8 return 0;
6143 }
6144
6145 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6146 {
6147 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6148 int seq = 0, entry = 0;
6149 int key = pkt->flags & AV_PKT_FLAG_KEY;
6150 start = find_next_marker(pkt->data, end);
6151 for (next = start; next < end; start = next) {
6152 next = find_next_marker(start + 4, end);
6153 switch (AV_RB32(start)) {
6154 case VC1_CODE_SEQHDR:
6155 seq = 1;
6156 break;
6157 case VC1_CODE_ENTRYPOINT:
6158 entry = 1;
6159 break;
6160 case VC1_CODE_SLICE:
6161 trk->vc1_info.slices = 1;
6162 break;
6163 }
6164 }
6165 if (!trk->entry && trk->vc1_info.first_packet_seen)
6166 trk->vc1_info.first_frag_written = 1;
6167 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6168 /* First packet in first fragment */
6169 trk->vc1_info.first_packet_seq = seq;
6170 trk->vc1_info.first_packet_entry = entry;
6171 trk->vc1_info.first_packet_seen = 1;
6172 } else if ((seq && !trk->vc1_info.packet_seq) ||
6173 (entry && !trk->vc1_info.packet_entry)) {
6174 int i;
6175 for (i = 0; i < trk->entry; i++)
6176 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6177 trk->has_keyframes = 0;
6178 if (seq)
6179 trk->vc1_info.packet_seq = 1;
6180 if (entry)
6181 trk->vc1_info.packet_entry = 1;
6182 if (!trk->vc1_info.first_frag_written) {
6183 /* First fragment */
6184 if ((!seq || trk->vc1_info.first_packet_seq) &&
6185 (!entry || trk->vc1_info.first_packet_entry)) {
6186 /* First packet had the same headers as this one, readd the
6187 * sync sample flag. */
6188 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6189 trk->has_keyframes = 1;
6190 }
6191 }
6192 }
6193 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6194 key = seq && entry;
6195 else if (trk->vc1_info.packet_seq)
6196 key = seq;
6197 else if (trk->vc1_info.packet_entry)
6198 key = entry;
6199 if (key) {
6200 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6201 trk->has_keyframes++;
6202 }
6203 }
6204
6205 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6206 {
6207 int length;
6208
6209 if (pkt->size < 8)
6210 return;
6211
6212 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6213 if (length < 8 || length > pkt->size)
6214 return;
6215
6216 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6217 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6218 trk->has_keyframes++;
6219 }
6220
6221 return;
6222 }
6223
6224 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6225 {
6226 MOVMuxContext *mov = s->priv_data;
6227 int ret, buf_size;
6228 uint8_t *buf;
6229 int i, offset;
6230
6231 if (!track->mdat_buf)
6232 return 0;
6233 if (!mov->mdat_buf) {
6234 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6235 return ret;
6236 }
6237 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6238
6239 offset = avio_tell(mov->mdat_buf);
6240 avio_write(mov->mdat_buf, buf, buf_size);
6241 ffio_free_dyn_buf(&track->mdat_buf);
6242
6243 for (i = track->entries_flushed; i < track->entry; i++)
6244 track->cluster[i].pos += offset;
6245 track->entries_flushed = track->entry;
6246 return 0;
6247 }
6248
6249 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6250 {
6251 2 MOVMuxContext *mov = s->priv_data;
6252 2 AVPacket *squashed_packet = mov->pkt;
6253 2 int ret = AVERROR_BUG;
6254
6255
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
6256 2 case AV_CODEC_ID_TTML: {
6257 2 int had_packets = !!track->squashed_packet_queue.head;
6258
6259
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_generate_squashed_ttml_packet(s, track, squashed_packet)) < 0) {
6260 goto finish_squash;
6261 }
6262
6263 // We have generated a padding packet (no actual input packets in
6264 // queue) and its duration is zero. Skipping writing it.
6265
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (!had_packets && squashed_packet->duration == 0) {
6266 goto finish_squash;
6267 }
6268
6269 2 track->end_reliable = 1;
6270 2 break;
6271 }
6272 default:
6273 ret = AVERROR(EINVAL);
6274 goto finish_squash;
6275 }
6276
6277 2 squashed_packet->stream_index = track->st->index;
6278
6279 2 ret = mov_write_single_packet(s, squashed_packet);
6280
6281 2 finish_squash:
6282 2 av_packet_unref(squashed_packet);
6283
6284 2 return ret;
6285 }
6286
6287 315 static int mov_write_squashed_packets(AVFormatContext *s)
6288 {
6289 315 MOVMuxContext *mov = s->priv_data;
6290
6291
2/2
✓ Branch 0 taken 459 times.
✓ Branch 1 taken 315 times.
774 for (int i = 0; i < mov->nb_streams; i++) {
6292 459 MOVTrack *track = &mov->tracks[i];
6293 459 int ret = AVERROR_BUG;
6294
6295
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 457 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
459 if (track->squash_fragment_samples_to_one && !track->entry) {
6296
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6297 av_log(s, AV_LOG_ERROR,
6298 "Failed to write squashed packet for %s stream with "
6299 "index %d and track id %d. Error: %s\n",
6300 avcodec_get_name(track->st->codecpar->codec_id),
6301 track->st->index, track->track_id,
6302 av_err2str(ret));
6303 return ret;
6304 }
6305 }
6306 }
6307
6308 315 return 0;
6309 }
6310
6311 129 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6312 int64_t ref_pos)
6313 {
6314 int i;
6315
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 125 times.
129 if (!track->entry)
6316 4 return 0;
6317
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 120 times.
125 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6318
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5 times.
41 for (i = 0; i < track->entry; i++)
6319 36 track->cluster[i].pos += ref_pos + track->data_offset;
6320
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
5 if (track->cluster_written == 0 && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) {
6321 // First flush. If this was a case of not using empty moov, reset chunking.
6322
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < track->entry; i++) {
6323 18 track->cluster[i].chunkNum = 0;
6324 18 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6325 }
6326 }
6327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (av_reallocp_array(&track->cluster_written,
6328 5 track->entry_written + track->entry,
6329 sizeof(*track->cluster)))
6330 return AVERROR(ENOMEM);
6331 5 memcpy(&track->cluster_written[track->entry_written],
6332 5 track->cluster, track->entry * sizeof(*track->cluster));
6333 5 track->entry_written += track->entry;
6334 }
6335 125 track->entry = 0;
6336 125 track->entries_flushed = 0;
6337 125 track->end_reliable = 0;
6338 125 return 0;
6339 }
6340
6341 106 static int mov_flush_fragment(AVFormatContext *s, int force)
6342 {
6343 106 MOVMuxContext *mov = s->priv_data;
6344 106 int i, first_track = -1;
6345 106 int64_t mdat_size = 0, mdat_start = 0;
6346 int ret;
6347 106 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6348
6349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6350 return 0;
6351
6352 // Check if we have any tracks that require squashing.
6353 // In that case, we'll have to write the packet here.
6354
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 106 times.
106 if ((ret = mov_write_squashed_packets(s)) < 0)
6355 return ret;
6356
6357 // Try to fill in the duration of the last packet in each stream
6358 // from queued packets in the interleave queues. If the flushing
6359 // of fragments was triggered automatically by an AVPacket, we
6360 // already have reliable info for the end of that track, but other
6361 // tracks may need to be filled in.
6362
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 106 times.
298 for (i = 0; i < mov->nb_streams; i++) {
6363 192 MOVTrack *track = &mov->tracks[i];
6364
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 38 times.
192 if (!track->end_reliable) {
6365 154 const AVPacket *pkt = ff_interleaved_peek(s, i);
6366
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 148 times.
154 if (pkt) {
6367 int64_t offset, dts, pts;
6368 6 ff_get_muxer_ts_offset(s, i, &offset);
6369 6 pts = pkt->pts + offset;
6370 6 dts = pkt->dts + offset;
6371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6372 dts += track->dts_shift;
6373 6 track->track_duration = dts - track->start_dts;
6374
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6375 6 track->end_pts = pts;
6376 else
6377 track->end_pts = dts;
6378 }
6379 }
6380 }
6381
6382
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 106 times.
304 for (i = 0; i < mov->nb_tracks; i++) {
6383 198 MOVTrack *track = &mov->tracks[i];
6384
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 153 times.
198 if (track->entry <= 1)
6385 45 continue;
6386 // Sample durations are calculated as the diff of dts values,
6387 // but for the last sample in a fragment, we don't know the dts
6388 // of the first sample in the next fragment, so we have to rely
6389 // on what was set as duration in the AVPacket. Not all callers
6390 // set this though, so we might want to replace it with an
6391 // estimate if it currently is zero.
6392
2/2
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 2 times.
153 if (get_cluster_duration(track, track->entry - 1) != 0)
6393 151 continue;
6394 // Use the duration (i.e. dts diff) of the second last sample for
6395 // the last one. This is a wild guess (and fatal if it turns out
6396 // to be too long), but probably the best we can do - having a zero
6397 // duration is bad as well.
6398 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6399 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6400
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6401 2 av_log(s, AV_LOG_WARNING,
6402 "Estimating the duration of the last packet in a "
6403 "fragment, consider setting the duration field in "
6404 "AVPacket instead.\n");
6405 2 mov->missing_duration_warned = 1;
6406 }
6407 }
6408
6409
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 83 times.
106 if (!mov->moov_written) {
6410 23 int64_t pos = avio_tell(s->pb);
6411 uint8_t *buf;
6412 int buf_size, moov_size;
6413
6414
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 19 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6415
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 41 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
45 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6416 4 break;
6417 /* Don't write the initial moov unless all tracks have data */
6418
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
23 if (i < mov->nb_tracks && !force)
6419 2 return 0;
6420
6421 21 moov_size = get_moov_size(s);
6422
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 21 times.
62 for (i = 0; i < mov->nb_tracks; i++)
6423 41 mov->tracks[i].data_offset = pos + moov_size + 8;
6424
6425 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6426
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6427 17 mov_write_identification(s->pb, s);
6428
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6429 return ret;
6430
6431
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6433 mov->reserved_header_pos = avio_tell(s->pb);
6434 17 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6435 17 mov->moov_written = 1;
6436 17 return 0;
6437 }
6438
6439 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6440 4 avio_wb32(s->pb, buf_size + 8);
6441 4 ffio_wfourcc(s->pb, "mdat");
6442 4 avio_write(s->pb, buf, buf_size);
6443 4 ffio_free_dyn_buf(&mov->mdat_buf);
6444
6445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6446 mov->reserved_header_pos = avio_tell(s->pb);
6447
6448 4 mov->moov_written = 1;
6449 4 mov->mdat_size = 0;
6450
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6451 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6452 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6453 4 return 0;
6454 }
6455
6456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (mov->frag_interleave) {
6457 for (i = 0; i < mov->nb_tracks; i++) {
6458 MOVTrack *track = &mov->tracks[i];
6459 int ret;
6460 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6461 return ret;
6462 }
6463
6464 if (!mov->mdat_buf)
6465 return 0;
6466 mdat_size = avio_tell(mov->mdat_buf);
6467 }
6468
6469
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 83 times.
236 for (i = 0; i < mov->nb_tracks; i++) {
6470 153 MOVTrack *track = &mov->tracks[i];
6471
3/4
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 134 times.
153 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6472 19 track->data_offset = 0;
6473 else
6474 134 track->data_offset = mdat_size;
6475
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 80 times.
153 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6476 73 has_video = 1;
6477
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (first_video_track) {
6478
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 12 times.
73 if (track->entry)
6479 61 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6480 73 first_video_track = 0;
6481 }
6482 }
6483
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 117 times.
153 if (!track->entry)
6484 36 continue;
6485
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (track->mdat_buf)
6486 117 mdat_size += avio_tell(track->mdat_buf);
6487
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 50 times.
117 if (first_track < 0)
6488 67 first_track = i;
6489 }
6490
6491
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 67 times.
83 if (!mdat_size)
6492 16 return 0;
6493
6494
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 3 times.
67 avio_write_marker(s->pb,
6495 67 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6496
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 6 times.
67 (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);
6497
6498
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 67 times.
192 for (i = 0; i < mov->nb_tracks; i++) {
6499 125 MOVTrack *track = &mov->tracks[i];
6500 125 int buf_size, write_moof = 1, moof_tracks = -1;
6501 uint8_t *buf;
6502
6503
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 106 times.
125 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6504
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
19 if (!track->entry)
6505 8 continue;
6506 15 mdat_size = avio_tell(track->mdat_buf);
6507 15 moof_tracks = i;
6508 } else {
6509 106 write_moof = i == first_track;
6510 }
6511
6512
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 50 times.
121 if (write_moof) {
6513 71 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6514
6515 71 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6516 71 mov->fragments++;
6517
6518 71 avio_wb32(s->pb, mdat_size + 8);
6519 71 ffio_wfourcc(s->pb, "mdat");
6520 71 mdat_start = avio_tell(s->pb);
6521 }
6522
6523 121 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6524
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 if (!mov->frag_interleave) {
6525
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 117 times.
121 if (!track->mdat_buf)
6526 4 continue;
6527 117 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6528 117 track->mdat_buf = NULL;
6529 } else {
6530 if (!mov->mdat_buf)
6531 continue;
6532 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6533 mov->mdat_buf = NULL;
6534 }
6535
6536 117 avio_write(s->pb, buf, buf_size);
6537 117 av_free(buf);
6538 }
6539
6540 67 mov->mdat_size = 0;
6541
6542 67 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6543 67 return 0;
6544 }
6545
6546 61 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6547 {
6548 61 MOVMuxContext *mov = s->priv_data;
6549 61 int had_moov = mov->moov_written;
6550 61 int ret = mov_flush_fragment(s, force);
6551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (ret < 0)
6552 return ret;
6553 // If using delay_moov, the first flush only wrote the moov,
6554 // not the actual moof+mdat pair, thus flush once again.
6555
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4 times.
61 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6556 9 ret = mov_flush_fragment(s, force);
6557 61 return ret;
6558 }
6559
6560 36163 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6561 {
6562 int64_t ref;
6563 uint64_t duration;
6564
6565
2/2
✓ Branch 0 taken 35525 times.
✓ Branch 1 taken 638 times.
36163 if (trk->entry) {
6566 35525 ref = trk->cluster[trk->entry - 1].dts;
6567
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 524 times.
638 } else if ( trk->start_dts != AV_NOPTS_VALUE
6568
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 8 times.
114 && !trk->frag_discont) {
6569 106 ref = trk->start_dts + trk->track_duration;
6570 } else
6571 532 ref = pkt->dts; // Skip tests for the first packet
6572
6573
2/2
✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 34508 times.
36163 if (trk->dts_shift != AV_NOPTS_VALUE) {
6574 /* With negative CTS offsets we have set an offset to the DTS,
6575 * reverse this for the check. */
6576 1655 ref -= trk->dts_shift;
6577 }
6578
6579 36163 duration = pkt->dts - ref;
6580
2/4
✓ Branch 0 taken 36163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36163 times.
36163 if (pkt->dts < ref || duration >= INT_MAX) {
6581 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6582 duration, pkt->dts, pkt->stream_index);
6583
6584 pkt->dts = ref + 1;
6585 pkt->pts = AV_NOPTS_VALUE;
6586 }
6587
6588
2/4
✓ Branch 0 taken 36163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36163 times.
36163 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6589 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6590 return AVERROR(EINVAL);
6591 }
6592 36163 return 0;
6593 }
6594
6595 18100 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6596 {
6597 18100 MOVMuxContext *mov = s->priv_data;
6598 18100 AVIOContext *pb = s->pb;
6599 MOVTrack *trk;
6600 AVCodecParameters *par;
6601 AVProducerReferenceTime *prft;
6602 18100 unsigned int samples_in_chunk = 0;
6603 18100 int size = pkt->size, ret = 0, offset = 0;
6604 size_t prft_size;
6605 18100 uint8_t *reformatted_data = NULL;
6606
6607
2/2
✓ Branch 0 taken 18054 times.
✓ Branch 1 taken 46 times.
18100 if (pkt->stream_index < s->nb_streams)
6608 18054 trk = s->streams[pkt->stream_index]->priv_data;
6609 else // Timecode or chapter
6610 46 trk = &mov->tracks[pkt->stream_index];
6611 18100 par = trk->par;
6612
6613 18100 ret = check_pkt(s, trk, pkt);
6614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (ret < 0)
6615 return ret;
6616
6617
2/2
✓ Branch 0 taken 17498 times.
✓ Branch 1 taken 602 times.
18100 if (pkt->pts != AV_NOPTS_VALUE &&
6618
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17498 times.
17498 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
6619 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6620 return AVERROR_PATCHWELCOME;
6621 }
6622
6623
3/4
✓ Branch 0 taken 12840 times.
✓ Branch 1 taken 5260 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12840 times.
18100 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6624 int ret;
6625
4/4
✓ Branch 0 taken 2130 times.
✓ Branch 1 taken 3130 times.
✓ Branch 2 taken 1892 times.
✓ Branch 3 taken 238 times.
5260 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
6626
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5022 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5022 if (mov->frag_interleave && mov->fragments > 0) {
6627 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6628 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6629 return ret;
6630 }
6631 }
6632
6633
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 4905 times.
5022 if (!trk->mdat_buf) {
6634
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
117 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6635 return ret;
6636 }
6637 5022 pb = trk->mdat_buf;
6638 } else {
6639
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6640
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6641 return ret;
6642 }
6643 238 pb = mov->mdat_buf;
6644 }
6645 }
6646
6647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6648 /* We must find out how many AMR blocks there are in one packet */
6649 static const uint16_t packed_size[16] =
6650 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6651 int len = 0;
6652
6653 while (len < size && samples_in_chunk < 100) {
6654 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6655 samples_in_chunk++;
6656 }
6657 if (samples_in_chunk > 1) {
6658 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6659 return -1;
6660 }
6661
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6663 samples_in_chunk = trk->par->frame_size;
6664
2/2
✓ Branch 0 taken 1297 times.
✓ Branch 1 taken 16803 times.
18100 } else if (trk->sample_size)
6665 1297 samples_in_chunk = size / trk->sample_size;
6666 else
6667 16803 samples_in_chunk = 1;
6668
6669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (samples_in_chunk < 1) {
6670 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6671 return AVERROR_PATCHWELCOME;
6672 }
6673
6674 /* copy extradata if it exists */
6675
4/4
✓ Branch 0 taken 5375 times.
✓ Branch 1 taken 12725 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5373 times.
18100 if (trk->vos_len == 0 && par->extradata_size > 0 &&
6676
14/28
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 2 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 2 times.
✗ Branch 27 not taken.
2 !TAG_IS_AVCI(trk->tag) &&
6677
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6678 2 trk->vos_len = par->extradata_size;
6679 2 trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
6680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->vos_data) {
6681 ret = AVERROR(ENOMEM);
6682 goto err;
6683 }
6684 2 memcpy(trk->vos_data, par->extradata, trk->vos_len);
6685 2 memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6686 }
6687
6688
2/2
✓ Branch 0 taken 17985 times.
✓ Branch 1 taken 115 times.
18100 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6689
2/2
✓ Branch 0 taken 15397 times.
✓ Branch 1 taken 2588 times.
17985 par->codec_id == AV_CODEC_ID_H264 ||
6690
2/2
✓ Branch 0 taken 15242 times.
✓ Branch 1 taken 155 times.
15397 par->codec_id == AV_CODEC_ID_HEVC ||
6691
2/2
✓ Branch 0 taken 15232 times.
✓ Branch 1 taken 10 times.
15242 par->codec_id == AV_CODEC_ID_VVC ||
6692
1/2
✓ Branch 0 taken 15232 times.
✗ Branch 1 not taken.
15232 par->codec_id == AV_CODEC_ID_VP9 ||
6693
2/2
✓ Branch 0 taken 14932 times.
✓ Branch 1 taken 300 times.
15232 par->codec_id == AV_CODEC_ID_EVC ||
6694
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14932 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3144 times.
18100 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->vos_len &&
6695
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)) {
6696 /* copy frame to create needed atoms */
6697 24 trk->vos_len = size;
6698 24 trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->vos_data) {
6700 ret = AVERROR(ENOMEM);
6701 goto err;
6702 }
6703 24 memcpy(trk->vos_data, pkt->data, size);
6704 24 memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6705 }
6706
6707
3/4
✓ Branch 0 taken 5540 times.
✓ Branch 1 taken 12560 times.
✓ Branch 2 taken 5540 times.
✗ Branch 3 not taken.
18100 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5540 times.
5540 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6709 if (!trk->st->nb_frames) {
6710 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6711 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6712 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6713 return -1;
6714 }
6715 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6716 }
6717
19/34
✓ Branch 0 taken 2588 times.
✓ Branch 1 taken 15512 times.
✓ Branch 2 taken 2588 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 498 times.
✓ Branch 5 taken 2090 times.
✓ Branch 6 taken 498 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 498 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 498 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 498 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 498 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 498 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 498 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 498 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 498 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 498 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 498 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 498 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 498 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 498 times.
✗ Branch 33 not taken.
18100 if (par->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1 && !TAG_IS_AVCI(trk->tag)) {
6718 /* from x264 or from bytestream H.264 */
6719 /* NAL reformatting needed */
6720
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6721 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6722 &size);
6723 if (ret < 0)
6724 return ret;
6725 avio_write(pb, reformatted_data, size);
6726 } else {
6727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6728 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6729 if (size < 0) {
6730 ret = size;
6731 goto err;
6732 }
6733 } else {
6734 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6735 }
6736 }
6737
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 17447 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
17602 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 &&
6738
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
299 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6739 /* extradata is Annex B, assume the bitstream is too and convert it */
6740 144 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6741
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
144 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6742 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6743 &size, filter_ps, NULL);
6744 if (ret < 0)
6745 return ret;
6746 avio_write(pb, reformatted_data, size);
6747 } else {
6748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6749 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6750 if (size < 0) {
6751 ret = size;
6752 goto err;
6753 }
6754 } else {
6755 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6756 }
6757 }
6758
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 17448 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
17458 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->vos_len > 6 &&
6759
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6760 /* extradata is Annex B, assume the bitstream is too and convert it */
6761
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) {
6762 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6763 &size, 0, NULL);
6764 if (ret < 0)
6765 return ret;
6766 avio_write(pb, reformatted_data, size);
6767 } else {
6768 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6769 }
6770
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17444 times.
17448 } else if (par->codec_id == AV_CODEC_ID_AV1) {
6771
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) {
6772 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6773 &size, &offset);
6774 if (ret < 0)
6775 return ret;
6776 avio_write(pb, reformatted_data, size);
6777 } else {
6778 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6779
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]) {
6780 mov->avif_extent_length[pkt->stream_index] = size;
6781 }
6782 }
6783
6784
2/2
✓ Branch 0 taken 17057 times.
✓ Branch 1 taken 387 times.
17444 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6785
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 16405 times.
17057 par->codec_id == AV_CODEC_ID_EAC3) {
6786 1039 size = handle_eac3(mov, pkt, trk);
6787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6788 return size;
6789
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6790 1 goto end;
6791 1038 avio_write(pb, pkt->data, size);
6792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6793 size = 8;
6794
6795 for (int i = 0; i < pkt->size; i += 3) {
6796 if (pkt->data[i] == 0xFC) {
6797 size += 2;
6798 }
6799 }
6800 avio_wb32(pb, size);
6801 ffio_wfourcc(pb, "cdat");
6802 for (int i = 0; i < pkt->size; i += 3) {
6803 if (pkt->data[i] == 0xFC) {
6804 avio_w8(pb, pkt->data[i + 1]);
6805 avio_w8(pb, pkt->data[i + 2]);
6806 }
6807 }
6808 } else {
6809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 if (trk->cenc.aes_ctr) {
6810 if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) {
6811 int nal_size_length = (par->extradata[4] & 0x3) + 1;
6812 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6813 } else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) {
6814 int nal_size_length = (par->extradata[21] & 0x3) + 1;
6815 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6816 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6817 ret = AVERROR_PATCHWELCOME;
6818 } else {
6819 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6820 }
6821
6822 if (ret) {
6823 goto err;
6824 }
6825 } else {
6826 16405 avio_write(pb, pkt->data, size);
6827 }
6828 }
6829
6830
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 17826 times.
18099 if (trk->entry >= trk->cluster_capacity) {
6831 273 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6832 273 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
273 if (!cluster) {
6834 ret = AVERROR(ENOMEM);
6835 goto err;
6836 }
6837 273 trk->cluster = cluster;
6838 273 trk->cluster_capacity = new_capacity;
6839 }
6840
6841 18099 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6842 18099 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6843 18099 trk->cluster[trk->entry].chunkNum = 0;
6844 18099 trk->cluster[trk->entry].size = size;
6845 18099 trk->cluster[trk->entry].entries = samples_in_chunk;
6846 18099 trk->cluster[trk->entry].dts = pkt->dts;
6847 18099 trk->cluster[trk->entry].pts = pkt->pts;
6848
2/2
✓ Branch 0 taken 18097 times.
✓ Branch 1 taken 2 times.
18099 if (!trk->squash_fragment_samples_to_one &&
6849
4/4
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 17765 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 257 times.
18097 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
6850
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
75 if (!trk->frag_discont) {
6851 /* First packet of a new fragment. We already wrote the duration
6852 * of the last packet of the previous fragment based on track_duration,
6853 * which might not exactly match our dts. Therefore adjust the dts
6854 * of this packet to be what the previous packets duration implies. */
6855 71 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6856 /* We also may have written the pts and the corresponding duration
6857 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6858 * the next fragment. This means the cts of the first sample must
6859 * be the same in all fragments, unless end_pts was updated by
6860 * the packet causing the fragment to be written. */
6861
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 57 times.
71 if ((mov->flags & FF_MOV_FLAG_DASH &&
6862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6863
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 47 times.
57 mov->mode == MODE_ISM)
6864 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6865 } else {
6866 /* New fragment, but discontinuous from previous fragments.
6867 * Pretend the duration sum of the earlier fragments is
6868 * pkt->dts - trk->start_dts. */
6869 4 trk->end_pts = AV_NOPTS_VALUE;
6870 4 trk->frag_discont = 0;
6871 }
6872 }
6873
6874
6/6
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 17765 times.
✓ Branch 2 taken 259 times.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 229 times.
18099 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
6875
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 11 times.
30 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
6876 /* Not using edit lists and shifting the first track to start from zero.
6877 * If the other streams start from a later timestamp, we won't be able
6878 * to signal the difference in starting time without an edit list.
6879 * Thus move the timestamp for this first sample to 0, increasing
6880 * its duration instead. */
6881 19 trk->cluster[trk->entry].dts = trk->start_dts = 0;
6882 }
6883
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 17859 times.
18099 if (trk->start_dts == AV_NOPTS_VALUE) {
6884 240 trk->start_dts = pkt->dts;
6885
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 234 times.
240 if (trk->frag_discont) {
6886
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
6887 /* Pretend the whole stream started at pts=0, with earlier fragments
6888 * already written. If the stream started at pts=0, the duration sum
6889 * of earlier fragments would have been pkt->pts. */
6890 4 trk->start_dts = pkt->dts - pkt->pts;
6891 } else {
6892 /* Pretend the whole stream started at dts=0, with earlier fragments
6893 * already written, with a duration summing up to pkt->dts. */
6894 2 trk->start_dts = 0;
6895 }
6896 6 trk->frag_discont = 0;
6897
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 31 times.
234 } else if (pkt->dts && mov->moov_written)
6898 2 av_log(s, AV_LOG_WARNING,
6899 "Track %d starts with a nonzero dts %"PRId64", while the moov "
6900 "already has been written. Set the delay_moov flag to handle "
6901 "this case.\n",
6902 pkt->stream_index, pkt->dts);
6903 }
6904 18099 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
6905 18099 trk->last_sample_is_subtitle_end = 0;
6906
6907
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 17497 times.
18099 if (pkt->pts == AV_NOPTS_VALUE) {
6908 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
6909 602 pkt->pts = pkt->dts;
6910 }
6911
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 17081 times.
18099 if (pkt->dts != pkt->pts)
6912 1018 trk->flags |= MOV_TRACK_CTTS;
6913 18099 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
6914 18099 trk->cluster[trk->entry].flags = 0;
6915
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 17840 times.
18099 if (trk->start_cts == AV_NOPTS_VALUE)
6916 259 trk->start_cts = pkt->pts - pkt->dts;
6917
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 17836 times.
18099 if (trk->end_pts == AV_NOPTS_VALUE)
6918 263 trk->end_pts = trk->cluster[trk->entry].dts +
6919 263 trk->cluster[trk->entry].cts + pkt->duration;
6920 else
6921 17836 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
6922 trk->cluster[trk->entry].cts +
6923 pkt->duration);
6924
6925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 if (par->codec_id == AV_CODEC_ID_VC1) {
6926 mov_parse_vc1_frame(pkt, trk);
6927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
6928 mov_parse_truehd_frame(pkt, trk);
6929
2/2
✓ Branch 0 taken 13459 times.
✓ Branch 1 taken 4640 times.
18099 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
6930
4/4
✓ Branch 0 taken 6356 times.
✓ Branch 1 taken 7103 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6347 times.
13459 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
6931
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
6932 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
6933
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
6934 trk->flags |= MOV_TRACK_STPS;
6935 } else {
6936 13451 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
6937 }
6938
1/2
✓ Branch 0 taken 13459 times.
✗ Branch 1 not taken.
13459 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
6939 13459 trk->has_keyframes++;
6940 }
6941
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18092 times.
18099 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
6942 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
6943 7 trk->has_disposable++;
6944 }
6945
6946 18099 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
6947
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18099 if (prft && prft_size == sizeof(AVProducerReferenceTime))
6948 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
6949 else
6950 18099 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
6951
6952 18099 trk->entry++;
6953 18099 trk->sample_count += samples_in_chunk;
6954 18099 mov->mdat_size += size;
6955
6956
3/4
✓ Branch 0 taken 18017 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
18099 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
6957 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
6958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
6959 : NULL, size);
6960
6961 18100 end:
6962 18100 err:
6963
6964
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 if (pkt->data != reformatted_data)
6965 18100 av_free(reformatted_data);
6966 18100 return ret;
6967 }
6968
6969 18063 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
6970 {
6971 18063 MOVMuxContext *mov = s->priv_data;
6972 18063 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
6973 18063 AVCodecParameters *par = trk->par;
6974 18063 int64_t frag_duration = 0;
6975 18063 int size = pkt->size;
6976
6977 18063 int ret = check_pkt(s, trk, pkt);
6978
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18063 times.
18063 if (ret < 0)
6979 return ret;
6980
6981
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18058 times.
18063 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
6982
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
6983 10 mov->tracks[i].frag_discont = 1;
6984 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
6985 }
6986
6987
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 17253 times.
18063 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
6988
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 799 times.
810 if (trk->dts_shift == AV_NOPTS_VALUE)
6989 11 trk->dts_shift = pkt->pts - pkt->dts;
6990 810 pkt->dts += trk->dts_shift;
6991 }
6992
6993
1/2
✓ Branch 0 taken 18063 times.
✗ Branch 1 not taken.
18063 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
6994
2/2
✓ Branch 0 taken 12521 times.
✓ Branch 1 taken 5542 times.
18063 trk->par->codec_id == AV_CODEC_ID_AAC ||
6995
2/2
✓ Branch 0 taken 12517 times.
✓ Branch 1 taken 4 times.
12521 trk->par->codec_id == AV_CODEC_ID_AV1 ||
6996
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12462 times.
12517 trk->par->codec_id == AV_CODEC_ID_FLAC) {
6997 size_t side_size;
6998 5601 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
6999
6/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5595 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5601 if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
7000 6 void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7002 return AVERROR(ENOMEM);
7003 6 av_free(par->extradata);
7004 6 par->extradata = newextra;
7005 6 memcpy(par->extradata, side, side_size);
7006 6 par->extradata_size = side_size;
7007
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (!pkt->size) // Flush packet
7008 5 mov->need_rewrite_extradata = 1;
7009 }
7010 }
7011
7012
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18054 times.
18063 if (!pkt->size) {
7013
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) {
7014 4 trk->start_dts = pkt->dts;
7015
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7016 4 trk->start_cts = pkt->pts - pkt->dts;
7017 else
7018 trk->start_cts = 0;
7019 }
7020
7021 9 return 0; /* Discard 0 sized packets */
7022 }
7023
7024
4/4
✓ Branch 0 taken 17755 times.
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 17731 times.
✓ Branch 3 taken 24 times.
18054 if (trk->entry && pkt->stream_index < mov->nb_streams)
7025 17731 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7026 17731 s->streams[pkt->stream_index]->time_base,
7027 17731 AV_TIME_BASE_Q);
7028
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 17881 times.
18054 if ((mov->max_fragment_duration &&
7029
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 frag_duration >= mov->max_fragment_duration) ||
7030
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18051 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18051 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
7031
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 14378 times.
18051 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7032
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 2548 times.
3673 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7033
4/4
✓ Branch 0 taken 1101 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 1076 times.
✓ Branch 3 taken 25 times.
1125 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18026 times.
18026 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7035
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (frag_duration >= mov->min_fragment_duration) {
7036
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (trk->entry) {
7037 // Set the duration of this track to line up with the next
7038 // sample in this track. This avoids relying on AVPacket
7039 // duration, but only helps for this particular track, not
7040 // for the other ones that are flushed at the same time.
7041 //
7042 // If we have trk->entry == 0, no fragment will be written
7043 // for this track, and we can't adjust the track end here.
7044 28 trk->track_duration = pkt->dts - trk->start_dts;
7045
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (pkt->pts != AV_NOPTS_VALUE)
7046 28 trk->end_pts = pkt->pts;
7047 else
7048 trk->end_pts = pkt->dts;
7049 28 trk->end_reliable = 1;
7050 }
7051 28 mov_auto_flush_fragment(s, 0);
7052 }
7053 }
7054
7055 18054 return ff_mov_write_packet(s, pkt);
7056 }
7057
7058 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7059 int stream_index,
7060 int64_t dts) {
7061 3 MOVMuxContext *mov = s->priv_data;
7062 3 AVPacket *end = mov->pkt;
7063 3 uint8_t data[2] = {0};
7064 int ret;
7065
7066 3 end->size = sizeof(data);
7067 3 end->data = data;
7068 3 end->pts = dts;
7069 3 end->dts = dts;
7070 3 end->duration = 0;
7071 3 end->stream_index = stream_index;
7072
7073 3 ret = mov_write_single_packet(s, end);
7074 3 av_packet_unref(end);
7075
7076 3 return ret;
7077 }
7078
7079 #if CONFIG_IAMFENC
7080 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7081 {
7082 uint8_t *data;
7083 int ret;
7084
7085
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7086 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7088 return ret;
7089 }
7090
7091 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7092 275 s->streams[pkt->stream_index]->id, pkt);
7093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7094 return ret;
7095
7096
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7097 220 return AVERROR(EAGAIN);
7098
7099 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7100 55 trk->iamf_buf = NULL;
7101
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7103 // Either all or none of the packets for a single
7104 // IA Sample may be empty.
7105 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7106 "stream #%d\n", pkt->stream_index);
7107 ret = AVERROR_INVALIDDATA;
7108 }
7109 5 av_free(data);
7110 5 return ret;
7111 }
7112
7113 50 av_buffer_unref(&pkt->buf);
7114 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7116 av_free(data);
7117 return AVERROR(ENOMEM);
7118 }
7119 50 pkt->data = data;
7120 50 pkt->size = ret;
7121 50 pkt->stream_index = trk->first_iamf_idx;
7122
7123 50 return avio_open_dyn_buf(&trk->iamf_buf);
7124 }
7125 #endif
7126
7127 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7128 {
7129 2 int64_t pos = avio_tell(pb);
7130 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7131 2 const char *value = "";
7132
7133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7134
7135 2 avio_write_marker(pb,
7136 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7137 AVIO_DATA_MARKER_BOUNDARY_POINT);
7138
7139 2 avio_wb32(pb, 0); /* size */
7140 2 ffio_wfourcc(pb, "emsg");
7141 2 avio_w8(pb, 1); /* version */
7142 2 avio_wb24(pb, 0);
7143 2 avio_wb32(pb, st->time_base.den); /* timescale */
7144 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7145 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7146 2 avio_wb32(pb, 0); /* id */
7147 /* null terminated UTF8 strings */
7148 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7149 2 avio_write(pb, value, strlen(value) + 1);
7150 2 avio_write(pb, pkt->data, pkt->size);
7151
7152 2 return update_size(pb, pos);
7153 }
7154
7155 18391 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7156 {
7157 18391 MOVMuxContext *mov = s->priv_data;
7158 MOVTrack *trk;
7159
7160
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 18356 times.
18391 if (!pkt) {
7161 35 mov_flush_fragment(s, 1);
7162 35 return 1;
7163 }
7164
7165
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18354 times.
18356 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7166 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7167 2 return 0;
7168 }
7169
7170 18354 trk = s->streams[pkt->stream_index]->priv_data;
7171
7172 #if CONFIG_IAMFENC
7173
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 18079 times.
18354 if (trk->iamf) {
7174 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7175
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7176
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7177 220 return 0;
7178 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7179 "for stream #%d\n", trk->st->index);
7180 return ret;
7181 }
7182 }
7183 #endif
7184
7185
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18132 times.
18134 if (is_cover_image(trk->st)) {
7186 int ret;
7187
7188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7189 if (trk->st->nb_frames == 1)
7190 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7191 " ignoring.\n", pkt->stream_index);
7192 return 0;
7193 }
7194
7195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7196 return ret;
7197
7198 2 return 0;
7199 } else {
7200 int i;
7201
7202
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18123 times.
18132 if (!pkt->size)
7203 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7204
7205 /*
7206 * Subtitles require special handling.
7207 *
7208 * 1) For full complaince, every track must have a sample at
7209 * dts == 0, which is rarely true for subtitles. So, as soon
7210 * as we see any packet with dts > 0, write an empty subtitle
7211 * at dts == 0 for any subtitle track with no samples in it.
7212 *
7213 * 2) For each subtitle track, check if the current packet's
7214 * dts is past the duration of the last subtitle sample. If
7215 * so, we now need to write an end sample for that subtitle.
7216 *
7217 * This must be done conditionally to allow for subtitles that
7218 * immediately replace each other, in which case an end sample
7219 * is not needed, and is, in fact, actively harmful.
7220 *
7221 * 3) See mov_write_trailer for how the final end sample is
7222 * handled.
7223 */
7224
2/2
✓ Branch 0 taken 32861 times.
✓ Branch 1 taken 18123 times.
50984 for (i = 0; i < mov->nb_tracks; i++) {
7225 32861 MOVTrack *trk = &mov->tracks[i];
7226 int ret;
7227
7228
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 32858 times.
32861 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7229
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7230
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)) {
7231 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7233 2 trk->last_sample_is_subtitle_end = 1;
7234 }
7235 }
7236
7237
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 18049 times.
18123 if (trk->squash_fragment_samples_to_one) {
7238 /*
7239 * If the track has to have its samples squashed into one sample,
7240 * we just take it into the track's queue.
7241 * This will then be utilized as the samples get written in either
7242 * mov_flush_fragment or when the mux is finalized in
7243 * mov_write_trailer.
7244 */
7245 74 int ret = AVERROR_BUG;
7246
7247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
7248 av_log(s, AV_LOG_ERROR,
7249 "Packets without a valid presentation timestamp are "
7250 "not supported with packet squashing!\n");
7251 return AVERROR(EINVAL);
7252 }
7253
7254 /* The following will reset pkt and is only allowed to be used
7255 * because we return immediately. afterwards. */
7256
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7257 pkt, NULL, 0)) < 0) {
7258 return ret;
7259 }
7260
7261 74 return 0;
7262 }
7263
7264
7265
4/4
✓ Branch 0 taken 7825 times.
✓ Branch 1 taken 10224 times.
✓ Branch 2 taken 3702 times.
✓ Branch 3 taken 4123 times.
18049 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7266 3702 AVPacket *opkt = pkt;
7267 int reshuffle_ret, ret;
7268
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3677 times.
3702 if (trk->is_unaligned_qt_rgb) {
7269
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;
7270 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7271 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7273 return reshuffle_ret;
7274 } else
7275 3677 reshuffle_ret = 0;
7276
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3464 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3702 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7277 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7279 goto fail;
7280
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7281 5 trk->pal_done++;
7282
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2872 times.
3697 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7283
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7285 ret = av_packet_make_writable(pkt);
7286 if (ret < 0)
7287 goto fail;
7288 for (i = 0; i < pkt->size; i++)
7289 pkt->data[i] = ~pkt->data[i];
7290 }
7291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3702 times.
3702 if (reshuffle_ret) {
7292 ret = mov_write_single_packet(s, pkt);
7293 fail:
7294 if (reshuffle_ret)
7295 av_packet_free(&pkt);
7296 return ret;
7297 }
7298 }
7299
7300 18049 return mov_write_single_packet(s, pkt);
7301 }
7302 }
7303
7304 // QuickTime chapters involve an additional text track with the chapter names
7305 // as samples, and a tref pointing from the other tracks to the chapter one.
7306 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7307 {
7308 static const uint8_t stub_header[] = {
7309 // TextSampleEntry
7310 0x00, 0x00, 0x00, 0x01, // displayFlags
7311 0x00, 0x00, // horizontal + vertical justification
7312 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7313 // BoxRecord
7314 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7315 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7316 // StyleRecord
7317 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7318 0x00, 0x01, // fontID
7319 0x00, 0x00, // fontStyleFlags + fontSize
7320 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7321 // FontTableBox
7322 0x00, 0x00, 0x00, 0x0D, // box size
7323 'f', 't', 'a', 'b', // box atom name
7324 0x00, 0x01, // entry count
7325 // FontRecord
7326 0x00, 0x01, // font ID
7327 0x00, // font name length
7328 };
7329 1 MOVMuxContext *mov = s->priv_data;
7330 1 MOVTrack *track = &mov->tracks[tracknum];
7331 1 AVPacket *pkt = mov->pkt;
7332 int i, len;
7333 int ret;
7334
7335 1 track->mode = mov->mode;
7336 1 track->tag = MKTAG('t','e','x','t');
7337 1 track->timescale = mov->movie_timescale;
7338 1 track->par = avcodec_parameters_alloc();
7339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7340 return AVERROR(ENOMEM);
7341 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7342 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7344 return ret;
7345 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7346
7347 1 pkt->stream_index = tracknum;
7348 1 pkt->flags = AV_PKT_FLAG_KEY;
7349
7350
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7351 4 AVChapter *c = s->chapters[i];
7352 AVDictionaryEntry *t;
7353
7354 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7355 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7356 4 pkt->duration = end - pkt->dts;
7357
7358
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7359 static const char encd[12] = {
7360 0x00, 0x00, 0x00, 0x0C,
7361 'e', 'n', 'c', 'd',
7362 0x00, 0x00, 0x01, 0x00 };
7363 4 len = strlen(t->value);
7364 4 pkt->size = len + 2 + 12;
7365 4 pkt->data = av_malloc(pkt->size);
7366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7367 av_packet_unref(pkt);
7368 return AVERROR(ENOMEM);
7369 }
7370 4 AV_WB16(pkt->data, len);
7371 4 memcpy(pkt->data + 2, t->value, len);
7372 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7373 4 ff_mov_write_packet(s, pkt);
7374 4 av_freep(&pkt->data);
7375 }
7376 }
7377
7378 1 av_packet_unref(mov->pkt);
7379
7380 1 return 0;
7381 }
7382
7383
7384 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7385 {
7386 int ret;
7387
7388 /* compute the frame number */
7389 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7390 13 return ret;
7391 }
7392
7393 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7394 {
7395 6 MOVMuxContext *mov = s->priv_data;
7396 6 MOVTrack *track = &mov->tracks[index];
7397 6 AVStream *src_st = mov->tracks[src_index].st;
7398 uint8_t data[4];
7399 6 AVPacket *pkt = mov->pkt;
7400 6 AVRational rate = src_st->avg_frame_rate;
7401 int ret;
7402
7403 /* tmcd track based on video stream */
7404 6 track->mode = mov->mode;
7405 6 track->tag = MKTAG('t','m','c','d');
7406 6 track->src_track = src_index;
7407 6 track->timescale = mov->tracks[src_index].timescale;
7408
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7409 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7410
7411 /* set st to src_st for metadata access*/
7412 6 track->st = src_st;
7413
7414 /* encode context: tmcd data stream */
7415 6 track->par = avcodec_parameters_alloc();
7416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7417 return AVERROR(ENOMEM);
7418 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7419 6 track->par->codec_tag = track->tag;
7420 6 track->st->avg_frame_rate = rate;
7421
7422 /* the tmcd track just contains one packet with the frame number */
7423 6 pkt->data = data;
7424 6 pkt->stream_index = index;
7425 6 pkt->flags = AV_PKT_FLAG_KEY;
7426 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7427 6 pkt->size = 4;
7428 6 AV_WB32(pkt->data, tc.start);
7429 6 ret = ff_mov_write_packet(s, pkt);
7430 6 av_packet_unref(pkt);
7431 6 return ret;
7432 }
7433
7434 /*
7435 * st->disposition controls the "enabled" flag in the tkhd tag.
7436 * QuickTime will not play a track if it is not enabled. So make sure
7437 * that one track of each type (audio, video, subtitle) is enabled.
7438 *
7439 * Subtitles are special. For audio and video, setting "enabled" also
7440 * makes the track "default" (i.e. it is rendered when played). For
7441 * subtitles, an "enabled" subtitle is not rendered by default, but
7442 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7443 * empty!
7444 */
7445 209 static void enable_tracks(AVFormatContext *s)
7446 {
7447 209 MOVMuxContext *mov = s->priv_data;
7448 int i;
7449 int enabled[AVMEDIA_TYPE_NB];
7450 int first[AVMEDIA_TYPE_NB];
7451
7452
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7453 1045 enabled[i] = 0;
7454 1045 first[i] = -1;
7455 }
7456
7457
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (i = 0; i < mov->nb_streams; i++) {
7458 267 AVStream *st = mov->tracks[i].st;
7459
7460
1/2
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
267 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7461
3/4
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 265 times.
534 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7462 267 is_cover_image(st))
7463 2 continue;
7464
7465
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 14 times.
265 if (first[st->codecpar->codec_type] < 0)
7466 251 first[st->codecpar->codec_type] = i;
7467
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 236 times.
265 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7468 29 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7469 29 enabled[st->codecpar->codec_type]++;
7470 }
7471 }
7472
7473
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7474
2/2
✓ Branch 0 taken 627 times.
✓ Branch 1 taken 418 times.
1045 switch (i) {
7475 627 case AVMEDIA_TYPE_VIDEO:
7476 case AVMEDIA_TYPE_AUDIO:
7477 case AVMEDIA_TYPE_SUBTITLE:
7478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 627 times.
627 if (enabled[i] > 1)
7479 mov->per_stream_grouping = 1;
7480
4/4
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 224 times.
✓ Branch 3 taken 378 times.
627 if (!enabled[i] && first[i] >= 0)
7481 224 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7482 627 break;
7483 }
7484 }
7485 209 }
7486
7487 209 static void mov_free(AVFormatContext *s)
7488 {
7489 209 MOVMuxContext *mov = s->priv_data;
7490
7491
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int i = 0; i < s->nb_streams; i++)
7492 288 s->streams[i]->priv_data = NULL;
7493
7494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7495 return;
7496
7497
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track) {
7498 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7499 }
7500
7501
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (int i = 0; i < mov->nb_tracks; i++) {
7502 276 MOVTrack *const track = &mov->tracks[i];
7503
7504
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 274 times.
276 if (track->tag == MKTAG('r','t','p',' '))
7505 2 ff_mov_close_hinting(track);
7506
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
274 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7507 6 av_freep(&track->par);
7508 276 av_freep(&track->cluster);
7509 276 av_freep(&track->cluster_written);
7510 276 av_freep(&track->frag_info);
7511 276 av_packet_free(&track->cover_image);
7512
7513
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->eac3_priv) {
7514 5 struct eac3_info *info = track->eac3_priv;
7515 5 av_packet_free(&info->pkt);
7516 5 av_freep(&track->eac3_priv);
7517 }
7518
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 133 times.
276 if (track->vos_len)
7519 143 av_freep(&track->vos_data);
7520
7521 276 ff_mov_cenc_free(&track->cenc);
7522 276 ffio_free_dyn_buf(&track->mdat_buf);
7523
7524 #if CONFIG_IAMFENC
7525 276 ffio_free_dyn_buf(&track->iamf_buf);
7526
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->iamf)
7527 5 ff_iamf_uninit_context(track->iamf);
7528 276 av_freep(&track->iamf);
7529 #endif
7530
7531 276 avpriv_packet_list_free(&track->squashed_packet_queue);
7532 }
7533
7534 209 av_freep(&mov->tracks);
7535 209 ffio_free_dyn_buf(&mov->mdat_buf);
7536 }
7537
7538 static uint32_t rgb_to_yuv(uint32_t rgb)
7539 {
7540 uint8_t r, g, b;
7541 int y, cb, cr;
7542
7543 r = (rgb >> 16) & 0xFF;
7544 g = (rgb >> 8) & 0xFF;
7545 b = (rgb ) & 0xFF;
7546
7547 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7548 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7549 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7550
7551 return (y << 16) | (cr << 8) | cb;
7552 }
7553
7554 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7555 AVStream *st)
7556 {
7557 int i, width = 720, height = 480;
7558 int have_palette = 0, have_size = 0;
7559 uint32_t palette[16];
7560 char *cur = st->codecpar->extradata;
7561
7562 while (cur && *cur) {
7563 if (strncmp("palette:", cur, 8) == 0) {
7564 int i, count;
7565 count = sscanf(cur + 8,
7566 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7567 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7568 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7569 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7570 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7571 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7572 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7573 &palette[12], &palette[13], &palette[14], &palette[15]);
7574
7575 for (i = 0; i < count; i++) {
7576 palette[i] = rgb_to_yuv(palette[i]);
7577 }
7578 have_palette = 1;
7579 } else if (!strncmp("size:", cur, 5)) {
7580 sscanf(cur + 5, "%dx%d", &width, &height);
7581 have_size = 1;
7582 }
7583 if (have_palette && have_size)
7584 break;
7585 cur += strcspn(cur, "\n\r");
7586 cur += strspn(cur, "\n\r");
7587 }
7588 if (have_palette) {
7589 track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7590 if (!track->vos_data)
7591 return AVERROR(ENOMEM);
7592 for (i = 0; i < 16; i++) {
7593 AV_WB32(track->vos_data + i * 4, palette[i]);
7594 }
7595 memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7596 track->vos_len = 16 * 4;
7597 }
7598 st->codecpar->width = width;
7599 st->codecpar->height = track->height = height;
7600
7601 return 0;
7602 }
7603
7604 #if CONFIG_IAMFENC
7605 209 static int mov_init_iamf_track(AVFormatContext *s)
7606 {
7607 209 MOVMuxContext *mov = s->priv_data;
7608 MOVTrack *track;
7609 IAMFContext *iamf;
7610 209 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7611 209 int nb_audio_elements = 0, nb_mix_presentations = 0;
7612 int ret;
7613
7614
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (int i = 0; i < s->nb_stream_groups; i++) {
7615 10 const AVStreamGroup *stg = s->stream_groups[i];
7616
7617
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7618 5 nb_audio_elements++;
7619
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7620 5 nb_mix_presentations++;
7621 }
7622
7623
3/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
209 if (!nb_audio_elements && !nb_mix_presentations)
7624 204 return 0;
7625
7626
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) {
7627 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7628 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7629 return AVERROR(EINVAL);
7630 }
7631
7632 5 iamf = av_mallocz(sizeof(*iamf));
7633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7634 return AVERROR(ENOMEM);
7635
7636
7637
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7638 10 const AVStreamGroup *stg = s->stream_groups[i];
7639
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7640 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7641
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7642 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7643 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7644 }
7645
7646 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7647 5 break;
7648 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7649 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7650 5 break;
7651 default:
7652 av_assert0(0);
7653 }
7654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7655 return ret;
7656 }
7657
7658 5 track = &mov->tracks[first_iamf_idx];
7659 5 track->iamf = iamf;
7660 5 track->first_iamf_idx = first_iamf_idx;
7661 5 track->last_iamf_idx = last_iamf_idx;
7662 5 track->tag = MKTAG('i','a','m','f');
7663
7664
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7665 10 AVStreamGroup *stg = s->stream_groups[i];
7666
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7667 5 continue;
7668
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7669 25 stg->streams[j]->priv_data = track;
7670 }
7671
7672 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7674 return ret;
7675
7676 5 return 0;
7677 }
7678 #endif
7679
7680 209 static int mov_init(AVFormatContext *s)
7681 {
7682 209 MOVMuxContext *mov = s->priv_data;
7683 209 int has_iamf = 0;
7684 int i, ret;
7685
7686 209 mov->fc = s;
7687 209 mov->pkt = ffformatcontext(s)->pkt;
7688
7689 /* Default mode == MP4 */
7690 209 mov->mode = MODE_MP4;
7691
7692 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7695
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 63 times.
209 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7696
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7697
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7698
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 57 times.
61 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7701 #undef IS_MODE
7702
7703
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
209 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7704 17 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7705
7706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF)
7707 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7708
7709 /* Set the FRAGMENT flag if any of the fragmentation methods are
7710 * enabled. */
7711
3/4
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 208 times.
✗ Branch 3 not taken.
209 if (mov->max_fragment_duration || mov->max_fragment_size ||
7712
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 179 times.
208 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7713 FF_MOV_FLAG_FRAG_KEYFRAME |
7714 FF_MOV_FLAG_FRAG_CUSTOM |
7715 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7716 30 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7717
7718 /* Set other implicit flags immediately */
7719
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7720 1 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7721
7722
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM)
7723 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7724 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7725
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 198 times.
209 if (mov->flags & FF_MOV_FLAG_DASH)
7726 11 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7727 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7728
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_CMAF)
7729 1 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7730 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7731
7732
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 1 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
7733 29 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7734 29 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7735 }
7736
7737
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
209 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
7738 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7739 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7740 }
7741
7742
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7743 3 mov->reserved_moov_size = -1;
7744 }
7745
7746
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 7 times.
209 if (mov->use_editlist < 0) {
7747 202 mov->use_editlist = 1;
7748
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 175 times.
202 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7749
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
27 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7750 // If we can avoid needing an edit list by shifting the
7751 // tracks, prefer that over (trying to) write edit lists
7752 // in fragmented output.
7753
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7755 11 mov->use_editlist = 0;
7756 }
7757 }
7758
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7759
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
30 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
7760 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7761
7762
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1 times.
209 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
7763
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7764 10 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7765
7766 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7767 * if the latter is set that's enough and omit_tfhd_offset doesn't
7768 * add anything extra on top of that. */
7769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7770 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7771 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7772
7773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->frag_interleave &&
7774 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
7775 av_log(s, AV_LOG_ERROR,
7776 "Sample interleaving in fragments is mutually exclusive with "
7777 "omit_tfhd_offset and separate_moof\n");
7778 return AVERROR(EINVAL);
7779 }
7780
7781 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7782 * is enabled, we don't support non-seekable output at all. */
7783
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 181 times.
209 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7784
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
7785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7786 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7787 return AVERROR(EINVAL);
7788 }
7789
7790 /* AVIF output must have at most two video streams (one for YUV and one for
7791 * alpha). */
7792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF) {
7793 if (s->nb_streams > 2) {
7794 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7795 return AVERROR(EINVAL);
7796 }
7797 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7798 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7799 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7800 return AVERROR(EINVAL);
7801 }
7802 if (s->nb_streams > 1) {
7803 const AVPixFmtDescriptor *pixdesc =
7804 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7805 if (pixdesc->nb_components != 1) {
7806 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7807 return AVERROR(EINVAL);
7808 }
7809 }
7810 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7811 }
7812
7813 #if CONFIG_IAMFENC
7814
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (i = 0; i < s->nb_stream_groups; i++) {
7815 10 AVStreamGroup *stg = s->stream_groups[i];
7816
7817
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7818 5 continue;
7819
7820
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7821 25 AVStream *st = stg->streams[j];
7822
7823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
7824 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7825 "IAMF Audio Element\n", j);
7826 return AVERROR(EINVAL);
7827 }
7828 25 st->priv_data = st;
7829 }
7830 5 has_iamf = 1;
7831
7832
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
7833 5 mov->nb_tracks++;
7834 }
7835 #endif
7836
7837
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7838 288 AVStream *st = s->streams[i];
7839
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 263 times.
288 if (st->priv_data)
7840 25 continue;
7841 // Don't produce a track in the output file for timed ID3 streams.
7842
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 262 times.
263 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7843 // Leave priv_data set to NULL for these AVStreams that don't
7844 // have a corresponding track.
7845 1 continue;
7846 }
7847 262 st->priv_data = st;
7848 262 mov->nb_tracks++;
7849 }
7850
7851 209 mov->nb_streams = mov->nb_tracks;
7852
7853
4/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 203 times.
209 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
7854 1 mov->chapter_track = mov->nb_tracks++;
7855
7856
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7857
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
7858
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
7859 2 mov->nb_tracks++;
7860 }
7861
7862
1/2
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
209 if (mov->write_btrt < 0) {
7863 209 mov->write_btrt = mov->mode == MODE_MP4;
7864 }
7865
7866
6/6
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 57 times.
209 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
7867
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
7868 206 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
7869 NULL, 0);
7870
7871 /* +1 tmcd track for each video stream with a timecode */
7872
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 206 times.
489 for (i = 0; i < s->nb_streams; i++) {
7873 283 AVStream *st = s->streams[i];
7874 283 AVDictionaryEntry *t = global_tcr;
7875
4/4
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 171 times.
✓ Branch 3 taken 7 times.
283 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
7876
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 171 times.
171 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
7877 AVTimecode tc;
7878 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
7879
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
7880 7 mov->nb_meta_tmcd++;
7881 }
7882 }
7883
7884 /* check if there is already a tmcd track to remux */
7885
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 199 times.
206 if (mov->nb_meta_tmcd) {
7886
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
7887 13 AVStream *st = s->streams[i];
7888
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
7889 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
7890 "so timecode metadata are now ignored\n");
7891 3 mov->nb_meta_tmcd = 0;
7892 }
7893 }
7894 }
7895
7896 206 mov->nb_tracks += mov->nb_meta_tmcd;
7897 }
7898
7899 // Reserve an extra stream for chapters for the case where chapters
7900 // are written in the trailer
7901 209 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
7902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7903 return AVERROR(ENOMEM);
7904
7905
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
209 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
7906 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
7907 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
7908
7909 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
7910 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
7911 mov->encryption_key_len, AES_CTR_KEY_SIZE);
7912 return AVERROR(EINVAL);
7913 }
7914
7915 if (mov->encryption_kid_len != CENC_KID_SIZE) {
7916 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
7917 mov->encryption_kid_len, CENC_KID_SIZE);
7918 return AVERROR(EINVAL);
7919 }
7920 } else {
7921 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
7922 mov->encryption_scheme_str);
7923 return AVERROR(EINVAL);
7924 }
7925 }
7926
7927 #if CONFIG_IAMFENC
7928 209 ret = mov_init_iamf_track(s);
7929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (ret < 0)
7930 return ret;
7931 #endif
7932
7933
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int j = 0, i = 0; j < s->nb_streams; j++) {
7934 288 AVStream *st = s->streams[j];
7935
7936
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 262 times.
288 if (st != st->priv_data) {
7937
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
7938 5 i += has_iamf--;
7939 26 continue;
7940 }
7941 262 st->priv_data = &mov->tracks[i++];
7942 }
7943
7944
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7945 288 AVStream *st= s->streams[i];
7946 288 MOVTrack *track = st->priv_data;
7947 288 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
7948
7949
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 287 times.
288 if (!track)
7950 1 continue;
7951
7952
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 20 times.
287 if (!track->st) {
7953 267 track->st = st;
7954 267 track->par = st->codecpar;
7955 }
7956
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 263 times.
287 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
7957
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 132 times.
287 if (track->language < 0)
7958 155 track->language = 32767; // Unspecified Macintosh language code
7959 287 track->mode = mov->mode;
7960
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 25 times.
287 if (!track->tag)
7961 262 track->tag = mov_find_codec_tag(s, track);
7962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (!track->tag) {
7963 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
7964 "codec not currently supported in container\n",
7965 avcodec_get_name(st->codecpar->codec_id), i);
7966 return AVERROR(EINVAL);
7967 }
7968 /* If hinting of this track is enabled by a later hint track,
7969 * this is updated. */
7970 287 track->hint_track = -1;
7971 287 track->start_dts = AV_NOPTS_VALUE;
7972 287 track->start_cts = AV_NOPTS_VALUE;
7973 287 track->end_pts = AV_NOPTS_VALUE;
7974 287 track->dts_shift = AV_NOPTS_VALUE;
7975
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 107 times.
287 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7976
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
180 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
7977
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
180 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
7978
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 180 times.
180 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
7979 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
7980 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
7981 return AVERROR(EINVAL);
7982 }
7983 track->height = track->tag >> 24 == 'n' ? 486 : 576;
7984 }
7985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 if (mov->video_track_timescale) {
7986 track->timescale = mov->video_track_timescale;
7987 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
7988 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
7989 } else {
7990 180 track->timescale = st->time_base.den;
7991
2/2
✓ Branch 0 taken 1467 times.
✓ Branch 1 taken 180 times.
1647 while(track->timescale < 10000)
7992 1467 track->timescale *= 2;
7993 }
7994
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 180 times.
180 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
7995 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
7996 return AVERROR(EINVAL);
7997 }
7998
4/4
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 128 times.
180 if (track->mode == MODE_MOV && track->timescale > 100000)
7999 2 av_log(s, AV_LOG_WARNING,
8000 "WARNING codec timebase is very high. If duration is too long,\n"
8001 "file may not be playable by quicktime. Specify a shorter timebase\n"
8002 "or choose different container.\n");
8003
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 50 times.
180 if (track->mode == MODE_MOV &&
8004
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 113 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8005
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8006 1 enum AVPixelFormat pix_fmt = track->par->format;
8007
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)
8008 pix_fmt = AV_PIX_FMT_MONOWHITE;
8009 1 track->is_unaligned_qt_rgb =
8010 pix_fmt == AV_PIX_FMT_RGB24 ||
8011 pix_fmt == AV_PIX_FMT_BGR24 ||
8012 pix_fmt == AV_PIX_FMT_PAL8 ||
8013 pix_fmt == AV_PIX_FMT_GRAY8 ||
8014
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 ||
8015 pix_fmt == AV_PIX_FMT_MONOBLACK;
8016 }
8017
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
180 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
8018 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8019 return AVERROR(EINVAL);
8020
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 179 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8021
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 track->mode != MODE_MP4 && track->mode != MODE_AVIF) {
8022 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8023 return AVERROR(EINVAL);
8024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8025 /* altref frames handling is not defined in the spec as of version v1.0,
8026 * so just forbid muxing VP8 streams altogether until a new version does */
8027 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8028 return AVERROR_PATCHWELCOME;
8029 }
8030
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 178 times.
180 if (is_cover_image(st)) {
8031 2 track->cover_image = av_packet_alloc();
8032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8033 return AVERROR(ENOMEM);
8034 }
8035
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 7 times.
107 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8036 100 track->timescale = st->codecpar->sample_rate;
8037
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 69 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 25 times.
100 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8038 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8039 6 track->audio_vbr = 1;
8040
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8041
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8042
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8043 if (!st->codecpar->block_align) {
8044 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8045 return AVERROR(EINVAL);
8046 }
8047 track->sample_size = st->codecpar->block_align;
8048
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 25 times.
94 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8049 69 track->audio_vbr = 1;
8050 }else{
8051 25 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8052 25 st->codecpar->ch_layout.nb_channels;
8053 }
8054
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8056 track->audio_vbr = 1;
8057 }
8058
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 32 times.
100 if (track->mode != MODE_MOV &&
8059
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
68 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8060 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8061 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8062 i, track->par->sample_rate);
8063 return AVERROR(EINVAL);
8064 } else {
8065 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8066 i, track->par->sample_rate);
8067 }
8068 }
8069
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
100 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8070
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
75 track->par->codec_id == AV_CODEC_ID_OPUS) {
8072
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8073 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8074 return AVERROR(EINVAL);
8075 }
8076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8077 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8078 av_log(s, AV_LOG_ERROR,
8079 "%s in MP4 support is experimental, add "
8080 "'-strict %d' if you want to use it.\n",
8081 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8082 return AVERROR_EXPERIMENTAL;
8083 }
8084 }
8085
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8086 3 track->timescale = st->time_base.den;
8087
8088
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8089 /* 14496-30 requires us to use a single sample per fragment
8090 for TTML, for which we define a per-track flag.
8091
8092 We set the flag in case we are receiving TTML paragraphs
8093 from the input, in other words in case we are not doing
8094 stream copy. */
8095 2 track->squash_fragment_samples_to_one =
8096 2 ff_is_ttml_stream_paragraph_based(track->par);
8097
8098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8099 track->squash_fragment_samples_to_one) {
8100 av_log(s, AV_LOG_ERROR,
8101 "Fragmentation is not currently supported for "
8102 "TTML in MP4/ISMV (track synchronization between "
8103 "subtitles and other media is not yet implemented)!\n");
8104 return AVERROR_PATCHWELCOME;
8105 }
8106
8107
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
8108
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8110 av_log(s, AV_LOG_ERROR,
8111 "ISMV style TTML support with the 'dfxp' tag in "
8112 "non-ISMV formats is not officially supported. Add "
8113 "'-strict unofficial' if you want to use it.\n");
8114 return AVERROR_EXPERIMENTAL;
8115 }
8116 }
8117
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8118 4 track->timescale = st->time_base.den;
8119 } else {
8120 track->timescale = mov->movie_timescale;
8121 }
8122
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 if (!track->height)
8123 287 track->height = st->codecpar->height;
8124 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8125 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8126 for video tracks, so if user-set, it isn't overwritten */
8127
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
287 if (mov->mode == MODE_ISM &&
8128
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8129
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !mov->video_track_timescale))) {
8130 5 track->timescale = 10000000;
8131 }
8132
8133 287 avpriv_set_pts_info(st, 64, 1, track->timescale);
8134
8135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8136 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8137 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8138 track->par->codec_id == AV_CODEC_ID_VVC),
8139 s->flags & AVFMT_FLAG_BITEXACT);
8140 if (ret)
8141 return ret;
8142 }
8143 }
8144
8145 209 enable_tracks(s);
8146 209 return 0;
8147 }
8148
8149 209 static int mov_write_header(AVFormatContext *s)
8150 {
8151 209 AVIOContext *pb = s->pb;
8152 209 MOVMuxContext *mov = s->priv_data;
8153 209 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8154
8155
4/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 203 times.
209 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8156 1 nb_tracks++;
8157
8158
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8159 1 hint_track = nb_tracks;
8160
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8161
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8162 2 nb_tracks++;
8163 }
8164 }
8165
8166
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd)
8167 6 tmcd_track = nb_tracks;
8168
8169
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
8170 267 MOVTrack *track = &mov->tracks[i];
8171 267 AVStream *st = track->st;
8172
8173 /* copy extradata if it exists */
8174
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 150 times.
267 if (st->codecpar->extradata_size) {
8175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8176 mov_create_dvd_sub_decoder_specific_info(track, st);
8177
15/30
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 117 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 117 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 117 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 117 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 117 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 117 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 117 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 117 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 117 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 117 times.
✗ Branch 29 not taken.
117 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8178 117 track->vos_len = st->codecpar->extradata_size;
8179 117 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!track->vos_data) {
8181 return AVERROR(ENOMEM);
8182 }
8183 117 memcpy(track->vos_data, st->codecpar->extradata, track->vos_len);
8184 117 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8185 }
8186 }
8187
8188
4/4
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 14 times.
347 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8189 80 av_channel_layout_compare(&track->par->ch_layout,
8190 80 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8191 253 continue;
8192
8193
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8194 33 AVStream *stj= mov->tracks[j].st;
8195 33 MOVTrack *trackj= &mov->tracks[j];
8196
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8197 14 continue;
8198
8199
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8200
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
18 (trackj->par->ch_layout.nb_channels != 1 ||
8201 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8202 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8203 )
8204 4 track->mono_as_fc = -1;
8205
8206
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
30 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8207 11 av_channel_layout_compare(&trackj->par->ch_layout,
8208 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8209
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
8210 )
8211 7 track->mono_as_fc++;
8212
8213
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
30 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8214 11 av_channel_layout_compare(&trackj->par->ch_layout,
8215 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8216 trackj->language != track->language ||
8217 trackj->tag != track->tag
8218 )
8219 19 continue;
8220 track->multichannel_as_mono++;
8221 }
8222 }
8223
8224
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 17 times.
209 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8225
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
192 if ((ret = mov_write_identification(pb, s)) < 0)
8226 return ret;
8227 }
8228
8229
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->reserved_moov_size){
8230 3 mov->reserved_header_pos = avio_tell(pb);
8231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8232 avio_skip(pb, mov->reserved_moov_size);
8233 }
8234
8235
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8236 /* If no fragmentation options have been set, set a default. */
8237
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8238 FF_MOV_FLAG_FRAG_CUSTOM |
8239 4 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8240
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 !mov->max_fragment_duration && !mov->max_fragment_size)
8241 4 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8242
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8243 1 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8244
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8245 1 mov->mdat_pos = avio_tell(pb);
8246 }
8247
1/2
✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
175 } else if (mov->mode != MODE_AVIF) {
8248
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 172 times.
175 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8249 3 mov->reserved_header_pos = avio_tell(pb);
8250 175 mov_write_mdat_tag(pb, mov);
8251 }
8252
8253 209 ff_parse_creation_time_metadata(s, &mov->time, 1);
8254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->time)
8255 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8256
8257
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track)
8258
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8259 return ret;
8260
8261
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8262
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8263
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8264
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8265 return ret;
8266 2 hint_track++;
8267 }
8268 }
8269 }
8270
8271
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd) {
8272 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8273 "timecode", NULL, 0);
8274 /* Initialize the tmcd tracks */
8275
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8276 8 AVStream *st = mov->tracks[i].st;
8277 8 t = global_tcr;
8278
8279
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8280 AVTimecode tc;
8281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8282 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8284 continue;
8285
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8286 continue;
8287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8288 return ret;
8289 6 tmcd_track++;
8290 }
8291 }
8292 }
8293
8294 209 avio_flush(pb);
8295
8296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_ISML)
8297 mov_write_isml_manifest(pb, mov, s);
8298
8299
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8300
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
30 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8301
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8302 return ret;
8303 13 mov->moov_written = 1;
8304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8305 mov->reserved_header_pos = avio_tell(pb);
8306 }
8307
8308 209 return 0;
8309 }
8310
8311 27 static int get_moov_size(AVFormatContext *s)
8312 {
8313 int ret;
8314 AVIOContext *moov_buf;
8315 27 MOVMuxContext *mov = s->priv_data;
8316
8317
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8318 return ret;
8319
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8320 return ret;
8321 27 return ffio_close_null_buf(moov_buf);
8322 }
8323
8324 static int get_sidx_size(AVFormatContext *s)
8325 {
8326 int ret;
8327 AVIOContext *buf;
8328 MOVMuxContext *mov = s->priv_data;
8329
8330 if ((ret = ffio_open_null_buf(&buf)) < 0)
8331 return ret;
8332 mov_write_sidx_tags(buf, mov, -1, 0);
8333 return ffio_close_null_buf(buf);
8334 }
8335
8336 /*
8337 * This function gets the moov size if moved to the top of the file: the chunk
8338 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8339 * entries) when the moov is moved to the beginning, so the size of the moov
8340 * would change. It also updates the chunk offset tables.
8341 */
8342 3 static int compute_moov_size(AVFormatContext *s)
8343 {
8344 int i, moov_size, moov_size2;
8345 3 MOVMuxContext *mov = s->priv_data;
8346
8347 3 moov_size = get_moov_size(s);
8348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8349 return moov_size;
8350
8351
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8352 8 mov->tracks[i].data_offset += moov_size;
8353
8354 3 moov_size2 = get_moov_size(s);
8355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8356 return moov_size2;
8357
8358 /* if the size changed, we just switched from stco to co64 and need to
8359 * update the offsets */
8360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8361 for (i = 0; i < mov->nb_tracks; i++)
8362 mov->tracks[i].data_offset += moov_size2 - moov_size;
8363
8364 3 return moov_size2;
8365 }
8366
8367 static int compute_sidx_size(AVFormatContext *s)
8368 {
8369 int i, sidx_size;
8370 MOVMuxContext *mov = s->priv_data;
8371
8372 sidx_size = get_sidx_size(s);
8373 if (sidx_size < 0)
8374 return sidx_size;
8375
8376 for (i = 0; i < mov->nb_tracks; i++)
8377 mov->tracks[i].data_offset += sidx_size;
8378
8379 return sidx_size;
8380 }
8381
8382 3 static int shift_data(AVFormatContext *s)
8383 {
8384 int moov_size;
8385 3 MOVMuxContext *mov = s->priv_data;
8386
8387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8388 moov_size = compute_sidx_size(s);
8389 else
8390 3 moov_size = compute_moov_size(s);
8391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8392 return moov_size;
8393
8394 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8395 }
8396
8397 209 static int mov_write_trailer(AVFormatContext *s)
8398 {
8399 209 MOVMuxContext *mov = s->priv_data;
8400 209 AVIOContext *pb = s->pb;
8401 209 int res = 0;
8402 int i;
8403 int64_t moov_pos;
8404
8405
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 if (mov->need_rewrite_extradata) {
8406
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
12 for (i = 0; i < mov->nb_streams; i++) {
8407 7 MOVTrack *track = &mov->tracks[i];
8408 7 AVCodecParameters *par = track->par;
8409
8410 7 track->vos_len = par->extradata_size;
8411 7 av_freep(&track->vos_data);
8412 7 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!track->vos_data)
8414 return AVERROR(ENOMEM);
8415 7 memcpy(track->vos_data, par->extradata, track->vos_len);
8416 7 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8417 }
8418 5 mov->need_rewrite_extradata = 0;
8419 }
8420
8421 /*
8422 * Before actually writing the trailer, make sure that there are no
8423 * dangling subtitles, that need a terminating sample.
8424 */
8425
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (i = 0; i < mov->nb_tracks; i++) {
8426 276 MOVTrack *trk = &mov->tracks[i];
8427
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 275 times.
276 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8428
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8429 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8430 1 trk->last_sample_is_subtitle_end = 1;
8431 }
8432 }
8433
8434 // Check if we have any tracks that require squashing.
8435 // In that case, we'll have to write the packet here.
8436
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 209 times.
209 if ((res = mov_write_squashed_packets(s)) < 0)
8437 return res;
8438
8439 // If there were no chapters when the header was written, but there
8440 // are chapters now, write them in the trailer. This only works
8441 // when we are not doing fragments.
8442
4/4
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 34 times.
209 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
8443
3/4
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 173 times.
174 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
8444 mov->chapter_track = mov->nb_tracks++;
8445 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8446 return res;
8447 }
8448 }
8449
8450
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8451
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8452
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8453 1 mov_flush_fragment(s, 1);
8454 1 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8455
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
8456 2 MOVTrack *track = &mov->tracks[i];
8457 2 track->data_offset = 0;
8458 2 av_free(track->cluster);
8459 2 track->cluster = track->cluster_written;
8460 2 track->entry = track->entry_written;
8461 2 track->cluster_written = NULL;
8462 2 track->entry_written = 0;
8463 2 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8464 }
8465 // Clear the empty_moov flag, as we do want the moov to include
8466 // all the samples at this point.
8467 1 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8468 }
8469
8470 176 moov_pos = avio_tell(pb);
8471
8472 /* Write size of mdat tag */
8473
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 if (mov->mdat_size + 8 <= UINT32_MAX) {
8474 176 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8475 176 avio_wb32(pb, mov->mdat_size + 8);
8476
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8477 1 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8478 } else {
8479 /* overwrite 'wide' placeholder atom */
8480 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8481 /* special value: real atom size will be 64 bit value after
8482 * tag field */
8483 avio_wb32(pb, 1);
8484 ffio_wfourcc(pb, "mdat");
8485 avio_wb64(pb, mov->mdat_size + 16);
8486 }
8487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176 times.
176 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
8488
8489
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 173 times.
176 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8490 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8491 3 res = shift_data(s);
8492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8493 return res;
8494 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8495
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8496 return res;
8497
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 } else if (mov->reserved_moov_size > 0) {
8498 int64_t size;
8499 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8500 return res;
8501 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8502 if (size < 8){
8503 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8504 return AVERROR(EINVAL);
8505 }
8506 avio_wb32(pb, size);
8507 ffio_wfourcc(pb, "free");
8508 ffio_fill(pb, 0, size - 8);
8509 avio_seek(pb, moov_pos, SEEK_SET);
8510 } else {
8511
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8512 return res;
8513 }
8514 176 res = 0;
8515 } else {
8516 33 mov_auto_flush_fragment(s, 1);
8517
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++)
8518 63 mov->tracks[i].data_offset = 0;
8519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8520 int64_t end;
8521 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8522 res = shift_data(s);
8523 if (res < 0)
8524 return res;
8525 end = avio_tell(pb);
8526 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8527 mov_write_sidx_tags(pb, mov, -1, 0);
8528 avio_seek(pb, end, SEEK_SET);
8529 }
8530
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8531 33 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8532 33 res = mov_write_mfra_tag(pb, mov);
8533
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (res < 0)
8534 return res;
8535 }
8536 }
8537
8538 209 return res;
8539 }
8540
8541 232 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8542 const AVPacket *pkt)
8543 {
8544 232 int ret = 1;
8545
8546
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 223 times.
232 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8547
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
8548 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8550 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8551 }
8552
8553 232 return ret;
8554 }
8555
8556 #if CONFIG_AVIF_MUXER
8557 static int avif_write_trailer(AVFormatContext *s)
8558 {
8559 AVIOContext *pb = s->pb;
8560 MOVMuxContext *mov = s->priv_data;
8561 int64_t pos_backup, extent_offsets[2];
8562 uint8_t *buf;
8563 int buf_size, moov_size;
8564
8565 if (mov->moov_written) return 0;
8566
8567 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8568 if (mov->is_animated_avif && mov->nb_streams > 1) {
8569 // For animated avif with alpha channel, we need to write a tref tag
8570 // with type "auxl".
8571 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8572 mov->tracks[1].tref_id = 1;
8573 }
8574 mov_write_identification(pb, s);
8575 mov_write_meta_tag(pb, mov, s);
8576
8577 moov_size = get_moov_size(s);
8578 for (int i = 0; i < mov->nb_tracks; i++)
8579 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8580
8581 if (mov->is_animated_avif) {
8582 int ret;
8583 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8584 return ret;
8585 }
8586
8587 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8588 avio_wb32(pb, buf_size + 8);
8589 ffio_wfourcc(pb, "mdat");
8590
8591 // The offset for the YUV planes is the starting position of mdat.
8592 extent_offsets[0] = avio_tell(pb);
8593 // The offset for alpha plane is YUV offset + YUV size.
8594 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8595
8596 avio_write(pb, buf, buf_size);
8597
8598 // write extent offsets.
8599 pos_backup = avio_tell(pb);
8600 for (int i = 0; i < mov->nb_streams; i++) {
8601 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8602 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8603 return AVERROR_INVALIDDATA;
8604 }
8605 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8606 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8607 }
8608 avio_seek(pb, pos_backup, SEEK_SET);
8609
8610 return 0;
8611 }
8612 #endif
8613
8614 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8615 static const AVCodecTag codec_3gp_tags[] = {
8616 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8617 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8618 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8619 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8620 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8621 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8622 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8623 { AV_CODEC_ID_NONE, 0 },
8624 };
8625 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8626 #endif
8627
8628 static const AVCodecTag codec_mp4_tags[] = {
8629 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8630 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8631 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8632 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8633 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8634 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8635 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8636 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8637 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8638 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8639 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8640 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8641 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8642 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8643 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8644 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8645 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8646 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8647 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8648 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8649 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8650 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8651 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8652 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8653 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8654 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8655 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8656 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8657 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8658 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8659 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8660 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8661 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8662 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8663 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8664 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8665 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8666 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8667 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8668 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8669
8670 /* ISO/IEC 23003-5 integer formats */
8671 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8672 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8673 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8674 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8675 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8676 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8677 /* ISO/IEC 23003-5 floating-point formats */
8678 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8679 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8680 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8681 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8682
8683 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
8684
8685 { AV_CODEC_ID_NONE, 0 },
8686 };
8687 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8688 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8689 #endif
8690
8691 static const AVCodecTag codec_ism_tags[] = {
8692 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8693 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8694 { AV_CODEC_ID_NONE , 0 },
8695 };
8696
8697 static const AVCodecTag codec_ipod_tags[] = {
8698 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8699 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8700 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8701 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8702 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8703 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8704 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8705 { AV_CODEC_ID_NONE, 0 },
8706 };
8707
8708 static const AVCodecTag codec_f4v_tags[] = {
8709 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8710 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8711 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8712 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8713 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8714 { AV_CODEC_ID_NONE, 0 },
8715 };
8716
8717 #if CONFIG_AVIF_MUXER
8718
8719 static const AVOption avif_options[] = {
8720 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8721 { "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 },
8722 { NULL },
8723 };
8724 static const AVCodecTag codec_avif_tags[] = {
8725 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8726 { AV_CODEC_ID_NONE, 0 },
8727 };
8728 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8729
8730 static const AVClass mov_avif_muxer_class = {
8731 .class_name = "avif muxer",
8732 .item_name = av_default_item_name,
8733 .option = avif_options,
8734 .version = LIBAVUTIL_VERSION_INT,
8735 };
8736 #endif
8737
8738 #if CONFIG_MOV_MUXER
8739 const FFOutputFormat ff_mov_muxer = {
8740 .p.name = "mov",
8741 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8742 .p.extensions = "mov",
8743 .priv_data_size = sizeof(MOVMuxContext),
8744 .p.audio_codec = AV_CODEC_ID_AAC,
8745 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8746 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8747 .init = mov_init,
8748 .write_header = mov_write_header,
8749 .write_packet = mov_write_packet,
8750 .write_trailer = mov_write_trailer,
8751 .deinit = mov_free,
8752 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS
8753 #if FF_API_ALLOW_FLUSH
8754 | AVFMT_ALLOW_FLUSH
8755 #endif
8756 ,
8757 .p.codec_tag = (const AVCodecTag* const []){
8758 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8759 },
8760 .check_bitstream = mov_check_bitstream,
8761 .p.priv_class = &mov_isobmff_muxer_class,
8762 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8763 };
8764 #endif
8765 #if CONFIG_TGP_MUXER
8766 const FFOutputFormat ff_tgp_muxer = {
8767 .p.name = "3gp",
8768 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8769 .p.extensions = "3gp",
8770 .priv_data_size = sizeof(MOVMuxContext),
8771 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8772 .p.video_codec = AV_CODEC_ID_H263,
8773 .init = mov_init,
8774 .write_header = mov_write_header,
8775 .write_packet = mov_write_packet,
8776 .write_trailer = mov_write_trailer,
8777 .deinit = mov_free,
8778 #if FF_API_ALLOW_FLUSH
8779 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8780 #else
8781 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8782 #endif
8783 .p.codec_tag = codec_3gp_tags_list,
8784 .check_bitstream = mov_check_bitstream,
8785 .p.priv_class = &mov_isobmff_muxer_class,
8786 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8787 };
8788 #endif
8789 #if CONFIG_MP4_MUXER
8790 const FFOutputFormat ff_mp4_muxer = {
8791 .p.name = "mp4",
8792 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8793 .p.mime_type = "video/mp4",
8794 .p.extensions = "mp4",
8795 .priv_data_size = sizeof(MOVMuxContext),
8796 .p.audio_codec = AV_CODEC_ID_AAC,
8797 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8798 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8799 .init = mov_init,
8800 .write_header = mov_write_header,
8801 .write_packet = mov_write_packet,
8802 .write_trailer = mov_write_trailer,
8803 .deinit = mov_free,
8804 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS
8805 #if FF_API_ALLOW_FLUSH
8806 | AVFMT_ALLOW_FLUSH
8807 #endif
8808 ,
8809 .p.codec_tag = mp4_codec_tags_list,
8810 .check_bitstream = mov_check_bitstream,
8811 .p.priv_class = &mov_isobmff_muxer_class,
8812 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8813 };
8814 #endif
8815 #if CONFIG_PSP_MUXER
8816 const FFOutputFormat ff_psp_muxer = {
8817 .p.name = "psp",
8818 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8819 .p.extensions = "mp4,psp",
8820 .priv_data_size = sizeof(MOVMuxContext),
8821 .p.audio_codec = AV_CODEC_ID_AAC,
8822 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8823 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8824 .init = mov_init,
8825 .write_header = mov_write_header,
8826 .write_packet = mov_write_packet,
8827 .write_trailer = mov_write_trailer,
8828 .deinit = mov_free,
8829 #if FF_API_ALLOW_FLUSH
8830 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8831 #else
8832 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8833 #endif
8834 .p.codec_tag = mp4_codec_tags_list,
8835 .check_bitstream = mov_check_bitstream,
8836 .p.priv_class = &mov_isobmff_muxer_class,
8837 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8838 };
8839 #endif
8840 #if CONFIG_TG2_MUXER
8841 const FFOutputFormat ff_tg2_muxer = {
8842 .p.name = "3g2",
8843 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8844 .p.extensions = "3g2",
8845 .priv_data_size = sizeof(MOVMuxContext),
8846 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8847 .p.video_codec = AV_CODEC_ID_H263,
8848 .init = mov_init,
8849 .write_header = mov_write_header,
8850 .write_packet = mov_write_packet,
8851 .write_trailer = mov_write_trailer,
8852 .deinit = mov_free,
8853 #if FF_API_ALLOW_FLUSH
8854 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8855 #else
8856 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8857 #endif
8858 .p.codec_tag = codec_3gp_tags_list,
8859 .check_bitstream = mov_check_bitstream,
8860 .p.priv_class = &mov_isobmff_muxer_class,
8861 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8862 };
8863 #endif
8864 #if CONFIG_IPOD_MUXER
8865 const FFOutputFormat ff_ipod_muxer = {
8866 .p.name = "ipod",
8867 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8868 .p.mime_type = "video/mp4",
8869 .p.extensions = "m4v,m4a,m4b",
8870 .priv_data_size = sizeof(MOVMuxContext),
8871 .p.audio_codec = AV_CODEC_ID_AAC,
8872 .p.video_codec = AV_CODEC_ID_H264,
8873 .init = mov_init,
8874 .write_header = mov_write_header,
8875 .write_packet = mov_write_packet,
8876 .write_trailer = mov_write_trailer,
8877 .deinit = mov_free,
8878 #if FF_API_ALLOW_FLUSH
8879 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8880 #else
8881 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8882 #endif
8883 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
8884 .check_bitstream = mov_check_bitstream,
8885 .p.priv_class = &mov_isobmff_muxer_class,
8886 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8887 };
8888 #endif
8889 #if CONFIG_ISMV_MUXER
8890 const FFOutputFormat ff_ismv_muxer = {
8891 .p.name = "ismv",
8892 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
8893 .p.mime_type = "video/mp4",
8894 .p.extensions = "ismv,isma",
8895 .priv_data_size = sizeof(MOVMuxContext),
8896 .p.audio_codec = AV_CODEC_ID_AAC,
8897 .p.video_codec = AV_CODEC_ID_H264,
8898 .init = mov_init,
8899 .write_header = mov_write_header,
8900 .write_packet = mov_write_packet,
8901 .write_trailer = mov_write_trailer,
8902 .deinit = mov_free,
8903 #if FF_API_ALLOW_FLUSH
8904 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8905 #else
8906 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8907 #endif
8908 .p.codec_tag = (const AVCodecTag* const []){
8909 codec_mp4_tags, codec_ism_tags, 0 },
8910 .check_bitstream = mov_check_bitstream,
8911 .p.priv_class = &mov_isobmff_muxer_class,
8912 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8913 };
8914 #endif
8915 #if CONFIG_F4V_MUXER
8916 const FFOutputFormat ff_f4v_muxer = {
8917 .p.name = "f4v",
8918 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
8919 .p.mime_type = "application/f4v",
8920 .p.extensions = "f4v",
8921 .priv_data_size = sizeof(MOVMuxContext),
8922 .p.audio_codec = AV_CODEC_ID_AAC,
8923 .p.video_codec = AV_CODEC_ID_H264,
8924 .init = mov_init,
8925 .write_header = mov_write_header,
8926 .write_packet = mov_write_packet,
8927 .write_trailer = mov_write_trailer,
8928 .deinit = mov_free,
8929 #if FF_API_ALLOW_FLUSH
8930 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8931 #else
8932 .p.flags = AVFMT_GLOBALHEADER,
8933 #endif
8934 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
8935 .check_bitstream = mov_check_bitstream,
8936 .p.priv_class = &mov_isobmff_muxer_class,
8937 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8938 };
8939 #endif
8940 #if CONFIG_AVIF_MUXER
8941 const FFOutputFormat ff_avif_muxer = {
8942 .p.name = "avif",
8943 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
8944 .p.mime_type = "image/avif",
8945 .p.extensions = "avif",
8946 .priv_data_size = sizeof(MOVMuxContext),
8947 .p.video_codec = AV_CODEC_ID_AV1,
8948 .init = mov_init,
8949 .write_header = mov_write_header,
8950 .write_packet = mov_write_packet,
8951 .write_trailer = avif_write_trailer,
8952 .deinit = mov_free,
8953 #if FF_API_ALLOW_FLUSH
8954 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8955 #else
8956 .p.flags = AVFMT_GLOBALHEADER,
8957 #endif
8958 .p.codec_tag = codec_avif_tags_list,
8959 .p.priv_class = &mov_avif_muxer_class,
8960 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8961 };
8962 #endif
8963